X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..f80fe69f3f29962e8aa43a99f8ed9201548f3d78:/src/ld/parsers/macho_relocatable_file.cpp diff --git a/src/ld/parsers/macho_relocatable_file.cpp b/src/ld/parsers/macho_relocatable_file.cpp index 25c1965..c22af18 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -21,7 +21,7 @@ * * @APPLE_LICENSE_HEADER_END@ */ - + #include #include @@ -34,9 +34,9 @@ #include "MachOFileAbstraction.hpp" -#include -#include -#include +#include "libunwind/DwarfInstructions.hpp" +#include "libunwind/AddressSpace.hpp" +#include "libunwind/Registers.hpp" #include #include @@ -64,22 +64,23 @@ template class Parser; template class Atom; template class Section; template class CFISection; +template class CUSection; template class File : public ld::relocatable::File { public: - File(const char* p, time_t mTime, const uint8_t* content, uint32_t ord) : + File(const char* p, time_t mTime, const uint8_t* content, ld::File::Ordinal ord) : ld::relocatable::File(p,mTime,ord), _fileContent(content), _sectionsArray(NULL), _atomsArray(NULL), _sectionsArrayCount(0), _atomsArrayCount(0), _debugInfoKind(ld::relocatable::File::kDebugInfoNone), - _dwarfTranslationUnitDir(NULL), _dwarfTranslationUnitFile(NULL), + _dwarfTranslationUnitPath(NULL), _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), _objConstraint(ld::File::objcConstraintNone), _cpuSubType(0), - _ojcReplacmentClass(false), _canScatterAtoms(false) {} + _canScatterAtoms(false) {} virtual ~File(); // overrides of ld::File @@ -88,13 +89,13 @@ public: { return false; } // overrides of ld::relocatable::File - virtual bool objcReplacementClasses() const { return _ojcReplacmentClass; } virtual ObjcConstraint objCConstraint() const { return _objConstraint; } virtual uint32_t cpuSubType() const { return _cpuSubType; } virtual DebugInfoKind debugInfo() const { return _debugInfoKind; } - virtual const std::vector* stabs() const { return &_stabs; } + virtual const std::vector* stabs() const { return &_stabs; } virtual bool canScatterAtoms() const { return _canScatterAtoms; } - bool translationUnitSource(const char** dir, const char** name) const; + virtual const char* translationUnitSource() const; + virtual LinkerOptionsList* linkerOptions() const { return &_linkerOptions; } const uint8_t* fileContent() { return _fileContent; } private: @@ -115,16 +116,15 @@ private: std::vector _lineInfos; std::vector_stabs; ld::relocatable::File::DebugInfoKind _debugInfoKind; - const char* _dwarfTranslationUnitDir; - const char* _dwarfTranslationUnitFile; + const char* _dwarfTranslationUnitPath; const macho_section

* _dwarfDebugInfoSect; const macho_section

* _dwarfDebugAbbrevSect; const macho_section

* _dwarfDebugLineSect; const macho_section

* _dwarfDebugStringSect; ld::File::ObjcConstraint _objConstraint; uint32_t _cpuSubType; - bool _ojcReplacmentClass; bool _canScatterAtoms; + std::vector > _linkerOptions; }; @@ -147,15 +147,17 @@ public: virtual bool addFollowOnFixups() const { return ! _file.canScatterAtoms(); } virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) = 0; + const struct Parser::CFI_CU_InfoArrays&) = 0; virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) = 0; - virtual void makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&); + const struct Parser::CFI_CU_InfoArrays&) = 0; + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&); virtual bool addRelocFixup(class Parser& parser, const macho_relocation_info

*); virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const { return 0; } virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const { return false; } + virtual bool ignoreLabel(const char* label) const { return false; } + static const char* makeSectionName(const macho_section* s); protected: Section(File& f, const macho_section* s) @@ -166,11 +168,9 @@ protected: _beginAtoms(NULL), _endAtoms(NULL), _hasAliases(false) { } - bool addRelocFixup_powerpc(class Parser& parser,const macho_relocation_info* reloc); Atom* findContentAtomByAddress(pint_t addr, class Atom* start, class Atom* end); uint32_t x86_64PcRelOffset(uint8_t r_type); static const char* makeSegmentName(const macho_section* s); - static const char* makeSectionName(const macho_section* s); static bool readable(const macho_section* s); static bool writable(const macho_section* s); static bool exectuable(const macho_section* s); @@ -193,9 +193,9 @@ public: uint32_t cfiCount(); virtual ld::Atom::ContentType contentType() { return ld::Atom::typeCFI; } - virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFIInfoArray&); - virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFIInfoArray&); - virtual void makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&); + virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&); + virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&); + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&); virtual bool addFollowOnFixups() const { return false; } @@ -238,7 +238,7 @@ public: typedef typename A::P::uint_t pint_t; typedef libunwind::CFI_Atom_Info CFI_Atom_Info; - void cfiParse(class Parser& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t cfiCount); + void cfiParse(class Parser& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t& cfiCount, const pint_t cuStarts[], uint32_t cuCount); bool needsRelocating(); static bool bigEndian(); @@ -248,6 +248,47 @@ private: }; +template +class CUSection : public Section +{ +public: + CUSection(Parser& parser, File& f, const macho_section* s) + : Section(f, s) { } + + typedef typename A::P::uint_t pint_t; + typedef typename A::P P; + typedef typename A::P::E E; + + virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&) { return 0; } + virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&) { return 0; } + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&); + virtual bool addFollowOnFixups() const { return false; } + + struct Info { + pint_t functionStartAddress; + uint32_t functionSymbolIndex; + uint32_t rangeLength; + uint32_t compactUnwindInfo; + const char* personality; + pint_t lsdaAddress; + Atom* function; + Atom* lsda; + }; + + uint32_t count(); + void parse(class Parser& parser, uint32_t cnt, Info array[]); + static bool encodingMeansUseDwarf(compact_unwind_encoding_t enc); + + +private: + + const char* personalityName(class Parser& parser, const macho_relocation_info

* reloc); + + static int infoSorter(const void* l, const void* r); + +}; + + template class TentativeDefinitionSection : public Section { @@ -259,11 +300,11 @@ public: virtual bool addFollowOnFixups() const { return false; } virtual Atom* findAtomByAddress(typename A::P::uint_t addr) { throw "TentativeDefinitionSection::findAtomByAddress() should never be called"; } virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); + const struct Parser::CFI_CU_InfoArrays&); virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); - virtual void makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&) {} + const struct Parser::CFI_CU_InfoArrays&); + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) {} private: typedef typename A::P::uint_t pint_t; typedef typename A::P P; @@ -283,11 +324,11 @@ public: virtual bool addFollowOnFixups() const { return false; } virtual Atom* findAtomByAddress(typename A::P::uint_t addr) { throw "AbsoluteSymbolSection::findAtomByAddress() should never be called"; } virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); + const struct Parser::CFI_CU_InfoArrays&); virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); - virtual void makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&) {} + const struct Parser::CFI_CU_InfoArrays&); + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) {} virtual Atom* findAbsAtomForValue(typename A::P::uint_t); private: @@ -304,10 +345,10 @@ public: virtual ld::Atom::ContentType contentType() { return _type; } virtual bool dontDeadStrip(); virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); + const struct Parser::CFI_CU_InfoArrays&); virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&); + const struct Parser::CFI_CU_InfoArrays&); protected: typedef typename A::P::uint_t pint_t; typedef typename A::P P; @@ -334,24 +375,25 @@ class ImplicitSizeSection : public Section public: ImplicitSizeSection(Parser& parser, File& f, const macho_section* s) : Section(f, s) { } - virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFIInfoArray&); - virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFIInfoArray&); + virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&); + virtual uint32_t appendAtoms(class Parser& parser, uint8_t* buffer, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&); protected: typedef typename A::P::uint_t pint_t; typedef typename A::P P; virtual bool addFollowOnFixups() const { return false; } virtual const char* unlabeledAtomName(Parser& parser, pint_t addr) = 0; - virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableNotIn; } + virtual ld::Atom::SymbolTableInclusion symbolTableInclusion(); virtual pint_t elementSizeAtAddress(pint_t addr) = 0; virtual ld::Atom::Scope scopeAtAddress(Parser& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; } virtual bool useElementAt(Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, pint_t addr) = 0; virtual ld::Atom::Definition definition() { return ld::Atom::definitionRegular; } virtual ld::Atom::Combine combine(Parser& parser, pint_t addr) = 0; - virtual bool ignoreLabel(const char* label) { return (label[0] == 'L'); } + virtual bool ignoreLabel(const char* label) const { return (label[0] == 'L'); } }; + template class FixedSizeSection : public ImplicitSizeSection { @@ -437,14 +479,14 @@ protected: typedef typename A::P::uint_t pint_t; typedef typename A::P P; - virtual void makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&); + virtual void makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&); virtual ld::Atom::ContentType contentType() { return ld::Atom::typeNonLazyPointer; } virtual ld::Atom::Alignment alignmentForAddress(pint_t addr) { return ld::Atom::Alignment(log2(sizeof(pint_t))); } virtual const char* unlabeledAtomName(Parser&, pint_t) { return "non_lazy_ptr"; } virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); } virtual ld::Atom::Scope scopeAtAddress(Parser& parser, pint_t addr); virtual ld::Atom::Combine combine(Parser&, pint_t); - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; @@ -468,7 +510,7 @@ protected: virtual const char* unlabeledAtomName(Parser&, pint_t) { return "CFString"; } virtual pint_t elementSizeAtAddress(pint_t addr) { return 4*sizeof(pint_t); } virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineByNameAndReferences; } - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; @@ -496,7 +538,7 @@ protected: virtual ld::Atom::SymbolTableInclusion symbolTableInclusion() { return ld::Atom::symbolTableIn; } virtual pint_t elementSizeAtAddress(pint_t addr); virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineNever; } - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const { return 0; } virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, @@ -518,7 +560,7 @@ protected: virtual const char* unlabeledAtomName(Parser&, pint_t) { return "objc-class-ref"; } virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); } virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineByNameAndReferences; } - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; @@ -541,7 +583,7 @@ protected: virtual const char* unlabeledAtomName(Parser&, pint_t) { return "objc-cat-list"; } virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); } virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineNever; } - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } private: const char* targetClassName(const class Atom* atom, const ld::IndirectBindingTable& ind) const; }; @@ -560,7 +602,7 @@ protected: virtual const char* unlabeledAtomName(Parser&, pint_t) { return "pointer-to-literal-cstring"; } virtual pint_t elementSizeAtAddress(pint_t addr) { return sizeof(pint_t); } virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineByNameAndReferences; } - virtual bool ignoreLabel(const char* label) { return true; } + virtual bool ignoreLabel(const char* label) const { return true; } virtual unsigned long contentHash(const class Atom* atom, const ld::IndirectBindingTable& ind) const; virtual bool canCoalesceWith(const class Atom* atom, const ld::Atom& rhs, const ld::IndirectBindingTable& ind) const; @@ -598,6 +640,7 @@ protected: virtual Atom* findAtomByAddress(pint_t addr); virtual const char* unlabeledAtomName(Parser&, pint_t) { return "cstring"; } virtual pint_t elementSizeAtAddress(pint_t addr); + virtual bool ignoreLabel(const char* label) const; virtual bool useElementAt(Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, pint_t addr); virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineByNameAndContent; } @@ -634,8 +677,8 @@ class Atom : public ld::Atom public: // overrides of ld::Atom virtual ld::File* file() const { return §().file(); } - virtual bool translationUnitSource(const char** dir, const char** nm) const - { return sect().file().translationUnitSource(dir, nm); } + virtual const char* translationUnitSource() const + { return sect().file().translationUnitSource(); } virtual const char* name() const { return _name; } virtual uint64_t size() const { return _size; } virtual uint64_t objectAddress() const { return _objAddress; } @@ -668,6 +711,7 @@ public: File& machofile() const { return ((Section*)(this->_section))->file(); } void setFixupsRange(uint32_t s, uint32_t c); void setUnwindInfoRange(uint32_t s, uint32_t c); + void extendUnwindInfoRange(); void setLineInfoRange(uint32_t s, uint32_t c); bool roomForMoreLineInfoCount() { return (_lineInfoCount < ((1<::setUnwindInfoRange(uint32_t startIndex, uint32_t count) _unwindInfoCount = count; } +template +void Atom::extendUnwindInfoRange() +{ + if ( _unwindInfoCount+1 >= (1 << kUnwindInfoCountBits) ) + throwf("too many compact unwind infos in function %s", this->name()); + _unwindInfoCount += 1; +} + template void Atom::setLineInfoRange(uint32_t startIndex, uint32_t count) { @@ -771,6 +823,8 @@ template const uint8_t* Atom::contentPointer() const { const macho_section

* sct = this->sect().machoSection(); + if ( this->_objAddress > sct->addr() + sct->size() ) + throwf("malformed .o file, symbol has address 0x%0llX which is outside range of its section", (uint64_t)this->_objAddress); uint32_t fileOffset = sct->offset() - sct->addr() + this->_objAddress; return this->sect().file().fileContent()+fileOffset; } @@ -792,8 +846,8 @@ template <> void Atom::verifyAlignment() const { if ( (this->section().type() == ld::Section::typeCode) && ! isThumb() ) { - if ( (_objAddress % 4) != 0 ) - warning("ARM function %s not 4-byte aligned", this->name()); + if ( ((_objAddress % 4) != 0) || (this->alignment().powerOf2 < 2) ) + warning("ARM function not 4-byte aligned: %s from %s", this->name(), this->file()->path()); } } @@ -811,11 +865,13 @@ public: cpu_subtype_t subtype=0); static const char* fileKind(const uint8_t* fileContent); static bool hasObjC2Categories(const uint8_t* fileContent); + static bool hasObjC1Categories(const uint8_t* fileContent); static ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, - const char* path, time_t modTime, uint32_t ordinal, + const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts) { Parser p(fileContent, fileLength, path, modTime, - ordinal, opts.convertUnwindInfo); + ordinal, opts.warnUnwindConversionProblems, + opts.keepDwarfUnwind, opts.forceDwarfConversion); return p.parse(opts); } @@ -884,7 +940,7 @@ public: _allFixups.push_back(FixupInAtom(src, c, k)); } - + const char* path() { return _path; } uint32_t symbolCount() { return _symbolCount; } uint32_t indirectSymbol(uint32_t indirectIndex); const macho_nlist

& symbolFromIndex(uint32_t index); @@ -921,8 +977,13 @@ public: unsigned int stubsSectionNum() { return _stubsSectionNum; } void addDtraceExtraInfos(const SourceLocation& src, const char* provider); const char* scanSymbolTableForAddress(uint64_t addr); - bool convertUnwindInfo() { return _convertUnwindInfo; } - + bool warnUnwindConversionProblems() { return _warnUnwindConversionProblems; } + bool hasDataInCodeLabels() { return _hasDataInCodeLabels; } + bool keepDwarfUnwind() { return _keepDwarfUnwind; } + bool forceDwarfConversion() { return _forceDwarfConversion; } + + macho_data_in_code_entry

* dataInCodeStart() { return _dataInCodeStart; } + macho_data_in_code_entry

