]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/parsers/macho_relocatable_file.cpp
ld64-302.3.tar.gz
[apple/ld64.git] / src / ld / parsers / macho_relocatable_file.cpp
index 2fa41b9f269b9a123b8ea6669d26381bbc4a3144..8a3e7922220a604fa0839a7b1b4a3ec7a7314470 100644 (file)
@@ -84,9 +84,10 @@ public:
                                                                                                _swiftVersion(0),
                                                                                                _cpuSubType(0),
                                                                                                _minOSVersion(0),
-                                                                                               _platform(0),
+                                                                                               _platform(Options::kPlatformUnknown),
                                                                                                _canScatterAtoms(false),
-                                                                                               _srcKind(kSourceUnknown) {}
+                                                                                               _objcHasCategoryClassPropertiesField(false),
+                                                                                               _srcKind(kSourceUnknown) { }
        virtual                                                                 ~File();
 
        // overrides of ld::File
@@ -94,21 +95,24 @@ public:
        virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
                                                                                                                                                                        { return false; }
        virtual uint32_t                                                                        minOSVersion() const            { return _minOSVersion; }
-       virtual uint32_t                                                                        platformLoadCommand() const     { return _platform; }
+       virtual uint32_t                                                                        platform() const                        { return _platform; }
 
        // overrides of ld::relocatable::File 
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
+       virtual bool                                                                            objcHasCategoryClassPropertiesField() const 
+                                                                                                                                                                       { return _objcHasCategoryClassPropertiesField; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
        virtual DebugInfoKind                                                           debugInfo() const                               { return _debugInfoKind; }
        virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                           { return &_stabs; }
        virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
        virtual const char*                                                                     translationUnitSource() const;
        virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
+       virtual const ToolVersionList&                                          toolVersions() const                    { return _toolVersions; }
        virtual uint8_t                                                                         swiftVersion() const                    { return _swiftVersion; }
        virtual ld::Bitcode*                                                            getBitcode() const                              { return _bitcode.get(); }
        virtual SourceKind                                                                      sourceKind() const                              { return _srcKind; }
        
-       const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
+       virtual const uint8_t*                                                          fileContent() const                             { return _fileContent; }
 private:
        friend class Atom<A>;
        friend class Section<A>;
@@ -138,11 +142,13 @@ private:
        uint8_t                                                                 _swiftVersion;
        uint32_t                                                                _cpuSubType;
        uint32_t                                                                _minOSVersion;
-       uint32_t                                                                _platform;
+       Options::Platform                                               _platform;
        bool                                                                    _canScatterAtoms;
+       bool                                                                    _objcHasCategoryClassPropertiesField;
        std::vector<std::vector<const char*> >  _linkerOptions;
        std::unique_ptr<ld::Bitcode>                    _bitcode;
        SourceKind                                                              _srcKind;
+       ToolVersionList                                                 _toolVersions;
 };
 
 
@@ -385,6 +391,10 @@ public:
                                                TLVDefsSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s) :
                                                        SymboledSection<A>(parser, f, s) { }
 
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+
 private:
 
 };
@@ -530,6 +540,7 @@ protected:
        typedef typename A::P::uint_t   pint_t;
        typedef typename A::P                   P;
 
+       virtual void                                    makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&);
        virtual ld::Atom::ContentType   contentType()                                                   { return ld::Atom::typeTLVPointer; }
        virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "tlv_lazy_ptr"; }
@@ -930,6 +941,7 @@ void Atom<arm64>::verifyAlignment(const macho_section<P>& sect) const
 }
 #endif
 
+
 template <typename A>
 void Atom<A>::verifyAlignment(const macho_section<P>&) const
 {
@@ -1089,7 +1101,8 @@ public:
                                                                                                                                                                                TargetDesc& target);
        uint32_t                                                                                tentativeDefinitionCount() { return _tentativeDefinitionCount; }
        uint32_t                                                                                absoluteSymbolCount() { return _absoluteSymbolCount; }
