X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/9543cb2f21e50a417dc8cf37eb7173f353536979..599556ff3dd31aab68bb9685f1ed7fc4867803e7:/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 ad5720e..d3990e3 100644 --- a/src/ld/parsers/macho_relocatable_file.cpp +++ b/src/ld/parsers/macho_relocatable_file.cpp @@ -79,6 +79,7 @@ public: _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), _objConstraint(ld::File::objcConstraintNone), + _swiftVersion(0), _cpuSubType(0), _canScatterAtoms(false) {} virtual ~File(); @@ -96,6 +97,7 @@ public: virtual bool canScatterAtoms() const { return _canScatterAtoms; } virtual const char* translationUnitSource() const; virtual LinkerOptionsList* linkerOptions() const { return &_linkerOptions; } + virtual uint8_t swiftVersion() const { return _swiftVersion; } const uint8_t* fileContent() { return _fileContent; } private: @@ -109,8 +111,10 @@ private: const uint8_t* _fileContent; Section** _sectionsArray; uint8_t* _atomsArray; + uint8_t* _aliasAtomsArray; uint32_t _sectionsArrayCount; uint32_t _atomsArrayCount; + uint32_t _aliasAtomsArrayCount; std::vector _fixups; std::vector _unwindInfos; std::vector _lineInfos; @@ -122,6 +126,7 @@ private: const macho_section

* _dwarfDebugLineSect; const macho_section

* _dwarfDebugStringSect; ld::File::ObjcConstraint _objConstraint; + uint8_t _swiftVersion; uint32_t _cpuSubType; bool _canScatterAtoms; std::vector > _linkerOptions; @@ -182,6 +187,7 @@ protected: class Atom* _beginAtoms; class Atom* _endAtoms; bool _hasAliases; + std::set*> _altEntries; }; @@ -191,7 +197,7 @@ class CFISection : public Section public: CFISection(Parser& parser, File& f, const macho_section* s) : Section(f, s) { } - uint32_t cfiCount(); + uint32_t cfiCount(Parser& parser); virtual ld::Atom::ContentType contentType() { return ld::Atom::typeCFI; } virtual uint32_t computeAtomCount(class Parser& parser, struct Parser::LabelAndCFIBreakIterator& it, const struct Parser::CFI_CU_InfoArrays&); @@ -887,6 +893,39 @@ void Atom::verifyAlignment(const macho_section

&) const } +class AliasAtom : public ld::Atom +{ +public: + AliasAtom(const char* name, bool hidden, const ld::File* file, const char* aliasOfName) : + ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, + (hidden ? ld::Atom::scopeLinkageUnit : ld::Atom::scopeGlobal), + ld::Atom::typeUnclassified, ld::Atom::symbolTableIn, + false, false, true, 0), + _file(file), + _name(name), + _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, ld::Fixup::bindingByNameUnbound, aliasOfName) { } + + virtual const ld::File* file() const { return _file; } + virtual const char* translationUnitSource() const + { return NULL; } + virtual const char* name() const { return _name; } + virtual uint64_t size() const { return 0; } + virtual uint64_t objectAddress() const { return 0; } + virtual void copyRawContent(uint8_t buffer[]) const { } + virtual ld::Fixup::iterator fixupsBegin() const { return &((ld::Fixup*)&_fixup)[0]; } + virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; } + +private: + static ld::Section _s_section; + + const ld::File* _file; + const char* _name; + ld::Fixup _fixup; +}; + +ld::Section AliasAtom::_s_section("__LD", "__aliases", ld::Section::typeTempAlias, true); + + template class Parser { @@ -984,6 +1023,7 @@ public: static bool isThumbFromSymbol(const macho_nlist

& sym); static bool weakImportFromSymbol(const macho_nlist

& sym); static bool resolverFromSymbol(const macho_nlist

& sym); + static bool altEntryFromSymbol(const macho_nlist

& sym); uint32_t symbolIndexFromIndirectSectionAddress(pint_t,const macho_section

*); const macho_section

* firstMachOSection() { return _sectionsStart; } const macho_section

* machOSectionFromSectionIndex(uint32_t index); @@ -1014,7 +1054,7 @@ public: bool forceDwarfConversion() { return _forceDwarfConversion; } bool verboseOptimizationHints() { return _verboseOptimizationHints; } bool neverConvertDwarf() { return _neverConvertDwarf; } - + macho_data_in_code_entry

* dataInCodeStart() { return _dataInCodeStart; } macho_data_in_code_entry

* dataInCodeEnd() { return _dataInCodeEnd; } const uint8_t* optimizationHintsStart() { return _lohStart; } @@ -1111,10 +1151,13 @@ private: void parseDebugInfo(); void parseStabs(); + void appendAliasAtoms(uint8_t* atomBuffer); static bool isConstFunStabs(const char *stabStr); bool read_comp_unit(const char ** name, const char ** comp_dir, uint64_t *stmt_list); - const char* getDwarfString(uint64_t form, const uint8_t* p); + pint_t realAddr(pint_t addr); + const char* getDwarfString(uint64_t form, const uint8_t*& p); + uint64_t getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64); bool skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t form, uint8_t addr_size, bool dwarf64); @@ -1130,6 +1173,7 @@ private: File* _file; const macho_nlist