* dataInCodeEnd() { return _dataInCodeEnd; } void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target); void addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase); @@ -936,7 +997,7 @@ public: : sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa), cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols), newSection(false), cfiIndex(0), symIndex(0) {} - bool next(Parser& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, + bool next(Parser& parser, const Section& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr, pint_t* addr, pint_t* size, const macho_nlist

** sym); pint_t peek(Parser& parser, pint_t startAddr, pint_t endAddr); void beginSection() { newSection = true; symIndex = 0; } @@ -951,14 +1012,19 @@ public: uint32_t symIndex; }; - struct CFIInfoArray { + struct CFI_CU_InfoArrays { typedef typename CFISection::CFI_Atom_Info CFI_Atom_Info; - CFIInfoArray(const CFI_Atom_Info* cfia, uint32_t cfiac) : array(cfia), count(cfiac) {} - const CFI_Atom_Info* const array; - const uint32_t count; + typedef typename CUSection::Info CU_Info; + CFI_CU_InfoArrays(const CFI_Atom_Info* cfiAr, uint32_t cfiC, CU_Info* cuAr, uint32_t cuC) + : cfiArray(cfiAr), cuArray(cuAr), cfiCount(cfiC), cuCount(cuC) {} + const CFI_Atom_Info* const cfiArray; + CU_Info* const cuArray; + const uint32_t cfiCount; + const uint32_t cuCount; }; + private: friend class Section; @@ -966,7 +1032,8 @@ private: sectionTypeNonLazy, sectionTypeCFI, sectionTypeCString, sectionTypeCStringPointer, sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList, sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs, - sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs }; + sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs, + sectionTypeCompactUnwind }; template struct MachOSectionAndSectionClass @@ -986,19 +1053,24 @@ private: return 1; } }; + + struct ParserAndSectionsArray { Parser* parser; const uint32_t* sortedSectionsArray; }; + Parser(const uint8_t* fileContent, uint64_t fileLength, - const char* path, time_t modTime, - uint32_t ordinal, bool convertUnwindInfo); + const char* path, time_t modTime, ld::File::Ordinal ordinal, + bool warnUnwindConversionProblems, bool keepDwarfUnwind, bool forceDwarfConversion); ld::relocatable::File* parse(const ParserOptions& opts); uint8_t loadCommandSizeMask(); bool parseLoadCommands(); void makeSections(); - void checkForLSDA(); void prescanSymbolTable(); - void makeSortedSymbolsArray(uint32_t array[]); + void makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]); + void makeSortedSectionsArray(uint32_t array[]); static int pointerSorter(const void* l, const void* r); static int symbolIndexSorter(void* extra, const void* l, const void* r); + static int sectionIndexSorter(void* extra, const void* l, const void* r); + void parseDebugInfo(); void parseStabs(); static bool isConstFunStabs(const char *stabStr); @@ -1014,7 +1086,7 @@ private: uint32_t _fileLength; const char* _path; time_t _modTime; - uint32_t _ordinal; + ld::File::Ordinal _ordinal; // filled in by parseLoadCommands() File* _file; @@ -1029,19 +1101,23 @@ private: const macho_section

* _sectionsStart; uint32_t _machOSectionsCount; bool _hasUUID; - + macho_data_in_code_entry

* _dataInCodeStart; + macho_data_in_code_entry

* _dataInCodeEnd; + // filled in by parse() CFISection* _EHFrameSection; + CUSection* _compactUnwindSection; AbsoluteSymbolSection* _absoluteSection; - uint32_t _lsdaTextSectionNum; - uint32_t _lsdaDataSectionNum; uint32_t _tentativeDefinitionCount; uint32_t _absoluteSymbolCount; uint32_t _symbolsInSections; bool _hasLongBranchStubs; bool _AppleObjc; // FSF has objc that uses different data layout bool _overlappingSymbols; - bool _convertUnwindInfo; + bool _warnUnwindConversionProblems; + bool _hasDataInCodeLabels; + bool _keepDwarfUnwind; + bool _forceDwarfConversion; unsigned int _stubsSectionNum; const macho_section

* _stubsMachOSection; std::vector _dtraceProviderInfo; @@ -1052,47 +1128,23 @@ private: template Parser::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, - uint32_t ordinal, bool convertDUI) + ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion) : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime), _ordinal(ordinal), _file(NULL), _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0), _indirectTable(NULL), _indirectTableCount(0), _undefinedStartIndex(0), _undefinedEndIndex(0), _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), - _EHFrameSection(NULL), _absoluteSection(NULL), - _lsdaTextSectionNum(0), _lsdaDataSectionNum(0), + _dataInCodeStart(NULL), _dataInCodeEnd(NULL), + _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL), _tentativeDefinitionCount(0), _absoluteSymbolCount(0), _symbolsInSections(0), _hasLongBranchStubs(false), _AppleObjc(false), - _overlappingSymbols(false), _convertUnwindInfo(convertDUI), + _overlappingSymbols(false), _warnUnwindConversionProblems(convertDUI), _hasDataInCodeLabels(false), + _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion), _stubsSectionNum(0), _stubsMachOSection(NULL) { } -template <> -bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} - -template <> -bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC_64 ) - return false; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return false; - if ( header->filetype() != MH_OBJECT ) - return false; - return true; -} template <> bool Parser::validFile(const uint8_t* fileContent, bool, cpu_subtype_t) @@ -1143,38 +1195,18 @@ bool Parser::validFile(const uint8_t* fileContent, bool subtypeMustMatch, c template <> -const char* Parser::fileKind(const uint8_t* fileContent) +bool Parser::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype) { const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC ) - return NULL; - switch ( header->cpusubtype() ) { - case CPU_SUBTYPE_POWERPC_750: - return "ppc750"; - case CPU_SUBTYPE_POWERPC_7400: - return "ppc7400"; - case CPU_SUBTYPE_POWERPC_7450: - return "ppc7450"; - case CPU_SUBTYPE_POWERPC_970: - return "ppc970"; - case CPU_SUBTYPE_POWERPC_ALL: - return "ppc"; - } - return "ppc???"; + if ( header->magic() != MH_MAGIC_64 ) + return false; + if ( header->cputype() != CPU_TYPE_ARM64 ) + return false; + if ( header->filetype() != MH_OBJECT ) + return false; + return true; } -template <> -const char* Parser::fileKind(const uint8_t* fileContent) -{ - const macho_header

* header = (const macho_header

*)fileContent; - if ( header->magic() != MH_MAGIC ) - return NULL; - if ( header->cputype() != CPU_TYPE_POWERPC64 ) - return NULL; - return "ppc64"; -} template <> const char* Parser::fileKind(const uint8_t* fileContent) @@ -1206,21 +1238,26 @@ const char* Parser::fileKind(const uint8_t* fileContent) return NULL; if ( header->cputype() != CPU_TYPE_ARM ) return NULL; - switch ( header->cpusubtype() ) { - case CPU_SUBTYPE_ARM_V4T: - return "armv4t"; - case CPU_SUBTYPE_ARM_V5TEJ: - return "armv5"; - case CPU_SUBTYPE_ARM_V6: - return "armv6"; - case CPU_SUBTYPE_ARM_V7: - return "armv7"; - case CPU_SUBTYPE_ARM_ALL: - return "arm-ALL"; + for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { + if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) { + return t->archName; + } } return "arm???"; } +#if SUPPORT_ARCH_arm64 +template <> +const char* Parser::fileKind(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + if ( header->magic() != MH_MAGIC ) + return NULL; + if ( header->cputype() != CPU_TYPE_ARM64 ) + return NULL; + return "arm64"; +} +#endif template bool Parser::hasObjC2Categories(const uint8_t* fileContent) @@ -1250,6 +1287,35 @@ bool Parser::hasObjC2Categories(const uint8_t* fileContent) return false; } + +template +bool Parser::hasObjC1Categories(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)fileContent; + const uint32_t cmd_count = header->ncmds(); + const macho_load_command

* const cmds = (macho_load_command

*)((char*)header + sizeof(macho_header

)); + const macho_load_command

* const cmdsEnd = (macho_load_command

*)((char*)header + sizeof(macho_header

) + header->sizeofcmds()); + const macho_load_command