-       
+
+       uint32_t                                                                                fileLength() const { return _fileLength; }
        bool                                                                                    hasStubsSection() { return (_stubsSectionNum != 0); }
        unsigned int                                                                    stubsSectionNum() { return _stubsSectionNum; }
        void                                                                                    addDtraceExtraInfos(const SourceLocation& src, const char* provider);
@@ -1101,6 +1114,8 @@ public:
        bool                                                                                    verboseOptimizationHints() { return _verboseOptimizationHints; }
        bool                                                                                    neverConvertDwarf() { return _neverConvertDwarf; }
        bool                                                                                    armUsesZeroCostExceptions() { return _armUsesZeroCostExceptions; }
+       uint8_t                                                                                 maxDefaultCommonAlignment() { return _maxDefaultCommonAlignment; }
+
 
        macho_data_in_code_entry<P>*                                    dataInCodeStart() { return _dataInCodeStart; }
        macho_data_in_code_entry<P>*                                    dataInCodeEnd()   { return _dataInCodeEnd; }
@@ -1256,6 +1271,7 @@ private:
        bool                                                                            _ignoreMismatchPlatform;
        bool                                                                            _treateBitcodeAsData;
        bool                                                                            _usingBitcode;
+       uint8_t                                                                         _maxDefaultCommonAlignment;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
@@ -1402,6 +1418,7 @@ const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
 }
 #endif
 
