X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c:/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..e79d261 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,6 +64,7 @@ template class Parser; template class Atom; template class Section; template class CFISection; +template class CUSection; template class File : public ld::relocatable::File @@ -147,15 +148,16 @@ 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; } + 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; } @@ -248,6 +248,46 @@ 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[]); + + +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 +299,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 +323,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 +344,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,8 +374,8 @@ 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; @@ -437,7 +477,7 @@ 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"; } @@ -598,6 +638,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); virtual bool useElementAt(Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, pint_t addr); virtual ld::Atom::Combine combine(Parser&, pint_t) { return ld::Atom::combineByNameAndContent; } @@ -668,6 +709,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) { @@ -792,8 +842,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()); } } @@ -951,14 +1001,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 +1021,8 @@ private: sectionTypeNonLazy, sectionTypeCFI, sectionTypeCString, sectionTypeCStringPointer, sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList, sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs, - sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs }; + sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs, + sectionTypeCompactUnwind }; template struct MachOSectionAndSectionClass @@ -986,6 +1042,9 @@ 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, @@ -994,11 +1053,13 @@ private: 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); @@ -1032,9 +1093,8 @@ private: // 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; @@ -1059,8 +1119,7 @@ Parser::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p _indirectTable(NULL), _indirectTableCount(0), _undefinedStartIndex(0), _undefinedEndIndex(0), _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), - _EHFrameSection(NULL), _absoluteSection(NULL), - _lsdaTextSectionNum(0), _lsdaDataSectionNum(0), + _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL), _tentativeDefinitionCount(0), _absoluteSymbolCount(0), _symbolsInSections(0), _hasLongBranchStubs(false), _AppleObjc(false), _overlappingSymbols(false), _convertUnwindInfo(convertDUI), @@ -1068,31 +1127,6 @@ Parser::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p { } -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) @@ -1142,39 +1176,6 @@ bool Parser::validFile(const uint8_t* fileContent, bool subtypeMustMatch, c } -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_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???"; -} - -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,17 +1207,10 @@ 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 ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) { + if ( t->subType == (cpu_subtype_t)header->cpusubtype() ) { + return t->subTypeName; + } } return "arm???"; } @@ -1302,7 +1296,8 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, uint32_t sectN while ( symIndex < sortedSymbolCount ) { const macho_nlist

& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]); pint_t nextSymbolAddr = sym.n_value(); - if ( (nextSymbolAddr >= startAddr) && (sym.n_sect() >= sectNum) ) + //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; } @@ -1444,16 +1439,28 @@ 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 + // if it exists, do special early parsing of __compact_unwind section + uint32_t countOfCUs = 0; + if ( _compactUnwindSection != NULL ) + countOfCUs = _compactUnwindSection->count(); + uint8_t cuInfoBuffer[sizeof(typename CUSection::Info) * countOfCUs]; + typename CUSection::Info* cuInfoArray = (typename CUSection::Info*)cuInfoBuffer; + if ( countOfCUs != 0 ) + _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray); + + // if it exists, do special early parsing of __eh_frame section // stack allocate array of CFI_Atom_Info uint32_t countOfCFIs = 0; if ( _EHFrameSection != NULL ) @@ -1489,7 +1496,7 @@ 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]; @@ -1539,7 +1546,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) 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 +1581,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; @@ -1587,7 +1594,33 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1); } } - + // 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); + // 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,8 +1629,6 @@ 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; } @@ -1686,31 +1717,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() @@ -1766,12 +1772,6 @@ void Parser::prescanSymbolTable() 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"; @@ -1781,11 +1781,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 +1850,15 @@ 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 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 ) @@ -1812,9 +1875,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 +1897,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 +1907,8 @@ 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; @@ -1858,9 +1919,11 @@ void Parser::makeSortedSymbolsArray(uint32_t array[]) } } - //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])) ); + } } @@ -1876,21 +1939,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) ) @@ -1918,11 +1990,11 @@ void Parser::makeSections() _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 +2173,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); @@ -2386,9 +2463,6 @@ 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; - break; default: combined = false; cl = ld::Fixup::k1of2; @@ -2462,7 +2536,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 +2544,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 +2563,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 +2582,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 +2590,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; @@ -3488,6 +3562,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 +3643,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; } @@ -3689,32 +3763,7 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, } -// 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) -{ - // 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 - assert(count == 0); -} template <> void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, @@ -3730,9 +3779,9 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, 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 +3789,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 +3804,13 @@ 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 <> @@ -3813,30 +3860,6 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, const C } -template <> -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); - - 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); - } - else if ( personalityEncoding != 0 ) { - throwf("unsupported address encoding (%02X) of personality function in CIE", - personalityEncoding); - } -} - - template void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) { @@ -3845,14 +3868,14 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_A } 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 +4095,136 @@ 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) +{ + assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section"); + 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); +} + +template <> +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info* reloc) +{ + assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section"); + 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); +} + +template +const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info