* cmd = cmds; + for (uint32_t i = 0; i < cmd_count; ++i) { + if ( cmd->cmd() == macho_segment_command

::CMD ) { + const macho_segment_command

* segment = (macho_segment_command

*)cmd; + const macho_section

* sectionsStart = (macho_section

*)((char*)segment + sizeof(macho_segment_command

)); + for (uint32_t si=0; si < segment->nsects(); ++si) { + const macho_section

* sect = §ionsStart[si]; + if ( (sect->size() > 0) + && (strcmp(sect->sectname(), "__category") == 0) + && (strcmp(sect->segname(), "__OBJC") == 0) ) { + return true; + } + } + } + cmd = (const macho_load_command

*)(((char*)cmd)+cmd->cmdsize()); + if ( cmd > cmdsEnd ) + throwf("malformed mach-o file, load command #%d is outside size of load commands", i); + } + return false; +} + template int Parser::pointerSorter(const void* l, const void* r) { @@ -1292,7 +1358,7 @@ typename A::P::uint_t Parser::LabelAndCFIBreakIterator::peek(Parser& parse // was becuase of a label, the symbol). Returns false when no more chunks. // template -bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, +bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, const Section& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr, pint_t* addr, pint_t* size, const macho_nlist

** symbol) { // may not be a label on start of section, but need atom demarcation there @@ -1301,9 +1367,12 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, uint32_t sectN // advance symIndex until we get to the first label at or past the start of this section while ( symIndex < sortedSymbolCount ) { const macho_nlist

& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]); - pint_t nextSymbolAddr = sym.n_value(); - if ( (nextSymbolAddr >= startAddr) && (sym.n_sect() >= sectNum) ) - break; + if ( ! sect.ignoreLabel(parser.nameFromSymbol(sym)) ) { + pint_t nextSymbolAddr = sym.n_value(); + //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym)); + if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) ) + break; + } ++symIndex; } if ( symIndex < sortedSymbolCount ) { @@ -1350,7 +1419,19 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, uint32_t sectN *symbol = NULL; return true; } - // no symbols left in whole file, so entire section is one chunk + // no symbols in section, check CFI + if ( cfiIndex < cfiStartsCount ) { + pint_t nextCfiAddr = cfiStartsArray[cfiIndex]; + if ( nextCfiAddr < endAddr ) { + // use cfi + ++cfiIndex; + *addr = nextCfiAddr; + *size = peek(parser, startAddr, endAddr) - nextCfiAddr; + *symbol = NULL; + return true; + } + } + // no cfi, so whole section is one chunk *addr = startAddr; *size = endAddr - startAddr; *symbol = NULL; @@ -1428,6 +1509,16 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, uint32_t sectN return false; } +#define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \ + _type* _name = NULL; \ + uint32_t _name##_count = 1; \ + if ( _actual_count > _maxCount ) \ + _name = (_type*)malloc(sizeof(_type) * _actual_count); \ + else \ + _name##_count = _actual_count; \ + _type _name##_buffer[_name##_count]; \ + if ( _name == NULL ) \ + _name = _name##_buffer; template @@ -1444,44 +1535,62 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) if ( ! parseLoadCommands() ) return _file; + // make array of + uint32_t sortedSectionIndexes[_machOSectionsCount]; + this->makeSortedSectionsArray(sortedSectionIndexes); + // make symbol table sorted by address - this->checkForLSDA(); this->prescanSymbolTable(); uint32_t sortedSymbolIndexes[_symbolsInSections]; - this->makeSortedSymbolsArray(sortedSymbolIndexes); + this->makeSortedSymbolsArray(sortedSymbolIndexes, sortedSectionIndexes); // allocate Section object for each mach-o section makeSections(); - // if it exists, do special parsing of __eh_frame section - // stack allocate array of CFI_Atom_Info + // if it exists, do special early parsing of __compact_unwind section + uint32_t countOfCUs = 0; + if ( _compactUnwindSection != NULL ) + countOfCUs = _compactUnwindSection->count(); + // stack allocate (if not too large) cuInfoBuffer + STACK_ALLOC_IF_SMALL(typename CUSection::Info, cuInfoArray, countOfCUs, 1024); + if ( countOfCUs != 0 ) + _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray); + + // create lists of address that already have compact unwind and thus don't need the dwarf parsed + unsigned cuLsdaCount = 0; + pint_t cuStarts[countOfCUs]; + for (uint32_t i=0; i < countOfCUs; ++i) { + if ( CUSection::encodingMeansUseDwarf(cuInfoArray[i].compactUnwindInfo) ) + cuStarts[i] = -1; + else + cuStarts[i] = cuInfoArray[i].functionStartAddress; + if ( cuInfoArray[i].lsdaAddress != 0 ) + ++cuLsdaCount; + } + + + // if it exists, do special early parsing of __eh_frame section + // stack allocate (if not too large) array of CFI_Atom_Info uint32_t countOfCFIs = 0; if ( _EHFrameSection != NULL ) countOfCFIs = _EHFrameSection->cfiCount(); - typename CFISection::CFI_Atom_Info cfiArray[countOfCFIs]; + STACK_ALLOC_IF_SMALL(typename CFISection::CFI_Atom_Info, cfiArray, countOfCFIs, 1024); + // stack allocate (if not too large) a copy of __eh_frame to apply relocations to - uint8_t* ehBuffer = NULL; - uint32_t stackAllocSize = 0; - if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) { - uint32_t sectSize = _EHFrameSection->machoSection()->size(); - if ( sectSize > 50*1024 ) - ehBuffer = (uint8_t*)malloc(sectSize); - else - stackAllocSize = sectSize; - } - uint32_t ehStackBuffer[1+stackAllocSize/4]; // make 4-byte aligned stack bufffer - if ( ehBuffer == NULL ) - ehBuffer = (uint8_t*)&ehStackBuffer; + uint32_t sectSize = 4; + if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) + sectSize = _EHFrameSection->machoSection()->size()+4; + STACK_ALLOC_IF_SMALL(uint8_t, ehBuffer, sectSize, 50*1024); uint32_t cfiStartsCount = 0; if ( countOfCFIs != 0 ) { - _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs); + _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs, cuStarts, countOfCUs); // count functions and lsdas for(uint32_t i=0; i < countOfCFIs; ++i) { if ( cfiArray[i].isCIE ) continue; - //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n", - // (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress, - // (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress, + //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n", + // (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress, + // (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress, // cfiArray[i].u.fdeInfo.compactUnwindInfo); if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS ) ++cfiStartsCount; @@ -1489,26 +1598,44 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) ++cfiStartsCount; } } - CFIInfoArray cfis(cfiArray, countOfCFIs); + CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs); // create sorted array of function starts and lsda starts - pint_t cfiStartsArray[cfiStartsCount]; + pint_t cfiStartsArray[cfiStartsCount+cuLsdaCount]; uint32_t countOfFDEs = 0; + uint32_t cfiStartsArrayCount = 0; if ( countOfCFIs != 0 ) { - int index = 0; for(uint32_t i=0; i < countOfCFIs; ++i) { if ( cfiArray[i].isCIE ) continue; if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS ) - cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.function.targetAddress; + cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress; if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS ) - cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress; + cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress; ++countOfFDEs; } - ::qsort(cfiStartsArray, cfiStartsCount, sizeof(pint_t), pointerSorter); + } + if ( cuLsdaCount != 0 ) { + // merge in an lsda info from compact unwind + for (uint32_t i=0; i < countOfCUs; ++i) { + if ( cuInfoArray[i].lsdaAddress == 0 ) + continue; + // append to cfiStartsArray if not already in that list + bool found = false; + for(uint32_t j=0; j < cfiStartsArrayCount; ++j) { + if ( cfiStartsArray[j] == cuInfoArray[i].lsdaAddress ) + found = true; + } + if ( ! found ) { + cfiStartsArray[cfiStartsArrayCount++] = cuInfoArray[i].lsdaAddress; + } + } + } + if ( cfiStartsArrayCount != 0 ) { + ::qsort(cfiStartsArray, cfiStartsArrayCount, sizeof(pint_t), pointerSorter); #ifndef NDEBUG // scan for FDEs claming the same function - for(int i=1; i < index; ++i) { + for(uint32_t i=1; i < cfiStartsArrayCount; ++i) { assert( cfiStartsArray[i] != cfiStartsArray[i-1] ); } #endif @@ -1519,7 +1646,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) // figure out how many atoms will be allocated and allocate LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, - cfiStartsCount, _overlappingSymbols); + cfiStartsArrayCount, _overlappingSymbols); uint32_t computedAtomCount = 0; for (uint32_t i=0; i < sectionsCount; ++i ) { breakIterator.beginSection(); @@ -1534,12 +1661,12 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) // have each section append atoms to _atomsArray LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, - cfiStartsCount, _overlappingSymbols); + cfiStartsArrayCount, _overlappingSymbols); for (uint32_t i=0; i < sectionsCount; ++i ) { uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom); breakIterator2.beginSection(); uint32_t count = sections[i]->appendAtoms(*this, atoms, breakIterator2, cfis); - //fprintf(stderr, "append count=%u for section %s\n", count, sections[i]->machoSection()->sectname()); + //fprintf(stderr, "append count=%u for section %s/%s\n", count, sections[i]->machoSection()->segname(), sections[i]->machoSection()->sectname()); _file->_atomsArrayCount += count; } assert( _file->_atomsArrayCount == computedAtomCount && "more atoms allocated than expected"); @@ -1574,7 +1701,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) _allFixups.clear(); // add unwind info - _file->_unwindInfos.reserve(countOfFDEs); + _file->_unwindInfos.reserve(countOfFDEs+countOfCUs); for(uint32_t i=0; i < countOfCFIs; ++i) { if ( cfiArray[i].isCIE ) continue; @@ -1585,9 +1712,40 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) _file->_unwindInfos.push_back(info); Atom* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress); func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1); + //fprintf(stderr, "cu from dwarf =0x%08X, atom=%s\n", info.unwindInfo, func->name()); } } - + // apply compact infos in __LD,__compact_unwind section to each function + // if function also has dwarf unwind, CU will override it + Atom* lastFunc = NULL; + uint32_t lastEnd = 0; + for(uint32_t i=0; i < countOfCUs; ++i) { + typename CUSection::Info* info = &cuInfoArray[i]; + assert(info->function != NULL); + ld::Atom::UnwindInfo ui; + ui.startOffset = info->functionStartAddress - info->function->objectAddress(); + ui.unwindInfo = info->compactUnwindInfo; + _file->_unwindInfos.push_back(ui); + // don't override with converted cu with "use dwarf" cu, if forcing dwarf conversion + if ( !_forceDwarfConversion || !CUSection::encodingMeansUseDwarf(info->compactUnwindInfo) ) { + //fprintf(stderr, "cu=0x%08X, atom=%s\n", ui.unwindInfo, info->function->name()); + // if previous is for same function, extend range + if ( info->function == lastFunc ) { + if ( lastEnd != ui.startOffset ) { + if ( lastEnd < ui.startOffset ) + warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd); + else + warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd); + } + lastFunc->extendUnwindInfoRange(); + } + else + info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1); + lastFunc = info->function; + lastEnd = ui.startOffset + info->rangeLength; + } + } + // parse dwarf debug info to get line info this->parseDebugInfo(); @@ -1596,11 +1754,10 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) -template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } -template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template <> uint8_t Parser::loadCommandSizeMask() { return 0x03; } +template <> uint8_t Parser::loadCommandSizeMask() { return 0x07; } template bool Parser::parseLoadCommands() @@ -1663,7 +1820,29 @@ bool Parser::parseLoadCommands() case LC_UUID: _hasUUID = true; break; - + case LC_DATA_IN_CODE: + { + const macho_linkedit_data_command

* dc = (macho_linkedit_data_command

*)cmd; + _dataInCodeStart = (macho_data_in_code_entry

*)(_fileContent + dc->dataoff()); + _dataInCodeEnd = (macho_data_in_code_entry

*)(_fileContent + dc->dataoff() + dc->datasize()); + if ( _dataInCodeEnd > (macho_data_in_code_entry

*)endOfFile ) + throw "LC_DATA_IN_CODE table extends beyond end of file"; + } + break; + case LC_LINKER_OPTION: + { + const macho_linker_option_command

* loc = (macho_linker_option_command

*)cmd; + const char* buffer = loc->buffer(); + _file->_linkerOptions.resize(_file->_linkerOptions.size() + 1); + std::vector& vec = _file->_linkerOptions.back(); + for (uint32_t j=0; j < loc->count(); ++j) { + vec.push_back(buffer); + buffer += strlen(buffer) + 1; + } + if ( buffer > ((char*)cmd + loc->cmdsize()) ) + throw "malformed LC_LINKER_OPTION"; + } + break; default: if ( cmd->cmd() == macho_segment_command

::CMD ) { if ( segment != NULL ) @@ -1686,31 +1865,6 @@ bool Parser::parseLoadCommands() return true; } -template <> -void Parser::checkForLSDA() -{ - // ARM has no FDEs, so need labels to break up section into atoms -} - -template -void Parser::checkForLSDA() -{ - // ignore labels on __gcc_except_tab section, we'll break it into atoms based on FDE info - for (uint32_t i=0; i < _machOSectionsCount; ++i) { - const macho_section

* sect = &_sectionsStart[i]; - if ( strncmp(sect->sectname(), "__gcc_except_tab", 16) == 0 ) { - if ( strcmp(sect->segname(), "__TEXT") == 0 ) { - assert(_lsdaTextSectionNum == 0); - _lsdaTextSectionNum = i+1; - } - else if ( strcmp(sect->segname(), "__DATA") == 0 ) { - assert(_lsdaDataSectionNum == 0); - _lsdaDataSectionNum = i+1; - } - } - } -} - template void Parser::prescanSymbolTable() @@ -1718,6 +1872,7 @@ void Parser::prescanSymbolTable() _tentativeDefinitionCount = 0; _absoluteSymbolCount = 0; _symbolsInSections = 0; + _hasDataInCodeLabels = false; for (uint32_t i=0; i < this->_symbolCount; ++i) { const macho_nlist

& sym = symbolFromIndex(i); // ignore stabs @@ -1763,15 +1918,12 @@ void Parser::prescanSymbolTable() continue; // 'L' labels do not denote atom breaks - if ( symbolName[0] == 'L' ) - continue; - - // ignore labels in __gcc_except_tab section - if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) ) - continue; - if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) ) + if ( symbolName[0] == 'L' ) { + // Formalize data in code with L$start$ labels + if ( strncmp(symbolName, "L$start$", 8) == 0 ) + _hasDataInCodeLabels = true; continue; - + } // how many def syms in each section if ( sym.n_sect() > _machOSectionsCount ) throw "bad n_sect in symbol table"; @@ -1781,11 +1933,68 @@ void Parser::prescanSymbolTable() } template -int Parser::symbolIndexSorter(void* extra, const void* l, const void* r) +int Parser::sectionIndexSorter(void* extra, const void* l, const void* r) { Parser* parser = (Parser*)extra; const uint32_t* left = (uint32_t*)l; const uint32_t* right = (uint32_t*)r; + const macho_section

* leftSect = parser->machOSectionFromSectionIndex(*left); + const macho_section

* rightSect = parser->machOSectionFromSectionIndex(*right); + + // can't just return difference because 64-bit diff does not fit in 32-bit return type + int64_t result = leftSect->addr() - rightSect->addr(); + if ( result == 0 ) { + // two sections with same start address + // one with zero size goes first + bool leftEmpty = ( leftSect->size() == 0 ); + bool rightEmpty = ( rightSect->size() == 0 ); + if ( leftEmpty != rightEmpty ) { + return ( rightEmpty ? 1 : -1 ); + } + if ( !leftEmpty && !rightEmpty ) + throwf("overlapping sections"); + // both empty, so chose file order + return ( rightSect - leftSect ); + } + else if ( result < 0 ) + return -1; + else + return 1; +} + +template +void Parser::makeSortedSectionsArray(uint32_t array[]) +{ + const bool log = false; + + if ( log ) { + fprintf(stderr, "unsorted sections:\n"); + for(unsigned int i=0; i < _machOSectionsCount; ++i ) + fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[i].addr(), _sectionsStart[i].segname(), _sectionsStart[i].sectname()); + } + + // sort by symbol table address + for (uint32_t i=0; i < _machOSectionsCount; ++i) + array[i] = i; + ::qsort_r(array, _machOSectionsCount, sizeof(uint32_t), this, §ionIndexSorter); + + if ( log ) { + fprintf(stderr, "sorted sections:\n"); + for(unsigned int i=0; i < _machOSectionsCount; ++i ) + fprintf(stderr, "0x%08llX %s %s\n", _sectionsStart[array[i]].addr(), _sectionsStart[array[i]].segname(), _sectionsStart[array[i]].sectname()); + } +} + + + +template +int Parser::symbolIndexSorter(void* extra, const void* l, const void* r) +{ + ParserAndSectionsArray* extraInfo = (ParserAndSectionsArray*)extra; + Parser* parser = extraInfo->parser; + const uint32_t* sortedSectionsArray = extraInfo->sortedSectionsArray; + const uint32_t* left = (uint32_t*)l; + const uint32_t* right = (uint32_t*)r; const macho_nlist

& leftSym = parser->symbolFromIndex(*left); const macho_nlist

& rightSym = parser->symbolFromIndex(*right); // can't just return difference because 64-bit diff does not fit in 32-bit return type @@ -1793,9 +2002,24 @@ int Parser::symbolIndexSorter(void* extra, const void* l, const void* r) if ( result == 0 ) { // two symbols with same address // if in different sections, sort earlier section first - if ( leftSym.n_sect() != rightSym.n_sect() ) - return (leftSym.n_sect() - rightSym.n_sect()); - //, means one is an alias + if ( leftSym.n_sect() != rightSym.n_sect() ) { + for (uint32_t i=0; i < parser->machOSectionCount(); ++i) { + if ( sortedSectionsArray[i]+1 == leftSym.n_sect() ) + return -1; + if ( sortedSectionsArray[i]+1 == rightSym.n_sect() ) + return 1; + } + } + // two symbols in same section, means one is an alias + // if one is ltmp*, make it an alias (sort first) + const char* leftName = parser->nameFromSymbol(leftSym); + const char* rightName = parser->nameFromSymbol(rightSym); + bool leftIsTmp = strncmp(leftName, "ltmp", 4); + bool rightIsTmp = strncmp(rightName, "ltmp", 4); + if ( leftIsTmp != rightIsTmp ) { + return (rightIsTmp ? -1 : 1); + } + // if only one is global, make the other an alias (sort first) if ( (leftSym.n_type() & N_EXT) != (rightSym.n_type() & N_EXT) ) { if ( (rightSym.n_type() & N_EXT) != 0 ) @@ -1803,8 +2027,8 @@ int Parser::symbolIndexSorter(void* extra, const void* l, const void* r) else return 1; } - // if both are global, make alphabetically last one be the alias - return ( strcmp(parser->nameFromSymbol(rightSym), parser->nameFromSymbol(leftSym)) ); + // if both are global, sort alphabetically. earlier one will be the alias + return ( strcmp(rightName, leftName) ); } else if ( result < 0 ) return -1; @@ -1812,9 +2036,12 @@ int Parser::symbolIndexSorter(void* extra, const void* l, const void* r) return 1; } + template -void Parser::makeSortedSymbolsArray(uint32_t array[]) +void Parser::makeSortedSymbolsArray(uint32_t array[], const uint32_t sectionArray[]) { + const bool log = false; + uint32_t* p = array; for (uint32_t i=0; i < this->_symbolCount; ++i) { const macho_nlist

& sym = symbolFromIndex(i); @@ -1831,12 +2058,6 @@ void Parser::makeSortedSymbolsArray(uint32_t array[]) if ( symbolName[0] == 'L' ) continue; - // ignore labels in __gcc_except_tab section - if ( (_lsdaTextSectionNum != 0) && (sym.n_sect() == _lsdaTextSectionNum) ) - continue; - if ( (_lsdaDataSectionNum != 0) && (sym.n_sect() == _lsdaDataSectionNum) ) - continue; - // how many def syms in each section if ( sym.n_sect() > _machOSectionsCount ) throw "bad n_sect in symbol table"; @@ -1847,7 +2068,9 @@ void Parser::makeSortedSymbolsArray(uint32_t array[]) assert(p == &array[_symbolsInSections] && "second pass over symbol table yield a different number of symbols"); // sort by symbol table address - ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), this, &symbolIndexSorter); + ParserAndSectionsArray extra = { this, sectionArray }; + ::qsort_r(array, _symbolsInSections, sizeof(uint32_t), &extra, &symbolIndexSorter); + // look for two symbols at same address _overlappingSymbols = false; @@ -1855,15 +2078,17 @@ void Parser::makeSortedSymbolsArray(uint32_t array[]) if ( symbolFromIndex(array[i-1]).n_value() == symbolFromIndex(array[i]).n_value() ) { //fprintf(stderr, "overlapping symbols at 0x%08llX\n", symbolFromIndex(array[i-1]).n_value()); _overlappingSymbols = true; + break; } } - //fprintf(stderr, "sorted symbols:\n"); - //for(unsigned int i=0; i < _symbolsInSections; ++i ) - // fprintf(stderr, "0x%09llX symIndex=%3d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) ); + if ( log ) { + fprintf(stderr, "sorted symbols:\n"); + for(unsigned int i=0; i < _symbolsInSections; ++i ) + fprintf(stderr, "0x%09llX symIndex=%d sectNum=%2d, %s\n", symbolFromIndex(array[i]).n_value(), array[i], symbolFromIndex(array[i]).n_sect(), nameFromSymbol(symbolFromIndex(array[i])) ); + } } - template void Parser::makeSections() { @@ -1876,21 +2101,30 @@ void Parser::makeSections() unsigned int count = 0; for (uint32_t i=0; i < _machOSectionsCount; ++i) { const macho_section

* sect = &_sectionsStart[i]; - // ignore dwarf sections if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) { - // note that .o file has dwarf - _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf; - // save off iteresting dwarf sections - if ( strcmp(sect->sectname(), "__debug_info") == 0 ) - _file->_dwarfDebugInfoSect = sect; - else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 ) - _file->_dwarfDebugAbbrevSect = sect; - else if ( strcmp(sect->sectname(), "__debug_line") == 0 ) - _file->_dwarfDebugLineSect = sect; - else if ( strcmp(sect->sectname(), "__debug_str") == 0 ) - _file->_dwarfDebugStringSect = sect; - // linker does not propagate dwarf sections to output file - continue; + if ( strcmp(sect->segname(), "__DWARF") == 0 ) { + // note that .o file has dwarf + _file->_debugInfoKind = ld::relocatable::File::kDebugInfoDwarf; + // save off iteresting dwarf sections + if ( strcmp(sect->sectname(), "__debug_info") == 0 ) + _file->_dwarfDebugInfoSect = sect; + else if ( strcmp(sect->sectname(), "__debug_abbrev") == 0 ) + _file->_dwarfDebugAbbrevSect = sect; + else if ( strcmp(sect->sectname(), "__debug_line") == 0 ) + _file->_dwarfDebugLineSect = sect; + else if ( strcmp(sect->sectname(), "__debug_str") == 0 ) + _file->_dwarfDebugStringSect = sect; + // linker does not propagate dwarf sections to output file + continue; + } + else if ( strcmp(sect->segname(), "__LD") == 0 ) { + if ( strncmp(sect->sectname(), "__compact_unwind", 16) == 0 ) { + machOSects[count].sect = sect; + totalSectionsSize += sizeof(CUSection); + machOSects[count++].type = sectionTypeCompactUnwind; + continue; + } + } } // ignore empty __OBJC sections if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) ) @@ -1904,6 +2138,7 @@ void Parser::makeSections() // }; // #define OBJC_IMAGE_SUPPORTS_GC 2 // #define OBJC_IMAGE_GC_ONLY 4 + // #define OBJC_IMAGE_IS_SIMULATED 32 // const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset()); if ( (sect->size() >= 8) && (contents[0] == 0) ) { @@ -1912,17 +2147,17 @@ void Parser::makeSections() _file->_objConstraint = ld::File::objcConstraintGC; else if ( (flags & 2) == 2 ) _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC; + else if ( (flags & 32) == 32 ) + _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator; else _file->_objConstraint = ld::File::objcConstraintRetainRelease; - if ( (flags & 1) == 1 ) - _file->_ojcReplacmentClass = true; if ( sect->size() > 8 ) { warning("section %s/%s has unexpectedly large size %llu in %s", - sect->segname(), sect->sectname(), sect->size(), _file->path()); + sect->segname(), Section::makeSectionName(sect), sect->size(), _file->path()); } } else { - warning("can't parse %s/%s section in %s", sect->segname(), sect->sectname(), _file->path()); + warning("can't parse %s/%s section in %s", sect->segname(), Section::makeSectionName(sect), _file->path()); } continue; } @@ -2101,6 +2336,11 @@ void Parser::makeSections() *objects++ = new (space) TLVDefsSection(*this, *_file, machOSects[i].sect); space += sizeof(TLVDefsSection); break; + case sectionTypeCompactUnwind: + _compactUnwindSection = new (space) CUSection(*this, *_file, machOSects[i].sect); + *objects++ = _compactUnwindSection; + space += sizeof(CUSection); + break; case sectionTypeTentativeDefinitions: *objects++ = new (space) TentativeDefinitionSection(*this, *_file); space += sizeof(TentativeDefinitionSection); @@ -2330,8 +2570,14 @@ const char* Parser::scanSymbolTableForAddress(uint64_t addr) continue; // return with exact match - if ( sym.n_value() == addr ) - return nameFromSymbol(sym); + if ( sym.n_value() == addr ) { + const char* name = nameFromSymbol(sym); + if ( strncmp(name, "ltmp", 4) != 0 ) + return name; + // treat 'ltmp*' labels as close match + closestSymAddr = sym.n_value(); + closestSymName = name; + } // record closest seen so far if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) ) @@ -2386,9 +2632,23 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co case ld::Fixup::kindStoreThumbBranch22: firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22; break; - case ld::Fixup::kindStorePPCBranch24: - firstKind = ld::Fixup::kindStoreTargetAddressPPCBranch24; +#if SUPPORT_ARCH_arm64 + case ld::Fixup::kindStoreARM64Branch26: + firstKind = ld::Fixup::kindStoreTargetAddressARM64Branch26; + break; + case ld::Fixup::kindStoreARM64Page21: + firstKind = ld::Fixup::kindStoreTargetAddressARM64Page21; break; + case ld::Fixup::kindStoreARM64PageOff12: + firstKind = ld::Fixup::kindStoreTargetAddressARM64PageOff12; + break; + case ld::Fixup::kindStoreARM64GOTLoadPage21: + firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21; + break; + case ld::Fixup::kindStoreARM64GOTLoadPageOff12: + firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12; + break; +#endif default: combined = false; cl = ld::Fixup::k1of2; @@ -2407,6 +2667,10 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co // backing string in CFStrings should always be direct addFixup(src, cl, firstKind, target.atom); } + else if ( (src.atom == target.atom) && (target.atom->combine() == ld::Atom::combineByName) ) { + // reference to self should always be direct + addFixup(src, cl, firstKind, target.atom); + } else { // change direct fixup to by-name fixup addFixup(src, cl, firstKind, false, target.atom->name()); @@ -2462,7 +2726,7 @@ void Parser::addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const template uint32_t TentativeDefinitionSection::computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { return parser.tentativeDefinitionCount(); } @@ -2470,7 +2734,7 @@ uint32_t TentativeDefinitionSection::computeAtomCount(class Parser& parser template uint32_t TentativeDefinitionSection::appendAtoms(class Parser& parser, uint8_t* p, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { this->_beginAtoms = (Atom*)p; uint32_t count = 0; @@ -2489,8 +2753,8 @@ uint32_t TentativeDefinitionSection::appendAtoms(class Parser& parser, uin ++alignP2; } // limit alignment of extremely large commons to 2^15 bytes (8-page) - if ( alignP2 > 12 ) - alignP2 = 12; + if ( alignP2 > 15 ) + alignP2 = 15; Atom* allocatedSpace = (Atom*)p; new (allocatedSpace) Atom(*this, parser.nameFromSymbol(sym), (pint_t)ULLONG_MAX, size, ld::Atom::definitionTentative, ld::Atom::combineByName, @@ -2508,7 +2772,7 @@ uint32_t TentativeDefinitionSection::appendAtoms(class Parser& parser, uin template uint32_t AbsoluteSymbolSection::computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { return parser.absoluteSymbolCount(); } @@ -2516,7 +2780,7 @@ uint32_t AbsoluteSymbolSection::computeAtomCount(class Parser& parser, template uint32_t AbsoluteSymbolSection::appendAtoms(class Parser& parser, uint8_t* p, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { this->_beginAtoms = (Atom*)p; uint32_t count = 0; @@ -2792,6 +3056,22 @@ bool Parser::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t sz = 4; break; + case DW_FORM_sec_offset: + sz = sizeof(typename A::P::uint_t); + break; + + case DW_FORM_exprloc: + sz = read_uleb128 (offset, end); + break; + + case DW_FORM_flag_present: + sz = 0; + break; + + case DW_FORM_ref_sig8: + sz = 8; + break; + default: return false; } @@ -2859,14 +3139,27 @@ void Parser::parseDebugInfo() return; uint64_t stmtList; - if ( !read_comp_unit(&_file->_dwarfTranslationUnitFile, &_file->_dwarfTranslationUnitDir, &stmtList) ) { + const char* tuDir; + const char* tuName; + if ( !read_comp_unit(&tuName, &tuDir, &stmtList) ) { // if can't parse dwarf, warn and give up - _file->_dwarfTranslationUnitFile = NULL; - _file->_dwarfTranslationUnitDir = NULL; + _file->_dwarfTranslationUnitPath = NULL; warning("can't parse dwarf compilation unit info in %s", _path); _file->_debugInfoKind = ld::relocatable::File::kDebugInfoNone; return; } + if ( (tuName != NULL) && (tuName[0] == '/') ) { + _file->_dwarfTranslationUnitPath = tuName; + } + else if ( (tuDir != NULL) && (tuName != NULL) ) { + asprintf((char**)&(_file->_dwarfTranslationUnitPath), "%s/%s", tuDir, tuName); + } + else if ( tuDir == NULL ) { + _file->_dwarfTranslationUnitPath = tuName; + } + else { + _file->_dwarfTranslationUnitPath = NULL; + } // add line number info to atoms from dwarf std::vector > entries; @@ -3349,14 +3642,9 @@ File::~File() } template -bool File::translationUnitSource(const char** dir, const char** name) const +const char* File::translationUnitSource() const { - if ( _debugInfoKind == ld::relocatable::File::kDebugInfoDwarf ) { - *dir = _dwarfTranslationUnitDir; - *name = _dwarfTranslationUnitFile; - return (_dwarfTranslationUnitFile != NULL); - } - return false; + return _dwarfTranslationUnitPath; } @@ -3488,6 +3776,8 @@ ld::Section::Type Section::sectionType(const macho_section* se return ld::Section::typeCode; else if ( strcmp(sect->sectname(), "__StaticInit") == 0 ) return ld::Section::typeCode; + else if ( strcmp(sect->sectname(), "__constructor") == 0 ) + return ld::Section::typeInitializerPointers; } else if ( strcmp(sect->segname(), "__DATA") == 0 ) { if ( strcmp(sect->sectname(), "__cfstring") == 0 ) @@ -3567,8 +3857,6 @@ uint32_t Section::sectionNum(class Parser& parser) const return 1 + (this->_machOSection - parser.firstMachOSection()); } -// libunwind does not support ppc64 -template <> uint32_t CFISection::cfiCount() { return 0; } // arm does not have zero cost exceptions template <> uint32_t CFISection::cfiCount() { return 0; } @@ -3585,7 +3873,7 @@ template void CFISection::warnFunc(void* ref, uint64_t funcAddr, const char* msg) { Parser* parser = (Parser*)ref; - if ( ! parser->convertUnwindInfo() ) + if ( ! parser->warnUnwindConversionProblems() ) return; if ( funcAddr != CFI_INVALID_ADDRESS ) { // atoms are not constructed yet, so scan symbol table for labels @@ -3603,6 +3891,12 @@ bool CFISection::needsRelocating() return true; } +template <> +bool CFISection::needsRelocating() +{ + return true; +} + template bool CFISection::needsRelocating() { @@ -3610,9 +3904,9 @@ bool CFISection::needsRelocating() } template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, +void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) + 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()); @@ -3658,7 +3952,6 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, } } - // create ObjectAddressSpace object for use by libunwind OAS oas(*this, buffer); @@ -3666,7 +3959,7 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, const char* msg; msg = libunwind::DwarfInstructions::parseCFIs( oas, this->_machOSection->addr(), this->_machOSection->size(), - cfiArray, count, (void*)&parser, warnFunc); + cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc); if ( msg != NULL ) throwf("malformed __eh_frame section: %s", msg); } @@ -3674,7 +3967,7 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, template <> void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) + uint32_t& count, const pint_t cuStarts[], uint32_t cuCount) { // create ObjectAddressSpace object for use by libunwind OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset()); @@ -3683,56 +3976,95 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, const char* msg; msg = libunwind::DwarfInstructions::parseCFIs( oas, this->_machOSection->addr(), this->_machOSection->size(), - cfiArray, count, (void*)&parser, warnFunc); + cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc); if ( msg != NULL ) throwf("malformed __eh_frame section: %s", msg); } -// need to change libunwind parseCFIs() to work for ppc + + template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, - libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) +void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, + libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], + uint32_t& count, const pint_t cuStarts[], uint32_t cuCount) { - // create ObjectAddressSpace object for use by libunwind - OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset()); - - // use libuwind to parse __eh_frame data into array of CFI_Atom_Info - const char* msg; - msg = libunwind::DwarfInstructions::parseCFIs( - oas, this->_machOSection->addr(), this->_machOSection->size(), - cfiArray, count, (void*)&parser, warnFunc); - if ( msg != NULL ) - throwf("malformed __eh_frame section: %s", msg); -} - -template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, - libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) -{ - // libunwind does not support ppc64 + // arm does not use zero cost exceptions assert(count == 0); } template <> -void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, - libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], - uint32_t count) +void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, + libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], + uint32_t& count, const pint_t cuStarts[], uint32_t cuCount) { - // arm does not use zero cost exceptions - assert(count == 0); -} + // copy __eh_frame data to buffer + memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size()); + // and apply relocations + const macho_relocation_info

* relocs = (macho_relocation_info

*)(file().fileContent() + this->_machOSection->reloff()); + const macho_relocation_info

* relocsEnd = &relocs[this->_machOSection->nreloc()]; + for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { + uint64_t* p64 = (uint64_t*)&buffer[reloc->r_address()]; + uint32_t* p32 = (uint32_t*)&buffer[reloc->r_address()]; + uint32_t addend32 = E::get32(*p32); + uint64_t addend64 = E::get64(*p64); + uint64_t value = 0; + switch ( reloc->r_type() ) { + case ARM64_RELOC_SUBTRACTOR: + value = 0 - parser.symbolFromIndex(reloc->r_symbolnum()).n_value(); + ++reloc; + if ( reloc->r_extern() ) + value += parser.symbolFromIndex(reloc->r_symbolnum()).n_value(); + break; + case ARM64_RELOC_UNSIGNED: + value = parser.symbolFromIndex(reloc->r_symbolnum()).n_value(); + break; + case ARM64_RELOC_POINTER_TO_GOT: + // this is used for the reference to the personality function in CIEs + // store the symbol number of the personality function for later use as a Fixup + value = reloc->r_symbolnum(); + addend32 = 0; + addend64 = 0; + break; + default: + fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address()); + break; + } + switch ( reloc->r_length() ) { + case 3: + E::set64(*p64, value + addend64); + break; + case 2: + E::set32(*p32, value + addend32); + break; + default: + fprintf(stderr, "CFISection::cfiParse() unexpected relocation size at r_address=0x%08X\n", reloc->r_address()); + break; + } + } + + + // create ObjectAddressSpace object for use by libunwind + OAS oas(*this, buffer); + + // use libuwind to parse __eh_frame data into array of CFI_Atom_Info + const char* msg; + msg = libunwind::DwarfInstructions::parseCFIs( + oas, this->_machOSection->addr(), this->_machOSection->size(), + cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), + cfiArray, count, (void*)&parser, warnFunc); + if ( msg != NULL ) + throwf("malformed __eh_frame section: %s", msg); +} template uint32_t CFISection::computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray& cfis) + const struct Parser::CFI_CU_InfoArrays& cfis) { - return cfis.count; + return cfis.cfiCount; } @@ -3740,12 +4072,12 @@ uint32_t CFISection::computeAtomCount(class Parser& parser, template uint32_t CFISection::appendAtoms(class Parser& parser, uint8_t* p, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray& cfis) + const struct Parser::CFI_CU_InfoArrays& cfis) { this->_beginAtoms = (Atom*)p; // walk CFI_Atom_Info array and create atom for each entry - const CFI_Atom_Info* start = &cfis.array[0]; - const CFI_Atom_Info* end = &cfis.array[cfis.count]; + const CFI_Atom_Info* start = &cfis.cfiArray[0]; + const CFI_Atom_Info* end = &cfis.cfiArray[cfis.cfiCount]; for(const CFI_Atom_Info* a=start; a < end; ++a) { Atom* space = (Atom*)p; new (space) Atom(*this, (a->isCIE ? "CIE" : "FDE"), a->address, a->size, @@ -3755,15 +4087,14 @@ uint32_t CFISection::appendAtoms(class Parser& parser, uint8_t* p, p += sizeof(Atom); } this->_endAtoms = (Atom*)p; - return cfis.count; + return cfis.cfiCount; } template <> bool CFISection::bigEndian() { return false; } template <> bool CFISection::bigEndian() { return false; } template <> bool CFISection::bigEndian() { return false; } -template <> bool CFISection::bigEndian() { return true; } -template <> bool CFISection::bigEndian() { return true; } +template <> bool CFISection::bigEndian() { return false; } template <> @@ -3813,46 +4144,47 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, const C } + +#if SUPPORT_ARCH_arm64 template <> -void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) +void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) { uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress; - if ( (personalityEncoding == 0x9B) || (personalityEncoding == 0x90) ) { - uint32_t offsetInCFI = cieInfo->u.cieInfo.personality.offsetInCFI; - uint32_t nlpAddr = cieInfo->u.cieInfo.personality.targetAddress; - Atom* cieAtom = this->findAtomByAddress(cieInfo->address); - Atom* nlpAtom = parser.findAtomByAddress(nlpAddr); - assert(nlpAtom->contentType() == ld::Atom::typeNonLazyPointer); - Parser::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI); + if ( personalityEncoding == 0x9B ) { + // compiler always produces ARM64_RELOC_GOT r_pcrel=1 to personality function + // CFISection::cfiParse() set targetAddress to be symbolIndex + addressInCIE + uint32_t symbolIndex = cieInfo->u.cieInfo.personality.targetAddress + - cieInfo->address - cieInfo->u.cieInfo.personality.offsetInCFI; + const macho_nlist

& sym = parser.symbolFromIndex(symbolIndex); + const char* personalityName = parser.nameFromSymbol(sym); - parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, nlpAtom); - parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, cieAtom); - parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, offsetInCFI); - parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreBigEndian32); + Atom* cieAtom = this->findAtomByAddress(cieInfo->address); + Parser::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI); + parser.addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, false, personalityName); + parser.addFixup(src, ld::Fixup::k2of2, ld::Fixup::kindStoreARM64PCRelToGOT); } else if ( personalityEncoding != 0 ) { throwf("unsupported address encoding (%02X) of personality function in CIE", - personalityEncoding); + personalityEncoding); } } - +#endif template void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) { - // FIX ME - assert(0); + assert(0 && "addCiePersonalityFixups() not implemented for arch"); } template -void CFISection::makeFixups(class Parser& parser, const struct Parser::CFIInfoArray& cfis) +void CFISection::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays& cfis) { ld::Fixup::Kind store32 = bigEndian() ? ld::Fixup::kindStoreBigEndian32 : ld::Fixup::kindStoreLittleEndian32; ld::Fixup::Kind store64 = bigEndian() ? ld::Fixup::kindStoreBigEndian64 : ld::Fixup::kindStoreLittleEndian64; // add all references for FDEs, including implicit group references - const CFI_Atom_Info* end = &cfis.array[cfis.count]; - for(const CFI_Atom_Info* p = &cfis.array[0]; p < end; ++p) { + const CFI_Atom_Info* end = &cfis.cfiArray[cfis.cfiCount]; + for(const CFI_Atom_Info* p = &cfis.cfiArray[0]; p < end; ++p) { if ( p->isCIE ) { // add reference to personality function if used if ( p->u.cieInfo.personality.targetAddress != CFI_INVALID_ADDRESS ) { @@ -4072,6 +4404,215 @@ typename A::P::uint_t CFISection::OAS::getEncodedP(pint_t& addr, pint_t end, return result; } +template <> +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info* reloc) +{ + if ( reloc->r_extern() ) { + assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section"); + const macho_nlist