+
 template <typename A>
 bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
 {
@@ -1474,11 +1491,11 @@ bool Parser<A>::getNonLocalSymbols(const uint8_t* fileContent, std::vector<const
                        uint32_t symbolCount = symtab->nsyms();
                        const macho_nlist<P>* symbols = (const macho_nlist<P>*)(fileContent + symtab->symoff());
                        const char* strings = (char*)fileContent + symtab->stroff();
-                       for (uint32_t i = 0; i < symbolCount; ++i) {
+                       for (uint32_t j = 0; j < symbolCount; ++j) {
                                // ignore stabs and count only ext symbols
-                               if ( (symbols[i].n_type() & N_STAB) == 0 &&
-                                        (symbols[i].n_type() & N_EXT) != 0 ) {
-                                       const char* symName = &strings[symbols[i].n_strx()];
+                               if ( (symbols[j].n_type() & N_STAB) == 0 &&
+                                        (symbols[j].n_type() & N_EXT) != 0 ) {
+                                       const char* symName = &strings[symbols[j].n_strx()];
                                        syms.push_back(symName);
                                }
                        }
@@ -1700,11 +1717,14 @@ typename A::P::uint_t Parser<A>::realAddr(typename A::P::uint_t addr)
 #define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
        _type*  _name = NULL;   \
        uint32_t _name##_count = 1; \
-       if ( _actual_count > _maxCount ) \
+       uint32_t _name##_stack_count = _actual_count; \
+       if ( _actual_count > _maxCount ) { \
                _name = (_type*)malloc(sizeof(_type) * _actual_count); \
+               _name##_stack_count = 1; \
+       } \
        else \
                _name##_count = _actual_count; \
-       _type  _name##_buffer[_name##_count]; \
+       _type _name##_buffer[_name##_stack_count]; \
        if ( _name == NULL ) \
                _name = _name##_buffer;
 
@@ -1726,6 +1746,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                printf("%s\n", _path);
                
        _armUsesZeroCostExceptions = opts.armUsesZeroCostExceptions;
+       _maxDefaultCommonAlignment = opts.maxDefaultCommonAlignment;
 
        // parse start of mach-o file
        if ( ! parseLoadCommands(opts.platform, opts.minOSVersion, opts.simulator, opts.ignoreMismatchPlatform) )
@@ -1754,7 +1775,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
 
        // create lists of address that already have compact unwind and thus don't need the dwarf parsed
        unsigned cuLsdaCount = 0;
-       pint_t cuStarts[countOfCUs];
+       STACK_ALLOC_IF_SMALL(pint_t, cuStarts, countOfCUs, 1024);
        for (uint32_t i=0; i < countOfCUs; ++i) {
                if ( CUSection<A>::encodingMeansUseDwarf(cuInfoArray[i].compactUnwindInfo) )
                        cuStarts[i] = -1;
@@ -2073,17 +2094,33 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
        #endif
                                if ( ignoreMismatchPlatform )
                                        break;
-                               _file->_platform = cmd->cmd();
                                lcPlatform = Options::platformForLoadCommand(cmd->cmd());
+                               _file->_platform = lcPlatform;
                                _file->_minOSVersion = ((macho_version_min_command<P>*)cmd)->version();
                                break;
-                       default:
-                               if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
-                                       if ( segment != NULL )
-                                               throw "more than one LC_SEGMENT found in object file";
-                                       segment = (macho_segment_command<P>*)cmd;
+                       case LC_BUILD_VERSION:
+                               {
+                                       const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
+                                       if ( ignoreMismatchPlatform )
+                                               break;
+                                       lcPlatform = (Options::Platform)buildVersCmd->platform();
+                                       _file->_platform = lcPlatform;
+                                       _file->_minOSVersion = buildVersCmd->minos();
+                                       const macho_build_tool_version<P>* entry = (macho_build_tool_version<P>*)((uint8_t*)cmd + sizeof(macho_build_version_command<P>));
+                                       for (uint32_t t=0; t < buildVersCmd->ntools(); ++t) {
+                                               _file->_toolVersions.push_back(std::make_pair(entry->tool(), entry->version()));
+                                               ++entry;
+                                       }
                                }
                                break;
+                       case macho_segment_command<P>::CMD:
+                               if ( segment != NULL )
+                                       throw "more than one LC_SEGMENT found in object file";
+                               segment = (macho_segment_command<P>*)cmd;
+                               break;
+                       default:
+                               // ignore unknown load commands
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
                if ( cmd > cmdsEnd )
@@ -2104,11 +2141,18 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
                                        if ( lcPlatform == Options::kPlatformUnknown )
                                                break;
                                        // fall through if the Platform is not Unknown
+                               case Options::kPlatform_bridgeOS:
                                case Options::kPlatformWatchOS:
-                                       // WatchOS errors on cross-linking all the time.
-                                       throwf("building for %s%s, but linking in object file built for %s,",
+                                       // Error when using bitcocde, warning otherwise.
+                                       if (_usingBitcode)
+                                               throwf("building for %s%s, but linking in object file built for %s,",
                                                   Options::platformName(platform), (simulator ? " simulator" : ""),
                                                   Options::platformName(lcPlatform));
+                                       else
+                                               warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. "
+                                                               "Note: This will be an error in the future.",
+                                                               Options::platformName(platform), (simulator ? " simulator" : ""), path(),
+                                                               Options::platformName(lcPlatform));
                                        break;
        #if SUPPORT_APPLE_TV
                                case Options::kPlatform_tvOS:
@@ -2145,7 +2189,8 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
                throw "missing LC_SEGMENT";
        _sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
        _machOSectionsCount = segment->nsects();
-       
+       if ( (sizeof(macho_segment_command<P>) + _machOSectionsCount * sizeof(macho_section<P>)) > segment->cmdsize() )
+               throw "too many sections for size of LC_SEGMENT command";
        return true;
 }
 
@@ -2170,6 +2215,14 @@ Options::Platform Parser<A>::findPlatform(const macho_header<P>* header)
                                return Options::kPlatformOSX;
                        case LC_VERSION_MIN_IPHONEOS:
                                return Options::kPlatformiOS;
+                       case LC_VERSION_MIN_WATCHOS:
+                               return Options::kPlatformWatchOS;
+       #if SUPPORT_APPLE_TV
+                       case LC_VERSION_MIN_TVOS:
+                               return Options::kPlatform_tvOS;
+       #endif
+                       case LC_BUILD_VERSION:
+                               return (Options::Platform)((macho_build_version_command<P>*)cmd)->platform();
                }
                cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
                if ( cmd > cmdsEnd )
@@ -2453,6 +2506,10 @@ void Parser<A>::makeSections()
 
        for (uint32_t i=0; i < _machOSectionsCount; ++i) {
                const macho_section<P>* sect = &_sectionsStart[i];
+               uint8_t sectionType = (sect->flags() & SECTION_TYPE);
+               if ( (sect->offset() + sect->size() > _fileLength) && (sectionType != S_ZEROFILL) && (sectionType != S_THREAD_LOCAL_ZEROFILL) )
+                       throwf("section %s/%s extends beyond end of file,", sect->segname(), sect->sectname());
+
                if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
                        if ( strcmp(sect->segname(), "__DWARF") == 0 ) {
                                // note that .o file has dwarf
@@ -2508,6 +2565,7 @@ void Parser<A>::makeSections()
                        // #define OBJC_IMAGE_SUPPORTS_GC   2
                        // #define OBJC_IMAGE_GC_ONLY       4
                        // #define OBJC_IMAGE_IS_SIMULATED  32
+                       // #define OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES  64
                        //
                        const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
@@ -2521,6 +2579,7 @@ void Parser<A>::makeSections()
                                else
                                        _file->_objConstraint = ld::File::objcConstraintRetainRelease;
                                _file->_swiftVersion = ((flags >> 8) & 0xFF);
+                _file->_objcHasCategoryClassPropertiesField = (flags & 64);
                                if ( sect->size() > 8 ) {
                                        warning("section %s/%s has unexpectedly large size %llu in %s", 
                                                        sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
@@ -3150,10 +3209,10 @@ uint32_t TentativeDefinitionSection<A>::appendAtoms(class Parser<A>& parser, uin
                                alignP2 = 63 - (uint8_t)__builtin_clzll(size);
                                if ( size != (1ULL << alignP2) )
                                        ++alignP2;
+                               // <rdar://problem/24871389> limit default alignment of large commons
+                               if ( alignP2 > parser.maxDefaultCommonAlignment() )
+                                       alignP2 = parser.maxDefaultCommonAlignment();
                        }
-                       // limit alignment of extremely large commons to 2^15 bytes (8-page)
-                       if ( alignP2 > 15 )
-                               alignP2 = 15;
                        Atom<A>* allocatedSpace = (Atom<A>*)p;
                        new (allocatedSpace) Atom<A>(*this, parser.nameFromSymbol(sym), (pint_t)ULLONG_MAX, size,
                                                                                ld::Atom::definitionTentative,  ld::Atom::combineByName, 
@@ -3253,10 +3312,11 @@ uint32_t Parser<A>::symbolIndexFromIndirectSectionAddress(pint_t addr, const mac
                        break;
                case S_LAZY_SYMBOL_POINTERS:
                case S_NON_LAZY_SYMBOL_POINTERS:
+               case S_THREAD_LOCAL_VARIABLE_POINTERS:
                        elementSize = sizeof(pint_t);
                        break;
                default:
-                       throw "section does not use inirect symbol table";
+                       throw "section does not use indirect symbol table";
        }       
        uint32_t indexInSection = (addr - sect->addr()) / elementSize;
        uint32_t indexIntoIndirectTable = sect->reserved1() + indexInSection;
@@ -3950,6 +4010,7 @@ bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
        const uint8_t * debug_info;
        const uint8_t * debug_abbrev;
        const uint8_t * di;
+       const uint8_t * next_cu;
        const uint8_t * da;
        const uint8_t * end;
        const uint8_t * enda;
@@ -3967,108 +4028,122 @@ bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
        if ( (_file->_dwarfDebugInfoSect == NULL) || (_file->_dwarfDebugAbbrevSect == NULL) )
                return false;
 
-       debug_info = (uint8_t*)_file->fileContent() + _file->_dwarfDebugInfoSect->offset();
-       debug_abbrev = (uint8_t*)_file->fileContent() + _file->_dwarfDebugAbbrevSect->offset();
-       di = debug_info;
-
        if (_file->_dwarfDebugInfoSect->size() < 12)
-               /* Too small to be a real debug_info section.  */
-               return false;
-       sz = A::P::E::get32(*(uint32_t*)di);
-       di += 4;
-       dwarf64 = sz == 0xffffffff;
-       if (dwarf64)
-               sz = A::P::E::get64(*(uint64_t*)di), di += 8;
-       else if (sz > 0xffffff00)
-               /* Unknown dwarf format.  */
-               return false;
-
-       /* Verify claimed size.  */
-       if (sz + (di - debug_info) > _file->_dwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
-               return false;
-
-       vers = A::P::E::get16(*(uint16_t*)di);
-       if (vers < 2 || vers > 4)
-       /* DWARF version wrong for this code.
-          Chances are we could continue anyway, but we don't know for sure.  */
+       /* Too small to be a real debug_info section.  */
                return false;
-       di += 2;
-
-       /* Find the debug_abbrev section.  */
-       abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
-       di += dwarf64 ? 8 : 4;
-
-       if (abbrev_base > _file->_dwarfDebugAbbrevSect->size())
-               return false;
-       da = debug_abbrev + abbrev_base;
-       enda = debug_abbrev + _file->_dwarfDebugAbbrevSect->size();
-
-       address_size = *di++;
-
-       /* Find the abbrev number we're looking for.  */
-       end = di + sz;
-       abbrev = read_uleb128 (&di, end);
-       if (abbrev == (uint64_t) -1)
-               return false;
-
-       /* Skip through the debug_abbrev section looking for that abbrev.  */
-       for (;;)
-       {
-               uint64_t this_abbrev = read_uleb128 (&da, enda);
-               uint64_t attr;
-
-               if (this_abbrev == abbrev)
-                       /* This is almost always taken.  */
-                       break;
-               skip_leb128 (&da, enda); /* Skip the tag.  */
-               if (da == enda)
-                       return false;
-               da++;  /* Skip the DW_CHILDREN_* value.  */
-
-               do {
-                       attr = read_uleb128 (&da, enda);
-                       skip_leb128 (&da, enda);
-               } while (attr != 0 && attr != (uint64_t) -1);
-               if (attr != 0)
-                       return false;
-       }
-
-       /* Check that the abbrev is one for a DW_TAG_compile_unit.  */
-       if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
-       return false;
-       if (da == enda)
-       return false;
-       da++;  /* Skip the DW_CHILDREN_* value.  */
-
-       /* Now, go through the DIE looking for DW_AT_name,
-        DW_AT_comp_dir, and DW_AT_stmt_list.  */
-       for (;;)
-       {
-               uint64_t attr = read_uleb128 (&da, enda);
-               uint64_t form = read_uleb128 (&da, enda);
-
-               if (attr == (uint64_t) -1)
-                       return false;
-               else if (attr == 0)
-                       return true;
-               if (form == DW_FORM_indirect)
-                       form = read_uleb128 (&di, end);
 
-               switch (attr) {
-                       case DW_AT_name:
-                               *name = getDwarfString(form, di);
-                               break;
-                       case DW_AT_comp_dir:
-                               *comp_dir = getDwarfString(form, di);
-                               break;
-                       case DW_AT_stmt_list:
-                               *stmt_list = getDwarfOffset(form, di, dwarf64);
-                               break;
-                       default:
-                               if (! skip_form (&di, end, form, address_size, dwarf64))
-                                       return false;
-               }
-       }
+    debug_info = (uint8_t*)_file->fileContent() + _file->_dwarfDebugInfoSect->offset();
+    debug_abbrev = (uint8_t*)_file->fileContent() + _file->_dwarfDebugAbbrevSect->offset();
+    next_cu = debug_info;
+
+    while ((uint64_t)(next_cu - debug_info) < _file->_dwarfDebugInfoSect->size()) {
+               di = next_cu;
+        sz = A::P::E::get32(*(uint32_t*)di);
+        di += 4;
+        dwarf64 = sz == 0xffffffff;
+        if (dwarf64)
+            sz = A::P::E::get64(*(uint64_t*)di), di += 8;
+        else if (sz > 0xffffff00)
+            /* Unknown dwarf format.  */
+            return false;
+
+        /* Verify claimed size.  */
+        if (sz + (di - debug_info) > _file->_dwarfDebugInfoSect->size() || sz <= (dwarf64 ? 23 : 11))
+            return false;
+
+        next_cu = di + sz;
+
+        vers = A::P::E::get16(*(uint16_t*)di);
+        if (vers < 2 || vers > 4)
+        /* DWARF version wrong for this code.
+           Chances are we could continue anyway, but we don't know for sure.  */
+            return false;
+        di += 2;
+
+        /* Find the debug_abbrev section.  */
+        abbrev_base = dwarf64 ? A::P::E::get64(*(uint64_t*)di) : A::P::E::get32(*(uint32_t*)di);
+        di += dwarf64 ? 8 : 4;
+
+        if (abbrev_base > _file->_dwarfDebugAbbrevSect->size())
+            return false;
+        da = debug_abbrev + abbrev_base;
+        enda = debug_abbrev + _file->_dwarfDebugAbbrevSect->size();
+
+        address_size = *di++;
+
+        /* Find the abbrev number we're looking for.  */
+        end = di + sz;
+        abbrev = read_uleb128 (&di, end);
+        if (abbrev == (uint64_t) -1)
+            return false;
+
+        /* Skip through the debug_abbrev section looking for that abbrev.  */
+        for (;;)
+        {
+            uint64_t this_abbrev = read_uleb128 (&da, enda);
+            uint64_t attr;
+
+            if (this_abbrev == abbrev)
+                /* This is almost always taken.  */
+                break;
+            skip_leb128 (&da, enda); /* Skip the tag.  */
+            if (da == enda)
+                return false;
+            da++;  /* Skip the DW_CHILDREN_* value.  */
+
+            do {
+                attr = read_uleb128 (&da, enda);
+                skip_leb128 (&da, enda);
+            } while (attr != 0 && attr != (uint64_t) -1);
+            if (attr != 0)
+                return false;
+        }
+
+        /* Check that the abbrev is one for a DW_TAG_compile_unit.  */
+        if (read_uleb128 (&da, enda) != DW_TAG_compile_unit)
+        return false;
+        if (da == enda)
+        return false;
+        da++;  /* Skip the DW_CHILDREN_* value.  */
+
+        /* Now, go through the DIE looking for DW_AT_name,
+         DW_AT_comp_dir, and DW_AT_stmt_list.  */
+        bool skip_to_next_cu = false;
+        while (!skip_to_next_cu) {
+
+            uint64_t attr = read_uleb128 (&da, enda);
+            uint64_t form = read_uleb128 (&da, enda);
+
+            if (attr == (uint64_t) -1)
+                return false;
+            else if (attr == 0)
+                return true;
+            if (form == DW_FORM_indirect)
+                form = read_uleb128 (&di, end);
+
+            switch (attr) {
+                case DW_AT_name:
+                    *name = getDwarfString(form, di);
+                    /* Swift object files may contain two CUs: One
+                       describes the Swift code, one is created by the
+                       clang importer. Skip over the CU created by the
+                       clang importer as it may be empty. */
+                    if (std::string(*name) == "<swift-imported-modules>")
+                        skip_to_next_cu = true;
+                    break;
+                case DW_AT_comp_dir:
+                    *comp_dir = getDwarfString(form, di);
+                    break;
+                case DW_AT_stmt_list:
+                    *stmt_list = getDwarfOffset(form, di, dwarf64);
+                    break;
+                default:
+                    if (! skip_form (&di, end, form, address_size, dwarf64))
+                        return false;
+            }
+        }
+    }
+    return false;
 }
 
 
@@ -4355,6 +4430,7 @@ bool CFISection<arm64>::needsRelocating()
        return true;
 }
 
+
 template <typename A>
 bool CFISection<A>::needsRelocating()
 {
@@ -4366,8 +4442,9 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
                                                                        libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[], 
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
+       const uint32_t sectionSize = this->_machOSection->size();
        // copy __eh_frame data to buffer
-       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), sectionSize);
 
        // and apply relocations
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
@@ -4393,6 +4470,8 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
                                fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
                                break;
                }
+               if ( reloc->r_address() > sectionSize )
+                       throwf("malformed __eh_frame relocation, offset (0x%08X) is beyond end of section,", reloc->r_address());
                uint64_t*       p64;
                uint32_t*       p32;
                switch ( reloc->r_length() ) {
@@ -4476,7 +4555,8 @@ void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer,
                                                                        uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // copy __eh_frame data to buffer
-       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+       const uint32_t sectionSize = this->_machOSection->size();
+       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), sectionSize);
 
        // and apply relocations
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
@@ -4508,6 +4588,8 @@ void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer,
                                fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
                                break;
                }
+               if ( reloc->r_address() > sectionSize )
+                       throwf("malformed __eh_frame relocation, offset (0x%08X) is beyond end of section,", reloc->r_address());
                switch ( reloc->r_length() ) {
                        case 3:
                                E::set64(*p64, value + addend64);
@@ -4573,7 +4655,6 @@ template <> bool CFISection<x86>::bigEndian() { return false; }
 template <> bool CFISection<arm>::bigEndian() { return false; }
 template <> bool CFISection<arm64>::bigEndian() { return false; }
 
-
 template <>
 void CFISection<x86_64>::addCiePersonalityFixups(class Parser<x86_64>& parser, const CFI_Atom_Info* cieInfo)
 {
@@ -4645,6 +4726,7 @@ void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, con
 }
 #endif
 
+
 template <>
 void CFISection<arm>::addCiePersonalityFixups(class Parser<arm>& parser, const CFI_Atom_Info* cieInfo)
 {
@@ -4970,6 +5052,7 @@ const char* CUSection<arm64>::personalityName(class Parser<arm64>& parser, const
 }
 #endif
 
+
 #if SUPPORT_ARCH_arm_any
 template <>
 const char* CUSection<arm>::personalityName(class Parser<arm>& parser, const macho_relocation_info<arm::P>* reloc)
@@ -5034,6 +5117,7 @@ bool CUSection<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
 }
 #endif
 
+
 template <typename A>
 int CUSection<A>::infoSorter(const void* l, const void* r)
 {
@@ -5070,9 +5154,14 @@ void CUSection<A>::parse(class Parser<A>& parser, uint32_t cnt, Info array[])
        }
        
        // scan relocs, extern relocs are needed for personality references (possibly for function/lsda refs??)
+       const uint32_t sectionSize = this->_machOSection->size();
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
        const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
        for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               if ( reloc->r_address() & R_SCATTERED )
+                       continue;
+               if ( reloc->r_address() > sectionSize )
+                       throwf("malformed __compact_unwind relocation, offset (0x%08X) is beyond end of section,", reloc->r_address());
                if ( reloc->r_extern() ) {
                        // only expect external relocs on some colummns
                        if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::personalityFieldOffset() ) {
@@ -5270,6 +5359,7 @@ ld::Atom::SymbolTableInclusion ImplicitSizeSection<arm64>::symbolTableInclusion(
        return ld::Atom::symbolTableInWithRandomAutoStripLabel;
 }
 
+
 template <typename A>
 ld::Atom::SymbolTableInclusion ImplicitSizeSection<A>::symbolTableInclusion()
 {
@@ -5710,6 +5800,47 @@ ld::Atom::Combine TLVPointerSection<A>::combine(Parser<A>& parser, pint_t addr)
        return ld::Atom::combineByNameAndReferences;
 }
 
+template <>
+void TLVPointerSection<arm>::makeFixups(class Parser<arm>& parser, const struct Parser<arm>::CFI_CU_InfoArrays&)
+{
+       // add references for each thread local pointer atom based on indirect symbol table
+       const macho_section<P>* sect = this->machoSection();
+       const pint_t endAddr = sect->addr() + sect->size();
+       for (pint_t addr = sect->addr(); addr < endAddr; addr += sizeof(pint_t)) {
+               typename Parser<arm>::SourceLocation    src;
+               typename Parser<arm>::TargetDesc                target;
+               src.atom = this->findAtomByAddress(addr);
+               src.offsetInAtom = 0;
+               uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(addr, sect);
+               target.atom = NULL;
+               target.name = NULL;
+               target.weakImport = false;
+               target.addend = 0;
+               if ( symIndex == INDIRECT_SYMBOL_LOCAL ) {
+                       throwf("unexpected INDIRECT_SYMBOL_LOCAL in section %s", this->sectionName());
+               }
+               else {
+                       const macho_nlist<P>& sym = parser.symbolFromIndex(symIndex);
+                       // use direct reference for local symbols
+                       if ( ((sym.n_type() & N_TYPE) == N_SECT) && ((sym.n_type() & N_EXT) == 0) ) {
+                               throwf("unexpected pointer to local symbol in section %s", this->sectionName());
+                       }
+                       else {
+                               target.name = parser.nameFromSymbol(sym);
+                               target.weakImport = parser.weakImportFromSymbol(sym);
+                               assert(src.atom->combine() == ld::Atom::combineByNameAndReferences);
+                       }
+               }
+               parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+       }
+}
+
+template <typename A>
+void TLVPointerSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
+{
+       assert(0 && "should not have thread-local-pointer sections in .o files");
+}
+
 
 template <typename A>
 const char* TLVPointerSection<A>::targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind, bool* isStatic)
@@ -6139,6 +6270,10 @@ template <>
 bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_relocation_info<P>* reloc)
 {
        const macho_section<P>* sect = this->machoSection();
+       if ( sect == NULL ) {
+               warning("malformed mach-o, relocations not supported on section %s", this->sectionName());
+               return false;
+       }
        uint64_t srcAddr = sect->addr() + reloc->r_address();
        Parser<x86_64>::SourceLocation  src;
        Parser<x86_64>::TargetDesc              target;
@@ -6309,10 +6444,14 @@ bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_re
                        }
                        else {
                                parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
-                               useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
+                               useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit) || ((toTarget.atom->combine() == ld::Atom::combineByNameAndContent) || (toTarget.atom->combine() == ld::Atom::combineByNameAndReferences));
+                       }
+                       if ( useDirectBinding ) {
+                               if ( (toTarget.atom->combine() == ld::Atom::combineByNameAndContent) || (toTarget.atom->combine() == ld::Atom::combineByNameAndReferences) )
+                                       parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, toTarget.atom);
+                               else
+                                       parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
                        }
-                       if ( useDirectBinding )
-                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
                        else
                                parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
                        parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
@@ -7359,6 +7498,7 @@ bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relo
 }
 #endif
 