* _symbols; uint32_t _symbolCount; + uint32_t _indirectSymbolCount; const char* _strings; uint32_t _stringsSize; const uint32_t* _indirectTable; @@ -1174,7 +1218,7 @@ Parser::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p bool neverConvertDwarf, bool verboseOptimizationHints) : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime), _ordinal(ordinal), _file(NULL), - _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0), + _symbols(NULL), _symbolCount(0), _indirectSymbolCount(0), _strings(NULL), _stringsSize(0), _indirectTable(NULL), _indirectTableCount(0), _undefinedStartIndex(0), _undefinedEndIndex(0), _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), @@ -1555,6 +1599,18 @@ bool Parser::LabelAndCFIBreakIterator::next(Parser& parser, const Section< return false; } +template <> +typename arm::P::uint_t Parser::realAddr(typename arm::P::uint_t addr) +{ + return addr & (-2); +} + +template +typename A::P::uint_t Parser::realAddr(typename A::P::uint_t addr) +{ + return addr; +} + #define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \ _type* _name = NULL; \ uint32_t _name##_count = 1; \ @@ -1619,7 +1675,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) // stack allocate (if not too large) array of CFI_Atom_Info uint32_t countOfCFIs = 0; if ( _EHFrameSection != NULL ) - countOfCFIs = _EHFrameSection->cfiCount(); + countOfCFIs = _EHFrameSection->cfiCount(*this); 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 @@ -1655,7 +1711,7 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) if ( cfiArray[i].isCIE ) continue; if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS ) - cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress; + cfiStartsArray[cfiStartsArrayCount++] = realAddr(cfiArray[i].u.fdeInfo.function.targetAddress); if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS ) cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress; ++countOfFDEs; @@ -1792,6 +1848,16 @@ ld::relocatable::File* Parser::parse(const ParserOptions& opts) } } + // process indirect symbols which become AliasAtoms + _file->_aliasAtomsArray = NULL; + _file->_aliasAtomsArrayCount = 0; + if ( _indirectSymbolCount != 0 ) { + _file->_aliasAtomsArrayCount = _indirectSymbolCount; + _file->_aliasAtomsArray = new uint8_t[_file->_aliasAtomsArrayCount*sizeof(AliasAtom)]; + this->appendAliasAtoms(_file->_aliasAtomsArray); + } + + // parse dwarf debug info to get line info this->parseDebugInfo(); @@ -1799,7 +1865,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; } @@ -1950,7 +2015,11 @@ void Parser::prescanSymbolTable() } continue; } - + else if ( ((sym.n_type() & N_TYPE) == N_INDR) && ((sym.n_type() & N_EXT) != 0) ) { + _indirectSymbolCount++; + continue; + } + // count absolute symbols if ( (sym.n_type() & N_TYPE) == N_ABS ) { const char* absName = this->nameFromSymbol(sym); @@ -1987,6 +2056,34 @@ void Parser::prescanSymbolTable() } } +template +void Parser::appendAliasAtoms(uint8_t* p) +{ + for (uint32_t i=0; i < this->_symbolCount; ++i) { + const macho_nlist