& sym = parser.symbolFromIndex(reloc->r_symbolnum()); + return parser.nameFromSymbol(sym); + } + else { + const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address()); + pint_t personalityAddr = *content; + Section* personalitySection = parser.sectionForAddress(personalityAddr); + assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function"); + // atoms may not be constructed yet, so scan symbol table for labels + const char* name = parser.scanSymbolTableForAddress(personalityAddr); + return name; + } +} + +template <> +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info* reloc) +{ + if ( reloc->r_extern() ) { + assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section"); + const macho_nlist

& sym = parser.symbolFromIndex(reloc->r_symbolnum()); + return parser.nameFromSymbol(sym); + } + else { + // support __LD, __compact_unwind personality entries which are pointer to personality non-lazy pointer + const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address()); + pint_t nlPointerAddr = *content; + Section* nlSection = parser.sectionForAddress(nlPointerAddr); + if ( nlSection->type() == ld::Section::typeCode ) { + // personality function is defined in this .o file, so this is a direct reference to it + // atoms may not be constructed yet, so scan symbol table for labels + const char* name = parser.scanSymbolTableForAddress(nlPointerAddr); + return name; + } + else { + uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(nlPointerAddr, nlSection->machoSection()); + const macho_nlist

& nlSymbol = parser.symbolFromIndex(symIndex); + return parser.nameFromSymbol(nlSymbol); + } + } +} + +#if SUPPORT_ARCH_arm64 +template <> +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info* reloc) +{ + if ( reloc->r_extern() ) { + assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section"); + const macho_nlist