+
 template <typename A>
 bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
 {
@@ -7510,6 +7650,7 @@ void Section<arm64>::addLOH(class Parser<arm64>& parser, int kind, int count, co
 }
 #endif
 
+
 template <typename A>
 void Section<A>::addLOH(class Parser<A>& parser, int kind, int count, const uint64_t addrs[]) {
 
@@ -7519,6 +7660,8 @@ template <typename A>
 void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        const macho_section<P>* sect = this->machoSection();
+       if ( sect->reloff() + (sect->nreloc() * sizeof(macho_relocation_info<P>)) > parser.fileLength() )
+               throwf("relocations for section %s/%s extends beyond end of file,", sect->segname(), Section<A>::makeSectionName(sect) );
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + sect->reloff());
        const uint32_t relocCount = sect->nreloc();
        for (uint32_t r = 0; r < relocCount; ++r) {
@@ -7558,7 +7701,8 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
                Atom<A>* end = &_endAtoms[-1];
                for(Atom<A>* p = _beginAtoms; p < end; ++p) {
                        Atom<A>* nextAtom = &p[1];
-                       if ( _altEntries.count(nextAtom) != 0 ) {
+                       // <rdar://problem/22960070> support alt_entry aliases (alias process already added followOn, don't repeat)
+                       if ( (_altEntries.count(nextAtom) != 0) && (p->_objAddress != nextAtom->_objAddress) ) {
                                typename Parser<A>::SourceLocation src(p, 0);
                                parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
                                typename Parser<A>::SourceLocation src2(nextAtom, 0);
@@ -7779,7 +7923,7 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
        if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
                const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
                *result = CPU_TYPE_ARM64;
-               *subResult = CPU_SUBTYPE_ARM64_ALL;
+               *subResult = header->cpusubtype();
                *platform = Parser<arm64>::findPlatform(header);
                return true;
        }