& sym = symbolFromIndex(i); + // ignore stabs + if ( (sym.n_type() & N_STAB) != 0 ) + continue; + + // only look at N_INDR symbols + if ( (sym.n_type() & N_TYPE) != N_INDR ) + continue; + + // skip non-external aliases + if ( (sym.n_type() & N_EXT) == 0 ) + continue; + + const char* symbolName = this->nameFromSymbol(sym); + const char* aliasOfName = &_strings[sym.n_value()]; + bool isHiddenVisibility = (sym.n_type() & N_PEXT); + AliasAtom* allocatedSpace = (AliasAtom*)p; + new (allocatedSpace) AliasAtom(symbolName, isHiddenVisibility, _file, aliasOfName); + p += sizeof(AliasAtom); + } +} + + + template int Parser::sectionIndexSorter(void* extra, const void* l, const void* r) { @@ -2206,6 +2303,7 @@ void Parser::makeSections() _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator; else _file->_objConstraint = ld::File::objcConstraintRetainRelease; + _file->_swiftVersion = ((flags >> 8) & 0xFF); if ( sect->size() > 8 ) { warning("section %s/%s has unexpectedly large size %llu in %s", sect->segname(), Section::makeSectionName(sect), sect->size(), _file->path()); @@ -3011,6 +3109,12 @@ bool Parser::resolverFromSymbol(const macho_nlist

& sym) return ( sym.n_desc() & N_SYMBOL_RESOLVER ); } +template +bool Parser::altEntryFromSymbol(const macho_nlist

& sym) +{ + return ( sym.n_desc() & N_ALT_ENTRY ); +} + /* Skip over a LEB128 value (signed or unsigned). */ static void @@ -3144,21 +3248,51 @@ bool Parser::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t template -const char* Parser::getDwarfString(uint64_t form, const uint8_t* p) +const char* Parser::getDwarfString(uint64_t form, const uint8_t*& di) { - if ( form == DW_FORM_string ) - return (const char*)p; - else if ( form == DW_FORM_strp ) { - uint32_t offset = E::get32(*((uint32_t*)p)); - const char* dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset(); - if ( offset > _file->_dwarfDebugStringSect->size() ) { - warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->_path); - return NULL; - } - return &dwarfStrings[offset]; + uint32_t offset; + const char* dwarfStrings; + const char* result = NULL; + switch (form) { + case DW_FORM_string: + result = (const char*)di; + di += strlen(result) + 1; + break; + case DW_FORM_strp: + offset = E::get32(*((uint32_t*)di)); + dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset(); + if ( offset < _file->_dwarfDebugStringSect->size() ) + result = &dwarfStrings[offset]; + else + warning("dwarf DW_FORM_strp (offset=0x%08X) is too big in %s", offset, this->_path); + di += 4; + break; + default: + warning("unknown dwarf string encoding (form=%lld) in %s", form, this->_path); + break; } - warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->_path); - return NULL; + return result; +} + +template +uint64_t Parser::getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64) +{ + if ( form == DW_FORM_sec_offset ) + form = (dwarf64 ? DW_FORM_data8 : DW_FORM_data4); + uint64_t result = -1; + switch (form) { + case DW_FORM_data4: + result = A::P::E::get32(*(uint32_t*)di); + di += 4; + break; + case DW_FORM_data8: + result = A::P::E::get64(*(uint64_t*)di); + di += 8; + break; + default: + warning("unknown dwarf DW_FORM_ for DW_AT_stmt_list in %s", this->_path); + } + return result; } @@ -3400,6 +3534,7 @@ void Parser::parseStabs() case N_LSYM: case N_RSYM: case N_PSYM: + case N_AST: // not associated with an atom, just copy stab.string = symString; break; @@ -3676,20 +3811,23 @@ bool Parser::read_comp_unit(const char ** name, const char ** comp_dir, return false; else if (attr == 0) return true; - if (form == DW_FORM_indirect) form = read_uleb128 (&di, end); - if (attr == DW_AT_name) - *name = getDwarfString(form, di); - else if (attr == DW_AT_comp_dir) - *comp_dir = getDwarfString(form, di); - else if (attr == DW_AT_stmt_list && form == DW_FORM_data4) - *stmt_list = A::P::E::get32(*(uint32_t*)di); - else if (attr == DW_AT_stmt_list && form == DW_FORM_data8) - *stmt_list = A::P::E::get64(*(uint64_t*)di); - if (! skip_form (&di, end, form, address_size, dwarf64)) - return false; + switch (attr) { + case DW_AT_name: + *name = getDwarfString(form, di); + break; + case DW_AT_comp_dir: + *comp_dir = getDwarfString(form, di); + break; + case DW_AT_stmt_list: + *stmt_list = getDwarfOffset(form, di, dwarf64); + break; + default: + if (! skip_form (&di, end, form, address_size, dwarf64)) + return false; + } } } @@ -3708,7 +3846,7 @@ const char* File::translationUnitSource() const return _dwarfTranslationUnitPath; } - + template bool File::forEachAtom(ld::File::AtomHandler& handler) const @@ -3719,7 +3857,13 @@ bool File::forEachAtom(ld::File::AtomHandler& handler) const handler.doAtom(*((Atom*)p)); p += sizeof(Atom); } - return (_atomsArrayCount != 0); + p = _aliasAtomsArray; + for(int i=_aliasAtomsArrayCount; i > 0; --i) { + handler.doAtom(*((AliasAtom*)p)); + p += sizeof(AliasAtom); + } + + return (_atomsArrayCount != 0) || (_aliasAtomsArrayCount != 0); } template @@ -3922,10 +4066,14 @@ uint32_t Section::sectionNum(class Parser& parser) const } // arm does not have zero cost exceptions -template <> uint32_t CFISection::cfiCount() { return 0; } +template <> +uint32_t CFISection::cfiCount(Parser& parser) +{ + return 0; +} template -uint32_t CFISection::cfiCount() +uint32_t CFISection::cfiCount(Parser& parser) { // create ObjectAddressSpace object for use by libunwind OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset()); @@ -4059,6 +4207,9 @@ void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, assert(count == 0); } + + + template <> void CFISection::cfiParse(class Parser& parser, uint8_t* buffer, libunwind::CFI_Atom_Info::OAS>::CFI_Atom_Info cfiArray[], @@ -4209,8 +4360,6 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, const C } } - - #if SUPPORT_ARCH_arm64 template <> void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) @@ -4236,6 +4385,7 @@ void CFISection::addCiePersonalityFixups(class Parser& parser, con } #endif + template void CFISection::addCiePersonalityFixups(class Parser& parser, const CFI_Atom_Info* cieInfo) { @@ -4481,8 +4631,7 @@ const char* CUSection::personalityName(class Parser& parser, con 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"); + assert((parser.sectionForAddress(personalityAddr)->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; @@ -4537,6 +4686,7 @@ const char* CUSection::personalityName(class Parser& parser, const } #endif + template const char* CUSection::personalityName(class Parser& parser, const macho_relocation_info