& sym = parser.symbolFromIndex(reloc->r_symbolnum()); + return parser.nameFromSymbol(sym); + } + else { + const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address()); + pint_t personalityAddr = *content; + Section* personalitySection = parser.sectionForAddress(personalityAddr); + assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function"); + // atoms may not be constructed yet, so scan symbol table for labels + const char* name = parser.scanSymbolTableForAddress(personalityAddr); + return name; + } +} +#endif + +template +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info

* reloc) +{ + return NULL; +} + +template <> +bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) +{ + return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF); +} + +template <> +bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) +{ + return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF); +} + +#if SUPPORT_ARCH_arm_any +template <> +bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) +{ + return false; +} +#endif + +#if SUPPORT_ARCH_arm64 +template <> +bool CUSection::encodingMeansUseDwarf(compact_unwind_encoding_t enc) +{ + return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF); +} +#endif + +template +int CUSection::infoSorter(const void* l, const void* r) +{ + // sort references by symbol index, then address + const Info* left = (Info*)l; + const Info* right = (Info*)r; + if ( left->functionSymbolIndex == right->functionSymbolIndex ) + return (left->functionStartAddress - right->functionStartAddress); + else + return (left->functionSymbolIndex - right->functionSymbolIndex); +} + +template +void CUSection::parse(class Parser& parser, uint32_t cnt, Info array[]) +{ + // walk section content and copy to Info array + const macho_compact_unwind_entry

* const entries = (macho_compact_unwind_entry

*)(this->file().fileContent() + this->_machOSection->offset()); + for (uint32_t i=0; i < cnt; ++i) { + Info* info = &array[i]; + const macho_compact_unwind_entry

* entry = &entries[i]; + info->functionStartAddress = entry->codeStart(); + info->functionSymbolIndex = 0xFFFFFFFF; + info->rangeLength = entry->codeLen(); + info->compactUnwindInfo = entry->compactUnwindInfo(); + info->personality = NULL; + info->lsdaAddress = entry->lsda(); + info->function = NULL; + info->lsda = NULL; + if ( (info->compactUnwindInfo & UNWIND_PERSONALITY_MASK) != 0 ) + warning("no bits should be set in UNWIND_PERSONALITY_MASK of compact unwind encoding in __LD,__compact_unwind section"); + if ( info->lsdaAddress != 0 ) { + info->compactUnwindInfo |= UNWIND_HAS_LSDA; + } + } + + // scan relocs, extern relocs are needed for personality references (possibly for function/lsda refs??) + const macho_relocation_info

* relocs = (macho_relocation_info

*)(this->file().fileContent() + this->_machOSection->reloff()); + const macho_relocation_info

* relocsEnd = &relocs[this->_machOSection->nreloc()]; + for (const macho_relocation_info

* reloc = relocs; reloc < relocsEnd; ++reloc) { + if ( reloc->r_extern() ) { + // only expect external relocs on some colummns + if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry

)) == macho_compact_unwind_entry

::personalityFieldOffset() ) { + uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry

); + array[entryIndex].personality = this->personalityName(parser, reloc); + } + else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry

)) == macho_compact_unwind_entry

::lsdaFieldOffset() ) { + uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry

); + const macho_nlist

& lsdaSym = parser.symbolFromIndex(reloc->r_symbolnum()); + if ( (lsdaSym.n_type() & N_TYPE) == N_SECT ) + array[entryIndex].lsdaAddress = lsdaSym.n_value(); + else + warning("unexpected extern relocation to lsda in __compact_unwind section"); + } + else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry

)) == macho_compact_unwind_entry

::codeStartFieldOffset() ) { + uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry

); + array[entryIndex].functionSymbolIndex = reloc->r_symbolnum(); + array[entryIndex].functionStartAddress += parser.symbolFromIndex(reloc->r_symbolnum()).n_value(); + } + else { + warning("unexpected extern relocation in __compact_unwind section"); + } + } + else { + if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry

)) == macho_compact_unwind_entry

::personalityFieldOffset() ) { + uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry

); + array[entryIndex].personality = this->personalityName(parser, reloc); + } + } + } + + // sort array by function start address so unwind infos will be contiguous for a given function + ::qsort(array, cnt, sizeof(Info), infoSorter); +} + +template +uint32_t CUSection::count() +{ + const macho_section

* machoSect = this->machoSection(); + if ( (machoSect->size() % sizeof(macho_compact_unwind_entry

)) != 0 ) + throw "malformed __LD,__compact_unwind section, bad length"; + + return machoSect->size() / sizeof(macho_compact_unwind_entry

); +} + +template +void CUSection::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays& cus) +{ + Info* const arrayStart = cus.cuArray; + Info* const arrayEnd = &cus.cuArray[cus.cuCount]; + for (Info* info=arrayStart; info < arrayEnd; ++info) { + // find function atom from address + info->function = parser.findAtomByAddress(info->functionStartAddress); + // find lsda atom from address + if ( info->lsdaAddress != 0 ) { + info->lsda = parser.findAtomByAddress(info->lsdaAddress); + // add lsda subordinate + typename Parser::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress()); + parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinateLSDA, info->lsda); + } + if ( info->personality != NULL ) { + // add personality subordinate + typename Parser::SourceLocation src(info->function, info->functionStartAddress - info->function->objectAddress()); + parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinatePersonality, false, info->personality); + } + } + +} + template SymboledSection::SymboledSection(Parser& parser, File& f, const macho_section* s) : Section(f, s), _type(ld::Atom::typeUnclassified) @@ -4101,6 +4642,8 @@ SymboledSection::SymboledSection(Parser& parser, File& f, const macho_s case S_REGULAR: if ( strncmp(s->sectname(), "__gcc_except_tab", 16) == 0 ) _type = ld::Atom::typeLSDA; + else if ( this->type() == ld::Section::typeInitializerPointers ) + _type = ld::Atom::typeInitializerPointers; break; } } @@ -4127,7 +4670,7 @@ bool SymboledSection::dontDeadStrip() template uint32_t SymboledSection::computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { const pint_t startAddr = this->_machOSection->addr(); const pint_t endAddr = startAddr + this->_machOSection->size(); @@ -4137,7 +4680,7 @@ uint32_t SymboledSection::computeAtomCount(class Parser& parser, pint_t addr; pint_t size; const macho_nlist

* sym; - while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &sym) ) { + while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &sym) ) { ++count; } //fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count); @@ -4146,8 +4689,8 @@ uint32_t SymboledSection::computeAtomCount(class Parser& parser, template uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, - struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + struct Parser::LabelAndCFIBreakIterator& it, + const struct Parser::CFI_CU_InfoArrays&) { this->_beginAtoms = (Atom*)p; @@ -4160,7 +4703,7 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, pint_t addr; pint_t size; const macho_nlist