* reloc) +{ + return NULL; +} + + +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, local relocs are useless - ignore them + // 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(); + } + else { + warning("unexpected extern relocation in __compact_unwind section"); + } + } + } + + // 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) { + // if external reloc was used, real address is symbol n_value + addend + if ( info->functionSymbolIndex != 0xFFFFFFFF ) + info->functionStartAddress += parser.symbolFromIndex(info->functionSymbolIndex).n_value(); + // 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 +4254,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 +4282,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(); @@ -4147,7 +4302,7 @@ 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&) + const struct Parser::CFI_CU_InfoArrays&) { this->_beginAtoms = (Atom*)p; @@ -4173,8 +4328,12 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, this->_hasAliases = true; } else { + 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, this->contentType(), ld::Atom::symbolTableNotIn, + ld::Atom::scopeTranslationUnit, ctype, inclusion, this->dontDeadStrip(), false, false, this->alignmentForAddress(addr)); } p += sizeof(Atom); @@ -4189,7 +4348,7 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, 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(); @@ -4220,7 +4379,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; @@ -4382,6 +4541,12 @@ bool CStringSection::useElementAt(Parser& parser, struct Parser::LabelA return true; } +template +bool CStringSection::ignoreLabel(const char* label) +{ + return (label[0] == 'L') || (label[0] == 'l'); +} + template Atom* CStringSection::findAtomByAddress(pint_t addr) { @@ -4436,26 +4601,15 @@ ld::Fixup::Kind NonLazyPointerSection::fixupKind() return ld::Fixup::kindStoreLittleEndian32; } -template <> -ld::Fixup::Kind NonLazyPointerSection::fixupKind() -{ - return ld::Fixup::kindStoreBigEndian32; -} - -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(); @@ -5192,7 +5346,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 +5401,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 +5434,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 +5456,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 +5482,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 +5530,10 @@ 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) + + +template <> +bool Section::addRelocFixup(class Parser& parser, const macho_relocation_info

* reloc) { const macho_section

* sect = this->machoSection(); bool result = false; @@ -5389,429 +5542,37 @@ 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); - if ( (displacement & 0x02000000) != 0 ) - displacement |= 0xFC000000; - if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; - } - 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::kindStorePPCDtraceCallSiteNop, 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); - parser.addDtraceExtraInfos(src, &target.name[20]); - } - else { - parser.addFixups(src, ld::Fixup::kindStorePPCBranch24, 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; + 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 @@ -5892,7 +5653,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 +5700,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; @@ -6052,7 +5831,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 +5852,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 +5881,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 +5902,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); @@ -6254,41 +6032,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 +6045,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 +6080,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 +6091,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); } } @@ -6440,14 +6151,6 @@ ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 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); - break; } return NULL; } @@ -6464,10 +6167,6 @@ 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) ); } return false; } @@ -6493,17 +6192,6 @@ 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; - return true; - } return false; } @@ -6521,12 +6209,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,6 +6223,9 @@ 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); + } return false; }