* reloc) { @@ -4780,6 +4930,8 @@ uint32_t SymboledSection::appendAtoms(class Parser& parser, uint8_t* p, new (allocatedSpace) Atom(*this, parser, *label, size, isAlias); if ( isAlias ) this->_hasAliases = true; + if ( parser.altEntryFromSymbol(*label) ) + this->_altEntries.insert(allocatedSpace); } else { ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn; @@ -6085,7 +6237,12 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati if ((instruction & 0xFE000000) == 0xFA000000) displacement += ((instruction & 0x01000000) >> 23); if ( reloc->r_extern() ) { - target.addend = srcAddr + displacement; + dstAddr = srcAddr + displacement; + // support large .o files + if ( srcAddr > 0x2000000 ) { + dstAddr -= ((srcAddr + 0x1FFFFFF) & 0xFC000000); + } + target.addend = dstAddr; if ( externSymbolIsThumbDef ) target.addend &= -2; // remove thumb bit } @@ -6132,7 +6289,11 @@ bool Section::addRelocFixup(class Parser& parser, const macho_relocati dstAddr &= 0xFFFFFFFC; if ( reloc->r_extern() ) { - target.addend = dstAddr; + // support large .o files + if ( srcAddr > 0x1000000 ) { + dstAddr -= ((srcAddr + 0xFFFFFF) & 0xFE000000); + } + target.addend = (int64_t)(int32_t)dstAddr; } else { parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target); @@ -6994,6 +7155,21 @@ void Section::makeFixups(class Parser& parser, const struct Parser::CFI } } } + if ( !this->_altEntries.empty() && !this->addFollowOnFixups() ) { + if ( _altEntries.count(_beginAtoms) != 0 ) + warning("N_ALT_ENTRY bit set on first atom in section %s/%s", sect->segname(), Section::makeSectionName(sect)); + + Atom* end = &_endAtoms[-1]; + for(Atom* p = _beginAtoms; p < end; ++p) { + Atom* nextAtom = &p[1]; + if ( _altEntries.count(nextAtom) != 0 ) { + typename Parser::SourceLocation src(p, 0); + parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom); + typename Parser::SourceLocation src2(nextAtom, 0); + parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinate, p); + } + } + } // track data-in-code if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) {