* label; - while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &label) ) { + while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &label) ) { Atom* allocatedSpace = (Atom*)p; // is break because of label or CFI? if ( label != NULL ) { @@ -4173,8 +4716,12 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, this->_hasAliases = true; } else { - new (allocatedSpace) Atom(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever, - ld::Atom::scopeTranslationUnit, this->contentType(), ld::Atom::symbolTableNotIn, + ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn; + ld::Atom::ContentType ctype = this->contentType(); + if ( ctype == ld::Atom::typeLSDA ) + inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel; + new (allocatedSpace) Atom(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever, + ld::Atom::scopeTranslationUnit, ctype, inclusion, this->dontDeadStrip(), false, false, this->alignmentForAddress(addr)); } p += sizeof(Atom); @@ -4186,10 +4733,23 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, } +template <> +ld::Atom::SymbolTableInclusion ImplicitSizeSection::symbolTableInclusion() +{ + return ld::Atom::symbolTableInWithRandomAutoStripLabel; +} + +template +ld::Atom::SymbolTableInclusion ImplicitSizeSection::symbolTableInclusion() +{ + return ld::Atom::symbolTableNotIn; +} + + template uint32_t ImplicitSizeSection::computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { uint32_t count = 0; const macho_section

* sect = this->machoSection(); @@ -4203,15 +4763,18 @@ uint32_t ImplicitSizeSection::computeAtomCount(class Parser& parser, // if there are multiple labels in this section for the same address, then clone them into multi atoms pint_t prevSymbolAddr = (pint_t)(-1); uint8_t prevSymbolSectNum = 0; + bool prevIgnore = false; for(uint32_t i=0; i < it.sortedSymbolCount; ++i) { const macho_nlist

& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]); const pint_t symbolAddr = sym.n_value(); - const pint_t symbolSectNum = sym.n_sect(); - if ( (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) { + const uint8_t symbolSectNum = sym.n_sect(); + const bool ignore = this->ignoreLabel(parser.nameFromSymbol(sym)); + if ( !ignore && !prevIgnore && (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) { ++count; } prevSymbolAddr = symbolAddr; prevSymbolSectNum = symbolSectNum; + prevIgnore = ignore; } } return count; @@ -4220,7 +4783,7 @@ uint32_t ImplicitSizeSection::computeAtomCount(class Parser& parser, template uint32_t ImplicitSizeSection::appendAtoms(class Parser& parser, uint8_t* p, struct Parser::LabelAndCFIBreakIterator& it, - const struct Parser::CFIInfoArray&) + const struct Parser::CFI_CU_InfoArrays&) { this->_beginAtoms = (Atom*)p; @@ -4234,33 +4797,44 @@ uint32_t ImplicitSizeSection::appendAtoms(class Parser& parser, uint8_t* p pint_t size; const macho_nlist

* foundLabel; Atom* allocatedSpace; - while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) { + while ( it.next(parser, *this, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) { if ( foundLabel != NULL ) { + bool skip = false; pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr); allocatedSpace = (Atom*)p; if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) { - //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)foundAddr); - new (allocatedSpace) Atom(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr, + if ( size == 0 ) { + // + // a size of zero means there is another label at same location + // and we are supposed to ignore this label + skip = true; + } + else { + //fprintf(stderr, " 0x%08llX make annon, size=%lld\n", (uint64_t)foundAddr, (uint64_t)size); + new (allocatedSpace) Atom(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr, this->elementSizeAtAddress(foundAddr), this->definition(), this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr), this->contentType(), this->symbolTableInclusion(), this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr)); + } } else { // make named atom for label //fprintf(stderr, " 0x%08llX make labeled\n", (uint64_t)foundAddr); new (allocatedSpace) Atom(*this, parser, *foundLabel, labeledAtomSize); } - ++count; - p += sizeof(Atom); - foundAddr += labeledAtomSize; - size -= labeledAtomSize; + if ( !skip ) { + ++count; + p += sizeof(Atom); + foundAddr += labeledAtomSize; + size -= labeledAtomSize; + } } // some number of anonymous atoms for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) { // make anon atoms for area before label if ( this->useElementAt(parser, it, addr) ) { - //fprintf(stderr, " 0x%08llX make annon\n", (uint64_t)addr); + //fprintf(stderr, " 0x%08llX make annon, size=%lld\n", (uint64_t)addr, (uint64_t)elementSizeAtAddress(addr)); allocatedSpace = (Atom*)p; new (allocatedSpace) Atom(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr), this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr), @@ -4382,6 +4956,13 @@ bool CStringSection::useElementAt(Parser& parser, struct Parser::LabelA return true; } +template +bool CStringSection::ignoreLabel(const char* label) const +{ + return (label[0] == 'L') || (label[0] == 'l'); +} + + template Atom* CStringSection::findAtomByAddress(pint_t addr) { @@ -4437,25 +5018,20 @@ ld::Fixup::Kind NonLazyPointerSection::fixupKind() } template <> -ld::Fixup::Kind NonLazyPointerSection::fixupKind() +ld::Fixup::Kind NonLazyPointerSection::fixupKind() { - return ld::Fixup::kindStoreBigEndian32; + return ld::Fixup::kindStoreLittleEndian64; } -template <> -ld::Fixup::Kind NonLazyPointerSection::fixupKind() -{ - return ld::Fixup::kindStoreBigEndian64; -} template <> -void NonLazyPointerSection::makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&) +void NonLazyPointerSection::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) { assert(0 && "x86_64 should not have non-lazy-pointer sections in .o files"); } template -void NonLazyPointerSection::makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&) +void NonLazyPointerSection::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) { // add references for each NLP atom based on indirect symbol table const macho_section

* sect = this->machoSection(); @@ -4838,12 +5414,16 @@ const char* PointerToCStringSection::targetCString(const class Atom* atom, case ld::Fixup::bindingsIndirectlyBound: targetAtom = ind.indirectAtom(fit->u.bindingIndex); break; + case ld::Fixup::bindingDirectlyBound: + targetAtom = fit->u.target; + break; default: - assert(0); + assert(0 && "unsupported reference to selector"); } assert(targetAtom != NULL); const Atom* target = dynamic_cast*>(targetAtom); - assert(target != NULL); + assert(target != NULL); + assert(target->contentType() == ld::Atom::typeCString); return (char*)target->contentPointer(); } @@ -5192,7 +5772,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati const macho_nlist

& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum()); target.name = parser.nameFromSymbol(targetSymbol); target.weakImport = parser.weakImportFromSymbol(targetSymbol); - target.addend = contentValue; + target.addend = (int32_t)contentValue; } else { parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target); @@ -5247,6 +5827,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; srcAddr = sect->addr() + sreloc->r_address(); src.atom = this->findAtomByAddress(srcAddr); + assert(src.atom != NULL); src.offsetInAtom = srcAddr - src.atom->_objAddress; fixUpPtr = file().fileContent() + sect->offset() + sreloc->r_address(); uint32_t relocValue = sreloc->r_value(); @@ -5279,17 +5860,17 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati switch ( sreloc->r_length() ) { case 0: contentValue = srcAddr + 1 + *fixUpPtr; - target.addend = contentValue - relocValue; + target.addend = (int32_t)contentValue - (int32_t)relocValue; parser.addFixups(src, ld::Fixup::kindStoreX86PCRel8, target); break; case 1: contentValue = srcAddr + 2 + LittleEndian::get16(*((uint16_t*)fixUpPtr)); - target.addend = contentValue - relocValue; + target.addend = (int32_t)contentValue - (int32_t)relocValue; parser.addFixups(src, ld::Fixup::kindStoreX86PCRel16, target); break; case 2: contentValue = srcAddr + 4 + LittleEndian::get32(*((uint32_t*)fixUpPtr)); - target.addend = contentValue - relocValue; + target.addend = (int32_t)contentValue - (int32_t)relocValue; parser.addFixups(src, ld::Fixup::kindStoreX86PCRel32, target); break; case 3: @@ -5301,7 +5882,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati if ( sreloc->r_length() != 2 ) throwf("unsupported r_length=%d for scattered vanilla reloc", sreloc->r_length()); contentValue = LittleEndian::get32(*((uint32_t*)fixUpPtr)); - target.addend = contentValue - target.atom->objectAddress(); + target.addend = (int32_t)contentValue - (int32_t)(target.atom->objectAddress()); parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target); } break; @@ -5327,7 +5908,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress; parser.findTargetFromAddress(sreloc->r_value(), target); // check for addend encoded in the section content - int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue); + int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue); if ( addend < 0 ) { // switch binding base on coalescing if ( target.atom == NULL ) { @@ -5375,12 +5956,11 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati -// -// ppc and ppc64 both use the same relocations, so process them in one common routine -// -template -bool Section::addRelocFixup_powerpc(class Parser& parser, - const macho_relocation_info* reloc) + + +#if SUPPORT_ARCH_arm_any +template <> +bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) { const macho_section

* sect = this->machoSection(); bool result = false; @@ -5389,33 +5969,48 @@ bool Section::addRelocFixup_powerpc(class Parser& parser, uint32_t* fixUpPtr; int32_t displacement = 0; uint32_t instruction = 0; - int16_t lowBits; pint_t contentValue = 0; - typename Parser::SourceLocation src; - typename Parser::TargetDesc target; + Parser::SourceLocation src; + Parser::TargetDesc target; + const macho_relocation_info

* nextReloc; if ( (reloc->r_address() & R_SCATTERED) == 0 ) { + bool externSymbolIsThumbDef = false; srcAddr = sect->addr() + reloc->r_address(); src.atom = this->findAtomByAddress(srcAddr); src.offsetInAtom = srcAddr - src.atom->_objAddress; - const macho_relocation_info

* nextReloc = &reloc[1]; fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address()); - if ( reloc->r_type() != PPC_RELOC_PAIR ) - instruction = BigEndian::get32(*fixUpPtr); + if ( reloc->r_type() != ARM_RELOC_PAIR ) + instruction = LittleEndian::get32(*fixUpPtr); if ( reloc->r_extern() ) { - target.atom = NULL; const macho_nlist

& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum()); - target.name = parser.nameFromSymbol(targetSymbol); - target.weakImport = parser.weakImportFromSymbol(targetSymbol); + // use direct reference for local symbols + if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (((targetSymbol.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(targetSymbol)[0] == 'L')) ) { + parser.findTargetFromAddressAndSectionNum(targetSymbol.n_value(), targetSymbol.n_sect(), target); + } + else { + target.atom = NULL; + target.name = parser.nameFromSymbol(targetSymbol); + target.weakImport = parser.weakImportFromSymbol(targetSymbol); + if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (targetSymbol.n_desc() & N_ARM_THUMB_DEF) ) + externSymbolIsThumbDef = true; + } } switch ( reloc->r_type() ) { - case PPC_RELOC_BR24: - assert((instruction & 0x4C000000) == 0x48000000); - displacement = (instruction & 0x03FFFFFC); + case ARM_RELOC_BR24: + // Sign-extend displacement + displacement = (instruction & 0x00FFFFFF) << 2; if ( (displacement & 0x02000000) != 0 ) displacement |= 0xFC000000; + // The pc added will be +8 from the pc + displacement += 8; + // If this is BLX add H << 1 + if ((instruction & 0xFE000000) == 0xFA000000) + displacement += ((instruction & 0x01000000) >> 23); if ( reloc->r_extern() ) { target.addend = srcAddr + displacement; + if ( externSymbolIsThumbDef ) + target.addend &= -2; // remove thumb bit } else { dstAddr = srcAddr + displacement; @@ -5424,446 +6019,39 @@ bool Section::addRelocFixup_powerpc(class Parser& parser, // special case "calls" for dtrace if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) { parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStorePPCDtraceCallSiteNop, false, target.name); + ld::Fixup::kindStoreARMDtraceCallSiteNop, false, target.name); parser.addDtraceExtraInfos(src, &target.name[16]); } else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) { parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStorePPCDtraceIsEnableSiteClear, false, target.name); + ld::Fixup::kindStoreARMDtraceIsEnableSiteClear, false, target.name); parser.addDtraceExtraInfos(src, &target.name[20]); } else { - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); + parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target); } break; - case PPC_RELOC_BR14: - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; - } - else { - dstAddr = srcAddr + displacement; - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target); - break; - case PPC_RELOC_PAIR: - // skip, processed by a previous look ahead - break; - case PPC_RELOC_LO16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_LO16 missing following pair"; - result = true; - lowBits = (instruction & 0x0000FFFF); - dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target); - break; - case PPC_RELOC_LO14: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_LO14 missing following pair"; - result = true; - lowBits = (instruction & 0xFFFC); - dstAddr = (nextReloc->r_address() << 16) + ((uint32_t)lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target); - break; - case PPC_RELOC_HI16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_HI16 missing following pair"; - result = true; - lowBits = (nextReloc->r_address() & 0xFFFF); - dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target); - break; - case PPC_RELOC_HA16: - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_HA16 missing following pair"; - result = true; - lowBits = (nextReloc->r_address() & 0x0000FFFF); - dstAddr = ((instruction & 0xFFFF) << 16) + (int32_t)lowBits; - if ( reloc->r_extern() ) { - target.addend = dstAddr; - } - else { - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target); - break; - case PPC_RELOC_VANILLA: - contentValue = P::getP(*((pint_t*)fixUpPtr)); - if ( reloc->r_extern() ) { - target.addend = contentValue; - } - else { - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target); - } - switch ( reloc->r_length() ) { - case 0: - case 1: - throw "bad r_length in PPC_RELOC_VANILLA"; - case 2: - parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target); - break; - case 3: - parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target); - break; - } - break; - case PPC_RELOC_JBSR: - // this is from -mlong-branch codegen. We ignore the jump island and make reference to the real target - if ( nextReloc->r_type() != PPC_RELOC_PAIR ) - throw "PPC_RELOC_JBSR missing following pair"; - if ( !parser._hasLongBranchStubs ) - warning("object file compiled with -mlong-branch which is no longer needed. " - "To remove this warning, recompile without -mlong-branch: %s", parser._path); - parser._hasLongBranchStubs = true; - result = true; - if ( reloc->r_extern() ) { - throw "PPC_RELOC_JBSR should not be using an external relocation"; - } - parser.findTargetFromAddressAndSectionNum(nextReloc->r_address(), reloc->r_symbolnum(), target); - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); - break; - default: - warning("unknown relocation type %d", reloc->r_type()); - } - } - else { - const macho_scattered_relocation_info

* sreloc = (macho_scattered_relocation_info

*)reloc; - // file format allows pair to be scattered or not - const macho_scattered_relocation_info

* nextSReloc = &sreloc[1]; - const macho_relocation_info

* nextReloc = &reloc[1]; - srcAddr = sect->addr() + sreloc->r_address(); - dstAddr = sreloc->r_value(); - fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + sreloc->r_address()); - instruction = BigEndian::get32(*fixUpPtr); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->_objAddress; - typename Parser::TargetDesc picBase; - bool nextRelocIsPair = false; - uint32_t nextRelocAddress = 0; - uint32_t nextRelocValue = 0; - if ( (nextReloc->r_address() & R_SCATTERED) == 0 ) { - if ( nextReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextReloc->r_address(); - result = true; - } - } - else { - if ( nextSReloc->r_type() == PPC_RELOC_PAIR ) { - nextRelocIsPair = true; - nextRelocAddress = nextSReloc->r_address(); - nextRelocValue = nextSReloc->r_value(); - result = true; - } - } - switch ( sreloc->r_type() ) { - case PPC_RELOC_VANILLA: - // with a scattered relocation we get both the target (sreloc->r_value()) and the target+offset (*fixUpPtr) - target.atom = parser.findAtomByAddress(sreloc->r_value()); - switch ( sreloc->r_length() ) { - case 0: - case 1: - throw "unsuppored r_length < 2 for scattered PPC_RELOC_VANILLA"; - case 2: - contentValue = BigEndian::get32(*(uint32_t*)fixUpPtr); - target.addend = contentValue - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStoreBigEndian32, target); - break; - case 3: - contentValue = BigEndian::get64(*(uint64_t*)fixUpPtr); - target.addend = contentValue - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStoreBigEndian64, target); - break; - } - break; - case PPC_RELOC_BR14: - displacement = (instruction & 0x0000FFFC); - if ( (displacement & 0x00008000) != 0 ) - displacement |= 0xFFFF0000; - target.atom = parser.findAtomByAddress(sreloc->r_value()); - target.addend = (srcAddr + displacement) - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStorePPCBranch14, target); - break; - case PPC_RELOC_BR24: - assert((instruction & 0x4C000000) == 0x48000000); - displacement = (instruction & 0x03FFFFFC); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - target.atom = parser.findAtomByAddress(sreloc->r_value()); - target.addend = (srcAddr + displacement) - target.atom->_objAddress; - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, target); - break; - case PPC_RELOC_LO16_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO16_SECTDIFF missing following pair"; - lowBits = (instruction & 0xFFFF); - dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicLow16, target, picBase); - break; - case PPC_RELOC_LO14_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO14_SECTDIFF missing following pair"; - lowBits = (instruction & 0xFFFC); - dstAddr = nextRelocValue + ((nextRelocAddress << 16) | ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicLow14, target, picBase); - break; - case PPC_RELOC_HA16_SECTDIFF: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HA16_SECTDIFF missing following pair"; - lowBits = (nextRelocAddress & 0x0000FFFF); - dstAddr = nextRelocValue + (((instruction & 0x0000FFFF) << 16) + (int32_t)lowBits); - parser.findTargetFromAddress(sreloc->r_value(), target); - if ( target.atom != NULL ) - target.addend = dstAddr - target.atom->_objAddress; - picBase.atom = parser.findAtomByAddress(nextRelocValue); - picBase.addend = nextRelocValue - picBase.atom->_objAddress; - picBase.weakImport = false; - picBase.name = NULL; - parser.addFixups(src, ld::Fixup::kindStorePPCPicHigh16AddLow, target, picBase); - break; - case PPC_RELOC_LO14: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO14 missing following pair"; - lowBits = (instruction & 0xFFFC); - dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow14, target); - break; - case PPC_RELOC_LO16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_LO16 missing following pair"; - lowBits = (instruction & 0xFFFF); - dstAddr = ((nextRelocAddress << 16) + ((uint32_t)lowBits & 0x0000FFFF)); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsLow16, target); - break; - case PPC_RELOC_HA16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HA16 missing following pair"; - lowBits = (nextRelocAddress & 0xFFFF); - dstAddr = (((instruction & 0xFFFF) << 16) + (int32_t)lowBits); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16AddLow, target); - break; - case PPC_RELOC_HI16: - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_HI16 missing following pair"; - lowBits = (nextRelocAddress & 0xFFFF); - dstAddr = ((instruction & 0xFFFF) << 16) | (lowBits & 0x0000FFFF); - parser.findTargetFromAddress(sreloc->r_value(), dstAddr, target); - parser.addFixups(src, ld::Fixup::kindStorePPCAbsHigh16, target); - break; - case PPC_RELOC_SECTDIFF: - case PPC_RELOC_LOCAL_SECTDIFF: - { - if ( ! nextRelocIsPair ) - throw "PPC_RELOC_SECTDIFF missing following pair"; - ld::Fixup::Kind kind = ld::Fixup::kindNone; - switch ( sreloc->r_length() ) { - case 0: - throw "bad length for PPC_RELOC_SECTDIFF"; - case 1: - contentValue = (int32_t)(int16_t)BigEndian::get16(*((uint16_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian16; - break; - case 2: - contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian32; - break; - case 3: - contentValue = BigEndian::get64(*((uint64_t*)fixUpPtr)); - kind = ld::Fixup::kindStoreBigEndian64; - break; - break; - } - Atom* fromAtom = parser.findAtomByAddress(nextRelocValue); - Atom* targetAtom = parser.findAtomByAddress(sreloc->r_value()); - uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress; - uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress; - // check for addend encoded in the section content - int32_t addend = contentValue - (sreloc->r_value() - nextRelocValue); - if ( addend < 0 ) { - if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); - } - else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom); - } - else { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name()); - } - parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget); - parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom); - parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend); - parser.addFixup(src, ld::Fixup::k5of5, kind); - } - else { - if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); - } - else if ( (targetAtom->combine() == ld::Atom::combineByNameAndContent) || (targetAtom->combine() == ld::Atom::combineByNameAndReferences) ) { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, ld::Fixup::bindingByContentBound, targetAtom); - } - else { - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name()); - } - parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget+addend); - parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom); - parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom); - parser.addFixup(src, ld::Fixup::k5of5, kind); - } - } - break; - case PPC_RELOC_PAIR: - break; - case PPC_RELOC_HI16_SECTDIFF: - warning("unexpected scattered relocation type PPC_RELOC_HI16_SECTDIFF"); - break; - default: - warning("unknown scattered relocation type %d", sreloc->r_type()); - } - } - return result; -} - - -template <> -bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) -{ - return addRelocFixup_powerpc(parser, reloc); -} - - -template <> -bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) -{ - return addRelocFixup_powerpc(parser, reloc); -} - - - -template <> -bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) -{ - const macho_section

* sect = this->machoSection(); - bool result = false; - uint32_t srcAddr; - uint32_t dstAddr; - uint32_t* fixUpPtr; - int32_t displacement = 0; - uint32_t instruction = 0; - pint_t contentValue = 0; - Parser::SourceLocation src; - Parser::TargetDesc target; - const macho_relocation_info

* nextReloc; - - if ( (reloc->r_address() & R_SCATTERED) == 0 ) { - bool externSymbolIsThumbDef = false; - srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->_objAddress; - fixUpPtr = (uint32_t*)(file().fileContent() + sect->offset() + reloc->r_address()); - if ( reloc->r_type() != ARM_RELOC_PAIR ) - instruction = LittleEndian::get32(*fixUpPtr); - if ( reloc->r_extern() ) { - target.atom = NULL; - const macho_nlist

& targetSymbol = parser.symbolFromIndex(reloc->r_symbolnum()); - target.name = parser.nameFromSymbol(targetSymbol); - target.weakImport = parser.weakImportFromSymbol(targetSymbol); - if ( ((targetSymbol.n_type() & N_TYPE) == N_SECT) && (targetSymbol.n_desc() & N_ARM_THUMB_DEF) ) - externSymbolIsThumbDef = true; - } - switch ( reloc->r_type() ) { - case ARM_RELOC_BR24: - // Sign-extend displacement - displacement = (instruction & 0x00FFFFFF) << 2; - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - // The pc added will be +8 from the pc - displacement += 8; - // If this is BLX add H << 1 - if ((instruction & 0xFE000000) == 0xFA000000) - displacement += ((instruction & 0x01000000) >> 23); - if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; - if ( externSymbolIsThumbDef ) - target.addend &= -2; // remove thumb bit - } - else { - dstAddr = srcAddr + displacement; - parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); - } - // special case "calls" for dtrace - if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) { - parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStoreARMDtraceCallSiteNop, false, target.name); - parser.addDtraceExtraInfos(src, &target.name[16]); - } - else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) { - parser.addFixup(src, ld::Fixup::k1of1, - ld::Fixup::kindStoreARMDtraceIsEnableSiteClear, false, target.name); - parser.addDtraceExtraInfos(src, &target.name[20]); - } - else { - parser.addFixups(src, ld::Fixup::kindStoreARMBranch24, target); - } - break; - case ARM_THUMB_RELOC_BR22: - // thumb2 added two more bits to displacement, complicating the displacement decoding - { - uint32_t s = (instruction >> 10) & 0x1; - uint32_t j1 = (instruction >> 29) & 0x1; - uint32_t j2 = (instruction >> 27) & 0x1; - uint32_t imm10 = instruction & 0x3FF; - uint32_t imm11 = (instruction >> 16) & 0x7FF; - uint32_t i1 = (j1 == s); - uint32_t i2 = (j2 == s); - uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); - int32_t sdis = dis; - if ( s ) - sdis |= 0xFE000000; - displacement = sdis; + case ARM_THUMB_RELOC_BR22: + // thumb2 added two more bits to displacement, complicating the displacement decoding + { + uint32_t s = (instruction >> 10) & 0x1; + uint32_t j1 = (instruction >> 29) & 0x1; + uint32_t j2 = (instruction >> 27) & 0x1; + uint32_t imm10 = instruction & 0x3FF; + uint32_t imm11 = (instruction >> 16) & 0x7FF; + uint32_t i1 = (j1 == s); + uint32_t i2 = (j2 == s); + uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1); + int32_t sdis = dis; + if ( s ) + sdis |= 0xFE000000; + displacement = sdis; } // The pc added will be +4 from the pc displacement += 4; // If the instruction was blx, force the low 2 bits to be clear dstAddr = srcAddr + displacement; - if ((instruction & 0xF8000000) == 0xE8000000) + if ((instruction & 0xD0000000) == 0xC0000000) dstAddr &= 0xFFFFFFFC; if ( reloc->r_extern() ) { @@ -5892,7 +6080,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati throw "bad length for ARM_RELOC_VANILLA"; contentValue = LittleEndian::get32(*fixUpPtr); if ( reloc->r_extern() ) { - target.addend = contentValue; + target.addend = (int32_t)contentValue; if ( externSymbolIsThumbDef ) target.addend &= -2; // remove thumb bit } @@ -5939,13 +6127,31 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati if ( reloc->r_length() & 1 ) { // high 16 dstAddr = ((instruction16 << 16) | other16); - parser.findTargetFromAddress(dstAddr, target); + if ( reloc->r_extern() ) { + target.addend = dstAddr; + if ( externSymbolIsThumbDef ) + target.addend &= -2; // remove thumb bit + } + else { + parser.findTargetFromAddress(dstAddr, target); + if ( target.atom->isThumb() ) + target.addend &= (-2); // remove thumb bit + } parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbHigh16 : ld::Fixup::kindStoreARMHigh16), target); } else { // low 16 dstAddr = (other16 << 16) | instruction16; - parser.findTargetFromAddress(dstAddr, target); + if ( reloc->r_extern() ) { + target.addend = dstAddr; + if ( externSymbolIsThumbDef ) + target.addend &= -2; // remove thumb bit + } + else { + parser.findTargetFromAddress(dstAddr, target); + if ( target.atom->isThumb() ) + target.addend &= (-2); // remove thumb bit + } parser.addFixups(src, (isThumb ? ld::Fixup::kindStoreThumbLow16 : ld::Fixup::kindStoreARMLow16), target); } result = true; @@ -5993,6 +6199,8 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati if ( sreloc->r_length() != 2 ) throw "bad length for ARM_RELOC_VANILLA"; target.atom = parser.findAtomByAddress(sreloc->r_value()); + if ( target.atom == NULL ) + throwf("bad r_value (0x%08X) for ARM_RELOC_VANILLA\n", sreloc->r_value()); contentValue = LittleEndian::get32(*fixUpPtr); target.addend = contentValue - target.atom->_objAddress; if ( target.atom->isThumb() ) @@ -6052,7 +6260,7 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati uint32_t offsetInTarget; Atom* targetAtom = parser.findAtomByAddressOrLocalTargetOfStub(sreloc->r_value(), &offsetInTarget); // check for addend encoded in the section content - int64_t addend = contentValue - (sreloc->r_value() - nextRelocValue); + int64_t addend = (int32_t)contentValue - (int32_t)(sreloc->r_value() - nextRelocValue); if ( targetAtom->isThumb() ) addend &= -2; // remove thumb bit // if reference to LSDA, add group subordinate fixup @@ -6073,7 +6281,6 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati else { parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, false, targetAtom->name()); } - parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); parser.addFixup(src, ld::Fixup::k2of5, ld::Fixup::kindAddAddend, offsetInTarget); parser.addFixup(src, ld::Fixup::k3of5, ld::Fixup::kindSubtractTargetAddress, fromAtom); parser.addFixup(src, ld::Fixup::k4of5, ld::Fixup::kindSubtractAddend, offsetInFrom-addend); @@ -6103,8 +6310,6 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati uint32_t offsetInFrom = nextRelocValue - fromAtom->_objAddress; Atom* targetAtom = parser.findAtomByAddress(sreloc->r_value()); uint32_t offsetInTarget = sreloc->r_value() - targetAtom->_objAddress; - //if ( targetAtom->isThumb() ) - // addend &= -2; // remove thumb bit uint32_t instruction16; uint32_t other16 = (nextRelocAddress & 0xFFFF); bool isThumb; @@ -6126,6 +6331,8 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati dstAddr = ((instruction16 << 16) | other16); else dstAddr = (other16 << 16) | instruction16; + if ( targetAtom->isThumb() ) + dstAddr &= (-2); // remove thumb bit int32_t addend = dstAddr - (sreloc->r_value() - nextRelocValue); if ( targetAtom->scope() == ld::Atom::scopeTranslationUnit ) { parser.addFixup(src, ld::Fixup::k1of5, ld::Fixup::kindSetTargetAddress, targetAtom); @@ -6206,10 +6413,317 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati } return result; } +#endif - - +#if SUPPORT_ARCH_arm64 +template <> +bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) +{ + bool result = false; + Parser::SourceLocation src; + Parser::TargetDesc target = { NULL, NULL, false, 0 }; + Parser::TargetDesc toTarget; + int32_t prefixRelocAddend = 0; + if ( reloc->r_type() == ARM64_RELOC_ADDEND ) { + uint32_t rawAddend = reloc->r_symbolnum(); + prefixRelocAddend = rawAddend; + if ( rawAddend & 0x00800000 ) + prefixRelocAddend |= 0xFF000000; // sign extend 24-bit signed int to 32-bits + uint32_t addendAddress = reloc->r_address(); + ++reloc; //advance to next reloc record + result = true; + if ( reloc->r_address() != addendAddress ) + throw "ARM64_RELOC_ADDEND r_address does not match next reloc's r_address"; + } + const macho_section

* sect = this->machoSection(); + uint64_t srcAddr = sect->addr() + reloc->r_address(); + src.atom = this->findAtomByAddress(srcAddr); + src.offsetInAtom = srcAddr - src.atom->_objAddress; + const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); + uint64_t contentValue = 0; + const macho_relocation_info* nextReloc = &reloc[1]; + bool useDirectBinding; + uint32_t instruction; + uint32_t encodedAddend; + switch ( reloc->r_length() ) { + case 0: + contentValue = *fixUpPtr; + break; + case 1: + contentValue = (int64_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr)); + break; + case 2: + contentValue = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr)); + break; + case 3: + contentValue = E::get64(*((uint64_t*)fixUpPtr)); + break; + } + if ( reloc->r_extern() ) { + const macho_nlist

& sym = parser.symbolFromIndex(reloc->r_symbolnum()); + const char* symbolName = parser.nameFromSymbol(sym); + if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (symbolName[0] == 'L') || (symbolName[0] == 'l')) ) { + // use direct reference for local symbols + parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target); + //target.addend += contentValue; + } + else if ( ((sym.n_type() & N_TYPE) == N_SECT) && (src.atom->_objAddress <= sym.n_value()) && (sym.n_value() < (src.atom->_objAddress+src.atom->size())) ) { + // spurious warning when weak function has reference to itself + // use direct reference when atom targets itself + target.atom = src.atom; + target.name = NULL; + } + else { + target.name = symbolName; + target.weakImport = parser.weakImportFromSymbol(sym); + //target.addend = contentValue; + } + // cfstrings should always use direct reference to backing store + if ( (this->type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) { + parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target); + //target.addend = contentValue; + } + } + else { + if ( reloc->r_pcrel() ) + contentValue += srcAddr; + parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target); + } + switch ( reloc->r_type() ) { + case ARM64_RELOC_UNSIGNED: + if ( reloc->r_pcrel() ) + throw "pcrel and ARM64_RELOC_UNSIGNED not supported"; + target.addend = contentValue; + switch ( reloc->r_length() ) { + case 0: + case 1: + throw "length < 2 and ARM64_RELOC_UNSIGNED not supported"; + case 2: + parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target); + break; + case 3: + parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target); + break; + } + break; + case ARM64_RELOC_BRANCH26: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and ARM64_RELOC_BRANCH26 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_BRANCH26 not supported"; + if ( reloc->r_length() != 2 ) + throw "r_length != 2 and ARM64_RELOC_BRANCH26 not supported"; + if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) { + parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceCallSiteNop, false, target.name); + parser.addDtraceExtraInfos(src, &target.name[16]); + } + else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) { + parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear, false, target.name); + parser.addDtraceExtraInfos(src, &target.name[20]); + } + else { + target.addend = prefixRelocAddend; + instruction = contentValue; + encodedAddend = (instruction & 0x03FFFFFF) << 2; + if ( encodedAddend != 0 ) { + if ( prefixRelocAddend == 0 ) { + warning("branch26 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address()); + target.addend = encodedAddend; + } + else { + throwf("branch26 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address()); + } + } + parser.addFixups(src, ld::Fixup::kindStoreARM64Branch26, target); + } + break; + case ARM64_RELOC_PAGE21: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and ARM64_RELOC_PAGE21 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_PAGE21 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_PAGE21 not supported"; + target.addend = prefixRelocAddend; + instruction = contentValue; + encodedAddend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3); + encodedAddend *= 4096; // internally addend is in bytes, so scale + if ( encodedAddend != 0 ) { + if ( prefixRelocAddend == 0 ) { + warning("adrp instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address()); + target.addend = encodedAddend; + } + else { + throwf("adrp instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address()); + } + } + parser.addFixups(src, ld::Fixup::kindStoreARM64Page21, target); + break; + case ARM64_RELOC_PAGEOFF12: + if ( reloc->r_pcrel() ) + throw "pcrel and ARM64_RELOC_PAGEOFF12 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_PAGEOFF12 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_PAGEOFF12 not supported"; + target.addend = prefixRelocAddend; + instruction = contentValue; + encodedAddend = ((instruction & 0x003FFC00) >> 10); + // internally addend is in bytes. Some instructions have an implicit scale factor + if ( (instruction & 0x3B000000) == 0x39000000 ) { + switch ( instruction & 0xC0000000 ) { + case 0x00000000: + break; + case 0x40000000: + encodedAddend *= 2; + break; + case 0x80000000: + encodedAddend *= 4; + break; + case 0xC0000000: + encodedAddend *= 8; + break; + } + } + if ( encodedAddend != 0 ) { + if ( prefixRelocAddend == 0 ) { + warning("pageoff12 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address()); + target.addend = encodedAddend; + } + else { + throwf("pageoff12 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address()); + } + } + parser.addFixups(src, ld::Fixup::kindStoreARM64PageOff12, target); + break; + case ARM64_RELOC_GOT_LOAD_PAGE21: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and ARM64_RELOC_GOT_LOAD_PAGE21 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGE21 not supported"; + instruction = contentValue; + target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3); + if ( target.addend != 0 ) + throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported"; + parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPage21, target); + break; + case ARM64_RELOC_GOT_LOAD_PAGEOFF12: + if ( reloc->r_pcrel() ) + throw "pcrel and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported"; + instruction = contentValue; + target.addend = ((instruction & 0x003FFC00) >> 10); + parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPageOff12, target); + break; + case ARM64_RELOC_TLVP_LOAD_PAGE21: + if ( ! reloc->r_pcrel() ) + throw "not pcrel and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGE21 not supported"; + instruction = contentValue; + target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3); + if ( target.addend != 0 ) + throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported"; + parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPage21, target); + break; + case ARM64_RELOC_TLVP_LOAD_PAGEOFF12: + if ( reloc->r_pcrel() ) + throw "pcrel and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported"; + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported"; + if ( reloc->r_length() != 2 ) + throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported"; + instruction = contentValue; + target.addend = ((instruction & 0x003FFC00) >> 10); + parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPageOff12, target); + break; + case ARM64_RELOC_SUBTRACTOR: + if ( reloc->r_pcrel() ) + throw "ARM64_RELOC_SUBTRACTOR cannot be pc-relative"; + if ( reloc->r_length() < 2 ) + throw "ARM64_RELOC_SUBTRACTOR must have r_length of 2 or 3"; + if ( !reloc->r_extern() ) + throw "ARM64_RELOC_SUBTRACTOR must have r_extern=1"; + if ( nextReloc->r_type() != ARM64_RELOC_UNSIGNED ) + throw "ARM64_RELOC_SUBTRACTOR must be followed by ARM64_RELOC_UNSIGNED"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_SUBTRACTOR not supported"; + result = true; + if ( nextReloc->r_pcrel() ) + throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR cannot be pc-relative"; + if ( nextReloc->r_length() != reloc->r_length() ) + throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR must have same r_length"; + if ( nextReloc->r_extern() ) { + const macho_nlist

& sym = parser.symbolFromIndex(nextReloc->r_symbolnum()); + // use direct reference for local symbols + if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) { + parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), toTarget); + toTarget.addend = contentValue; + useDirectBinding = true; + } + else { + toTarget.name = parser.nameFromSymbol(sym); + toTarget.weakImport = parser.weakImportFromSymbol(sym); + toTarget.addend = contentValue; + useDirectBinding = false; + } + } + else { + parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget); + useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit); + } + 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); + if ( target.atom == NULL ) + parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, false, target.name); + else + parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, target.atom); + if ( reloc->r_length() == 2 ) + parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32); + else + parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian64); + break; + case ARM64_RELOC_POINTER_TO_GOT: + if ( ! reloc->r_extern() ) + throw "r_extern == 0 and ARM64_RELOC_POINTER_TO_GOT not supported"; + if ( prefixRelocAddend != 0 ) + throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_POINTER_TO_GOT not supported"; + if ( reloc->r_pcrel() ) { + if ( reloc->r_length() != 2 ) + throw "r_length != 2 and r_extern = 1 and ARM64_RELOC_POINTER_TO_GOT not supported"; + parser.addFixups(src, ld::Fixup::kindStoreARM64PCRelToGOT, target); + } + else { + if ( reloc->r_length() != 3 ) + throw "r_length != 3 and r_extern = 0 and ARM64_RELOC_POINTER_TO_GOT not supported"; + parser.addFixups(src, ld::Fixup::kindStoreARM64PointerToGOT, target); + } + break; + default: + throwf("unknown relocation type %d", reloc->r_type()); + } + return result; +} +#endif template bool ObjC1ClassSection::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) @@ -6254,41 +6768,6 @@ bool ObjC1ClassSection::addRelocFixup(class Parser& parser, const mach return FixedSizeSection::addRelocFixup(parser, reloc); } -template <> -bool ObjC1ClassSection::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) -{ - // if this is the reloc for the super class name string, add implicit reference to super class - if ( ((reloc->r_address() & R_SCATTERED) == 0) && (reloc->r_type() == PPC_RELOC_VANILLA) ) { - assert( reloc->r_length() == 2 ); - assert( ! reloc->r_pcrel() ); - - const macho_section

* sect = this->machoSection(); - Parser::SourceLocation src; - uint32_t srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->objectAddress(); - if ( src.offsetInAtom == 4 ) { - Parser::TargetDesc stringTarget; - const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); - uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget); - - assert(stringTarget.atom != NULL); - assert(stringTarget.atom->contentType() == ld::Atom::typeCString); - const char* superClassBaseName = (char*)stringTarget.atom->rawContentPointer(); - char* superClassName = new char[strlen(superClassBaseName) + 20]; - strcpy(superClassName, ".objc_class_name_"); - strcat(superClassName, superClassBaseName); - - parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, superClassName); - } - } - - // inherited - return FixedSizeSection::addRelocFixup(parser, reloc); -} - - template @@ -6302,38 +6781,6 @@ bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho } -template <> -bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) -{ - // add implict class refs, fixups not usable yet, so look at relocations - assert( (reloc->r_address() & R_SCATTERED) == 0 ); - assert( reloc->r_type() == PPC_RELOC_VANILLA ); - assert( reloc->r_length() == 2 ); - assert( ! reloc->r_pcrel() ); - - const macho_section

* sect = this->machoSection(); - Parser::SourceLocation src; - uint32_t srcAddr = sect->addr() + reloc->r_address(); - src.atom = this->findAtomByAddress(srcAddr); - src.offsetInAtom = srcAddr - src.atom->objectAddress(); - Parser::TargetDesc stringTarget; - const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address(); - uint32_t contentValue = BigEndian::get32(*((uint32_t*)fixUpPtr)); - parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), stringTarget); - - assert(stringTarget.atom != NULL); - assert(stringTarget.atom->contentType() == ld::Atom::typeCString); - const char* baseClassName = (char*)stringTarget.atom->rawContentPointer(); - char* objcClassName = new char[strlen(baseClassName) + 20]; - strcpy(objcClassName, ".objc_class_name_"); - strcat(objcClassName, baseClassName); - - parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindSetTargetAddress, false, objcClassName); - - // inherited - return PointerToCStringSection::addRelocFixup(parser, reloc); -} - template <> bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const macho_relocation_info* reloc) @@ -6369,7 +6816,7 @@ bool Objc1ClassReferences::addRelocFixup(class Parser& parser, const m template -void Section::makeFixups(class Parser& parser, const struct Parser::CFIInfoArray&) +void Section::makeFixups(class Parser& parser, const struct Parser::CFI_CU_InfoArrays&) { const macho_section

* sect = this->machoSection(); const macho_relocation_info

* relocs = (macho_relocation_info

*)(file().fileContent() + sect->reloff()); @@ -6380,7 +6827,7 @@ void Section::makeFixups(class Parser& parser, const struct Parser::CFI ++r; // skip next } catch (const char* msg) { - throwf("in section %s,%s reloc %u: %s", sect->segname(), sect->sectname(), r, msg); + throwf("in section %s,%s reloc %u: %s", sect->segname(), Section::makeSectionName(sect), r, msg); } } @@ -6405,6 +6852,84 @@ void Section::makeFixups(class Parser& parser, const struct Parser::CFI } } + // track data-in-code + if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) { + for (uint32_t i=0; i < parser.symbolCount(); ++i) { + const macho_nlist

& sym = parser.symbolFromIndex(i); + // ignore stabs + if ( (sym.n_type() & N_STAB) != 0 ) + continue; + // ignore non-definitions + if ( (sym.n_type() & N_TYPE) != N_SECT ) + continue; + + // 'L' labels do not denote atom breaks + const char* symbolName = parser.nameFromSymbol(sym); + if ( symbolName[0] == 'L' ) { + if ( strncmp(symbolName, "L$start$", 8) == 0 ) { + ld::Fixup::Kind kind = ld::Fixup::kindNone; + if ( strncmp(&symbolName[8], "data$", 5) == 0 ) + kind = ld::Fixup::kindDataInCodeStartData; + else if ( strncmp(&symbolName[8], "code$", 5) == 0 ) + kind = ld::Fixup::kindDataInCodeEnd; + else if ( strncmp(&symbolName[8], "jt8$", 4) == 0 ) + kind = ld::Fixup::kindDataInCodeStartJT8; + else if ( strncmp(&symbolName[8], "jt16$", 4) == 0 ) + kind = ld::Fixup::kindDataInCodeStartJT16; + else if ( strncmp(&symbolName[8], "jt32$", 4) == 0 ) + kind = ld::Fixup::kindDataInCodeStartJT32; + else if ( strncmp(&symbolName[8], "jta32$", 4) == 0 ) + kind = ld::Fixup::kindDataInCodeStartJTA32; + else + warning("unknown L$start$ label %s in file %s", symbolName, this->file().path()); + if ( kind != ld::Fixup::kindNone ) { + Atom* inAtom = parser.findAtomByAddress(sym.n_value()); + typename Parser::SourceLocation src(inAtom, sym.n_value() - inAtom->objectAddress()); + parser.addFixup(src, ld::Fixup::k1of1, kind); + } + } + } + } + } + + // Handle LC_DATA_IN_CODE in object files + if ( this->type() == ld::Section::typeCode ) { + const pint_t startAddr = this->_machOSection->addr(); + const pint_t endAddr = startAddr + this->_machOSection->size(); + for ( const macho_data_in_code_entry

* p = parser.dataInCodeStart(); p != parser.dataInCodeEnd(); ++p ) { + if ( (p->offset() >= startAddr) && (p->offset() < endAddr) ) { + ld::Fixup::Kind kind = ld::Fixup::kindNone; + switch ( p->kind() ) { + case DICE_KIND_DATA: + kind = ld::Fixup::kindDataInCodeStartData; + break; + case DICE_KIND_JUMP_TABLE8: + kind = ld::Fixup::kindDataInCodeStartJT8; + break; + case DICE_KIND_JUMP_TABLE16: + kind = ld::Fixup::kindDataInCodeStartJT16; + break; + case DICE_KIND_JUMP_TABLE32: + kind = ld::Fixup::kindDataInCodeStartJT32; + break; + case DICE_KIND_ABS_JUMP_TABLE32: + kind = ld::Fixup::kindDataInCodeStartJTA32; + break; + default: + kind = ld::Fixup::kindDataInCodeStartData; + warning("uknown LC_DATA_IN_CODE kind (%d) at offset 0x%08X", p->kind(), p->offset()); + break; + } + Atom* inAtom = parser.findAtomByAddress(p->offset()); + typename Parser::SourceLocation srcStart(inAtom, p->offset() - inAtom->objectAddress()); + parser.addFixup(srcStart, ld::Fixup::k1of1, kind); + typename Parser::SourceLocation srcEnd(inAtom, p->offset() + p->length() - inAtom->objectAddress()); + parser.addFixup(srcEnd, ld::Fixup::k1of1, ld::Fixup::kindDataInCodeEnd); + } + } + } + + // add follow-on fixups for aliases if ( _hasAliases ) { for(Atom* p = _beginAtoms; p < _endAtoms; ++p) { @@ -6425,29 +6950,33 @@ void Section::makeFixups(class Parser& parser, const struct Parser::CFI // main function used by linker to instantiate ld::Files // ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, - const char* path, time_t modTime, uint32_t ordinal, const ParserOptions& opts) + const char* path, time_t modTime, ld::File::Ordinal ordinal, const ParserOptions& opts) { switch ( opts.architecture ) { +#if SUPPORT_ARCH_x86_64 case CPU_TYPE_X86_64: if ( mach_o::relocatable::Parser::validFile(fileContent) ) return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; +#endif +#if SUPPORT_ARCH_i386 case CPU_TYPE_I386: if ( mach_o::relocatable::Parser::validFile(fileContent) ) return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; +#endif +#if SUPPORT_ARCH_arm_any case CPU_TYPE_ARM: if ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ) return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; - case CPU_TYPE_POWERPC: - if ( mach_o::relocatable::Parser::validFile(fileContent) ) - return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); - break; - case CPU_TYPE_POWERPC64: - if ( mach_o::relocatable::Parser::validFile(fileContent) ) - return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); +#endif +#if SUPPORT_ARCH_arm64 + case CPU_TYPE_ARM64: + if ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ) + return mach_o::relocatable::Parser::parse(fileContent, fileLength, path, modTime, ordinal, opts); break; +#endif } return NULL; } @@ -6464,10 +6993,8 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserO return ( mach_o::relocatable::Parser::validFile(fileContent) ); case CPU_TYPE_ARM: return ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ); - case CPU_TYPE_POWERPC: - return ( mach_o::relocatable::Parser::validFile(fileContent) ); - case CPU_TYPE_POWERPC64: - return ( mach_o::relocatable::Parser::validFile(fileContent) ); + case CPU_TYPE_ARM64: + return ( mach_o::relocatable::Parser::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) ); } return false; } @@ -6493,15 +7020,9 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* *subResult = header->cpusubtype(); return true; } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - *result = CPU_TYPE_POWERPC; - const macho_header >* header = (const macho_header >*)fileContent; - *subResult = header->cpusubtype(); - return true; - } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - *result = CPU_TYPE_POWERPC64; - *subResult = CPU_SUBTYPE_POWERPC_ALL; + if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { + *result = CPU_TYPE_ARM64; + *subResult = CPU_SUBTYPE_ARM64_ALL; return true; } return false; @@ -6521,12 +7042,6 @@ const char* archName(const uint8_t* fileContent) if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { return mach_o::relocatable::Parser::fileKind(fileContent); } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - return mach_o::relocatable::Parser::fileKind(fileContent); - } - if ( mach_o::relocatable::Parser::validFile(fileContent) ) { - return mach_o::relocatable::Parser::fileKind(fileContent); - } return NULL; } @@ -6541,9 +7056,28 @@ bool hasObjC2Categories(const uint8_t* fileContent) else if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { return mach_o::relocatable::Parser::hasObjC2Categories(fileContent); } + else if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { + return mach_o::relocatable::Parser::hasObjC2Categories(fileContent); + } +#if SUPPORT_ARCH_arm64 + else if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { + return mach_o::relocatable::Parser::hasObjC2Categories(fileContent); + } +#endif return false; } +// +// Used by archive reader when -ObjC option is specified +// +bool hasObjC1Categories(const uint8_t* fileContent) +{ + if ( mach_o::relocatable::Parser::validFile(fileContent, false, 0) ) { + return mach_o::relocatable::Parser::hasObjC1Categories(fileContent); + } + return false; +} + } // namespace relocatable