X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..fb9a160cc46cd88a41dda5ab61012c5572e56f33:/src/ld/LinkEdit.hpp diff --git a/src/ld/LinkEdit.hpp b/src/ld/LinkEdit.hpp index d905a3d..c4421ef 100644 --- a/src/ld/LinkEdit.hpp +++ b/src/ld/LinkEdit.hpp @@ -32,11 +32,13 @@ #include #include +#include #include "Options.h" #include "ld.hpp" #include "Architectures.hpp" #include "MachOFileAbstraction.hpp" +#include "code-sign-blobs/superblob.h" namespace ld { namespace tool { @@ -80,6 +82,17 @@ public: while( more ); } + void append_delta_encoded_uleb128_run(uint64_t start, const std::vector& locations) { + uint64_t lastAddr = start; + for(std::vector::const_iterator it = locations.begin(); it != locations.end(); ++it) { + uint64_t nextAddr = *it; + uint64_t delta = nextAddr - lastAddr; + assert(delta != 0); + append_uleb128(delta); + lastAddr = nextAddr; + } + } + void append_string(const char* str) { for (const char* s = str; *s != '\0'; ++s) _data.push_back(*s); @@ -112,8 +125,6 @@ public: // overrides of ld::Atom virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** nm) const - { return false; } virtual uint64_t objectAddress() const { return 0; } virtual uint64_t size() const; virtual void copyRawContent(uint8_t buffer[]) const; @@ -220,6 +231,8 @@ void RebaseInfoAtom::encode() const } mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1)); address += sizeof(pint_t); + if ( address >= curSegEnd ) + address = 0; } mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0)); @@ -970,6 +983,7 @@ void ExportInfoAtom::encode() const std::vector& exports = this->_writer._exportedAtoms; uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address; std::vector entries; + unsigned int padding = 0; entries.reserve(exports.size()); for (std::vector::const_iterator it = exports.begin(); it != exports.end(); ++it) { const ld::Atom* atom = *it; @@ -977,11 +991,11 @@ void ExportInfoAtom::encode() const uint64_t flags = (atom->contentType() == ld::Atom::typeTLV) ? EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL : EXPORT_SYMBOL_FLAGS_KIND_REGULAR; uint64_t other = 0; uint64_t address = atom->finalAddress() - imageBaseAddress; - if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) - flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; if ( atom->definition() == ld::Atom::definitionProxy ) { entry.name = atom->name(); entry.flags = flags | EXPORT_SYMBOL_FLAGS_REEXPORT; + if ( atom->combine() == ld::Atom::combineByName ) + entry.flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; entry.other = this->_writer.compressedOrdinalForAtom(atom); if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) { warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path()); @@ -1006,7 +1020,17 @@ void ExportInfoAtom::encode() const entries.push_back(entry); //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name); } + else if ( atom->definition() == ld::Atom::definitionAbsolute ) { + entry.name = atom->name(); + entry.flags = _options.canUseAbsoluteSymbols() ? EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE : EXPORT_SYMBOL_FLAGS_KIND_REGULAR; + entry.address = address; + entry.other = other; + entry.importName = NULL; + entries.push_back(entry); + } else { + if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) + flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; if ( atom->isThumb() ) address |= 1; if ( atom->contentType() == ld::Atom::typeResolver ) { @@ -1026,6 +1050,13 @@ void ExportInfoAtom::encode() const entry.importName = NULL; entries.push_back(entry); } + + if (_options.sharedRegionEligible() && strncmp(atom->section().segmentName(), "__DATA", 6) == 0) { + // Maximum address is 64bit which is 10 bytes as a uleb128. Minimum is 1 byte + // Pad the section out so we can deal with addresses getting larger when __DATA segment + // is moved before __TEXT in dyld shared cache. + padding += 9; + } } // sort vector by -exported_symbols_order, and any others by address @@ -1034,6 +1065,10 @@ void ExportInfoAtom::encode() const // create trie mach_o::trie::makeTrie(entries, this->_encodedData.bytes()); + //Add additional data padding for the unoptimized shared cache + for (unsigned int i = 0; i < padding; ++i) + this->_encodedData.append_byte(0); + // align to pointer size this->_encodedData.pad_to_size(sizeof(pint_t)); @@ -1042,10 +1077,10 @@ void ExportInfoAtom::encode() const template -class SplitSegInfoAtom : public LinkEditAtom +class SplitSegInfoV1Atom : public LinkEditAtom { public: - SplitSegInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer) + SplitSegInfoV1Atom(const Options& opts, ld::Internal& state, OutputFile& writer) : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { } // overrides of ld::Atom @@ -1058,22 +1093,26 @@ private: typedef typename A::P::E E; typedef typename A::P::uint_t pint_t; - void addSplitSegInfo(uint64_t address, ld::Fixup::Kind k) const; + void addSplitSegInfo(uint64_t address, ld::Fixup::Kind k, uint32_t) const; void uleb128EncodeAddresses(const std::vector& locations) const; mutable std::vector _32bitPointerLocations; mutable std::vector _64bitPointerLocations; - mutable std::vector _ppcHi16Locations; + mutable std::vector _thumbLo16Locations; + mutable std::vector _thumbHi16Locations[16]; + mutable std::vector _armLo16Locations; + mutable std::vector _armHi16Locations[16]; + mutable std::vector _adrpLocations; static ld::Section _s_section; }; template -ld::Section SplitSegInfoAtom::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true); +ld::Section SplitSegInfoV1Atom::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true); template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { case ld::Fixup::kindStoreX86PCRel32: @@ -1088,6 +1127,8 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind case ld::Fixup::kindStoreTargetAddressX86PCRel32: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad: case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA: + case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad: + case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA: _32bitPointerLocations.push_back(address); break; case ld::Fixup::kindStoreLittleEndian64: @@ -1101,11 +1142,13 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind } template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { case ld::Fixup::kindStoreLittleEndian32: case ld::Fixup::kindStoreTargetAddressLittleEndian32: + case ld::Fixup::kindStoreX86PCRel32TLVLoad: + case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA: _32bitPointerLocations.push_back(address); break; default: @@ -1115,28 +1158,25 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki } template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { case ld::Fixup::kindStoreLittleEndian32: _32bitPointerLocations.push_back(address); break; - default: - warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address); + case ld::Fixup::kindStoreARMLow16: + _armLo16Locations.push_back(address); break; - } -} - - -template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const -{ - switch (kind) { - case ld::Fixup::kindStorePPCPicHigh16AddLow: - _ppcHi16Locations.push_back(address); + case ld::Fixup::kindStoreThumbLow16: + _thumbLo16Locations.push_back(address); break; - case ld::Fixup::kindStoreBigEndian32: - _32bitPointerLocations.push_back(address); + case ld::Fixup::kindStoreARMHigh16: + assert(extra < 16); + _armHi16Locations[extra].push_back(address); + break; + case ld::Fixup::kindStoreThumbHigh16: + assert(extra < 16); + _thumbHi16Locations[extra].push_back(address); break; default: warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address); @@ -1144,23 +1184,37 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki } } - +#if SUPPORT_ARCH_arm64 template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { - case ld::Fixup::kindStorePPCPicHigh16AddLow: - _ppcHi16Locations.push_back(address); + case ld::Fixup::kindStoreARM64Page21: + case ld::Fixup::kindStoreARM64GOTLoadPage21: + case ld::Fixup::kindStoreARM64GOTLeaPage21: + case ld::Fixup::kindStoreARM64TLVPLoadPage21: + case ld::Fixup::kindStoreTargetAddressARM64Page21: + case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21: + case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21: + _adrpLocations.push_back(address); + break; + case ld::Fixup::kindStoreLittleEndian32: + case ld::Fixup::kindStoreARM64PCRelToGOT: + _32bitPointerLocations.push_back(address); + break; + case ld::Fixup::kindStoreLittleEndian64: + case ld::Fixup::kindStoreTargetAddressLittleEndian64: + _64bitPointerLocations.push_back(address); break; default: warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address); break; } } - +#endif template -void SplitSegInfoAtom::uleb128EncodeAddresses(const std::vector& locations) const +void SplitSegInfoV1Atom::uleb128EncodeAddresses(const std::vector& locations) const { pint_t addr = this->_options.baseAddress(); for(typename std::vector::const_iterator it = locations.begin(); it != locations.end(); ++it) { @@ -1187,12 +1241,12 @@ void SplitSegInfoAtom::uleb128EncodeAddresses(const std::vector& lo template -void SplitSegInfoAtom::encode() const +void SplitSegInfoV1Atom::encode() const { // sort into group by pointer adjustment kind std::vector& info = this->_writer._splitSegInfos; for (std::vector::const_iterator it = info.begin(); it != info.end(); ++it) { - this->addSplitSegInfo(it->address, it->kind); + this->addSplitSegInfo(it->fixupAddress, it->kind, it->extra); } // delta compress runs of addresses @@ -1213,14 +1267,50 @@ void SplitSegInfoAtom::encode() const this->_encodedData.append_byte(0); // terminator } - if ( _ppcHi16Locations.size() != 0 ) { + if ( _adrpLocations.size() != 0 ) { this->_encodedData.append_byte(3); //fprintf(stderr, "type 3:\n"); - std::sort(_ppcHi16Locations.begin(), _ppcHi16Locations.end()); - this->uleb128EncodeAddresses(_ppcHi16Locations); + std::sort(_adrpLocations.begin(), _adrpLocations.end()); + this->uleb128EncodeAddresses(_adrpLocations); this->_encodedData.append_byte(0); // terminator } + if ( _thumbLo16Locations.size() != 0 ) { + this->_encodedData.append_byte(5); + //fprintf(stderr, "type 5:\n"); + std::sort(_thumbLo16Locations.begin(), _thumbLo16Locations.end()); + this->uleb128EncodeAddresses(_thumbLo16Locations); + this->_encodedData.append_byte(0); // terminator + } + + if ( _armLo16Locations.size() != 0 ) { + this->_encodedData.append_byte(6); + //fprintf(stderr, "type 6:\n"); + std::sort(_armLo16Locations.begin(), _armLo16Locations.end()); + this->uleb128EncodeAddresses(_armLo16Locations); + this->_encodedData.append_byte(0); // terminator + } + + for (uint32_t i=0; i < 16; ++i) { + if ( _thumbHi16Locations[i].size() != 0 ) { + this->_encodedData.append_byte(16+i); + //fprintf(stderr, "type 16+%d:\n", i); + std::sort(_thumbHi16Locations[i].begin(), _thumbHi16Locations[i].end()); + this->uleb128EncodeAddresses(_thumbHi16Locations[i]); + this->_encodedData.append_byte(0); // terminator + } + } + + for (uint32_t i=0; i < 16; ++i) { + if ( _armHi16Locations[i].size() != 0 ) { + this->_encodedData.append_byte(32+i); + //fprintf(stderr, "type 32+%d:\n", i); + std::sort(_armHi16Locations[i].begin(), _armHi16Locations[i].end()); + this->uleb128EncodeAddresses(_armHi16Locations[i]); + this->_encodedData.append_byte(0); // terminator + } + } + // always add zero byte to mark end this->_encodedData.append_byte(0); @@ -1232,10 +1322,110 @@ void SplitSegInfoAtom::encode() const // clean up temporaries _32bitPointerLocations.clear(); _64bitPointerLocations.clear(); - _ppcHi16Locations.clear(); } +template +class SplitSegInfoV2Atom : public LinkEditAtom +{ +public: + SplitSegInfoV2Atom(const Options& opts, ld::Internal& state, OutputFile& writer) + : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { } + + // overrides of ld::Atom + virtual const char* name() const { return "split seg info"; } + // overrides of LinkEditAtom + virtual void encode() const; + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + // Whole :== FromToSection+ + // FromToSection :== ToOffset+ + // ToOffset :== FromOffset+ + // FromOffset :== + + typedef uint32_t SectionIndexes; + typedef std::map > FromOffsetMap; + typedef std::map ToOffsetMap; + typedef std::map WholeMap; + + + static ld::Section _s_section; +}; + +template +ld::Section SplitSegInfoV2Atom::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true); + + +template +void SplitSegInfoV2Atom::encode() const +{ + // sort into group by adjustment kind + //fprintf(stderr, "_splitSegV2Infos.size=%lu\n", this->_writer._splitSegV2Infos.size()); + WholeMap whole; + for (const OutputFile::SplitSegInfoV2Entry& entry : this->_writer._splitSegV2Infos) { + //fprintf(stderr, "from=%d, to=%d\n", entry.fixupSectionIndex, entry.targetSectionIndex); + SectionIndexes index = entry.fixupSectionIndex << 16 | entry.targetSectionIndex; + ToOffsetMap& toOffsets = whole[index]; + FromOffsetMap& fromOffsets = toOffsets[entry.targetSectionOffset]; + fromOffsets[entry.referenceKind].push_back(entry.fixupSectionOffset); + } + + // Add marker that this is V2 data + this->_encodedData.reserve(8192); + this->_encodedData.append_byte(DYLD_CACHE_ADJ_V2_FORMAT); + + // stream out + // Whole :== FromToSection+ + this->_encodedData.append_uleb128(whole.size()); + for (auto& fromToSection : whole) { + uint8_t fromSectionIndex = fromToSection.first >> 16; + uint8_t toSectionIndex = fromToSection.first & 0xFFFF; + ToOffsetMap& toOffsets = fromToSection.second; + // FromToSection :== ToOffset+ + this->_encodedData.append_uleb128(fromSectionIndex); + this->_encodedData.append_uleb128(toSectionIndex); + this->_encodedData.append_uleb128(toOffsets.size()); + //fprintf(stderr, "from sect=%d, to sect=%d, count=%lu\n", fromSectionIndex, toSectionIndex, toOffsets.size()); + uint64_t lastToOffset = 0; + for (auto& fromToOffsets : toOffsets) { + uint64_t toSectionOffset = fromToOffsets.first; + FromOffsetMap& fromOffsets = fromToOffsets.second; + // ToOffset :== FromOffset+ + this->_encodedData.append_uleb128(toSectionOffset - lastToOffset); + this->_encodedData.append_uleb128(fromOffsets.size()); + for (auto& kindAndOffsets : fromOffsets) { + uint8_t kind = kindAndOffsets.first; + std::vector& fromOffsets = kindAndOffsets.second; + // FromOffset :== + this->_encodedData.append_uleb128(kind); + this->_encodedData.append_uleb128(fromOffsets.size()); + std::sort(fromOffsets.begin(), fromOffsets.end()); + uint64_t lastFromOffset = 0; + for (uint64_t offset : fromOffsets) { + this->_encodedData.append_uleb128(offset - lastFromOffset); + lastFromOffset = offset; + } + } + lastToOffset = toSectionOffset; + } + } + + + // always add zero byte to mark end + this->_encodedData.append_byte(0); + + // align to pointer size + this->_encodedData.pad_to_size(sizeof(pint_t)); + + this->_encoded = true; +} + + + template class FunctionStartsAtom : public LinkEditAtom { @@ -1264,7 +1454,7 @@ template void FunctionStartsAtom::encode() const { this->_encodedData.reserve(8192); - const uint64_t badAddress = 1; + const uint64_t badAddress = 0xFFFFFFFFFFFFFFFF; uint64_t addr = badAddress; // delta compress all function addresses for (std::vector::iterator it = this->_state.sections.begin(); it != this->_state.sections.end(); ++it) { @@ -1278,6 +1468,9 @@ void FunctionStartsAtom::encode() const std::vector& atoms = sect->atoms; for (std::vector::iterator ait = atoms.begin(); ait != atoms.end(); ++ait) { const ld::Atom* atom = *ait; + // filter out zero-length atoms, so LC_FUNCTION_STARTS address can't spill into next section + if ( atom->size() == 0 ) + continue; uint64_t nextAddr = atom->finalAddress(); if ( atom->isThumb() ) nextAddr |= 1; @@ -1299,6 +1492,201 @@ void FunctionStartsAtom::encode() const } +// Need way to formalize data in code +template +class DataInCodeAtom : public LinkEditAtom +{ +public: + DataInCodeAtom(const Options& opts, ld::Internal& state, OutputFile& writer) + : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { } + + // overrides of ld::Atom + virtual const char* name() const { return "data-in-code info"; } + // overrides of LinkEditAtom + virtual void encode() const; + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + struct FixupByAddressSorter + { + bool operator()(const ld::Fixup* left, const ld::Fixup* right) + { + return (left->offsetInAtom < right->offsetInAtom); + } + }; + + void encodeEntry(uint32_t startImageOffset, int len, ld::Fixup::Kind kind) const { + //fprintf(stderr, "encodeEntry(start=0x%08X, len=0x%04X, kind=%04X\n", startImageOffset, len, kind); + do { + macho_data_in_code_entry

entry; + entry.set_offset(startImageOffset); + entry.set_length(len); + switch ( kind ) { + case ld::Fixup::kindDataInCodeStartData: + entry.set_kind(DICE_KIND_DATA); + break; + case ld::Fixup::kindDataInCodeStartJT8: + entry.set_kind(DICE_KIND_JUMP_TABLE8); + break; + case ld::Fixup::kindDataInCodeStartJT16: + entry.set_kind(DICE_KIND_JUMP_TABLE16); + break; + case ld::Fixup::kindDataInCodeStartJT32: + entry.set_kind(DICE_KIND_JUMP_TABLE32); + break; + case ld::Fixup::kindDataInCodeStartJTA32: + entry.set_kind(DICE_KIND_ABS_JUMP_TABLE32); + break; + default: + assert(0 && "bad L$start$ label to encode"); + } + uint8_t* bp = (uint8_t*)&entry; + this->_encodedData.append_byte(bp[0]); + this->_encodedData.append_byte(bp[1]); + this->_encodedData.append_byte(bp[2]); + this->_encodedData.append_byte(bp[3]); + this->_encodedData.append_byte(bp[4]); + this->_encodedData.append_byte(bp[5]); + this->_encodedData.append_byte(bp[6]); + this->_encodedData.append_byte(bp[7]); + // in rare case data range is huge, create multiple entries + len -= 0xFFF8; + startImageOffset += 0xFFF8; + } while ( len > 0 ); + } + + static ld::Section _s_section; +}; + +template +ld::Section DataInCodeAtom::_s_section("__LINKEDIT", "__dataInCode", ld::Section::typeLinkEdit, true); + + +template +void DataInCodeAtom::encode() const +{ + if ( this->_writer.hasDataInCode ) { + uint64_t mhAddress = 0; + for (std::vector::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + if ( sect->type() == ld::Section::typeMachHeader ) + mhAddress = sect->address; + if ( sect->type() != ld::Section::typeCode ) + continue; + for (std::vector::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + // gather all code-in-data labels + std::vector dataInCodeLabels; + for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { + switch ( fit->kind ) { + case ld::Fixup::kindDataInCodeStartData: + case ld::Fixup::kindDataInCodeStartJT8: + case ld::Fixup::kindDataInCodeStartJT16: + case ld::Fixup::kindDataInCodeStartJT32: + case ld::Fixup::kindDataInCodeStartJTA32: + case ld::Fixup::kindDataInCodeEnd: + dataInCodeLabels.push_back(fit); + break; + default: + break; + } + } + // to do: sort labels by address + std::sort(dataInCodeLabels.begin(), dataInCodeLabels.end(), FixupByAddressSorter()); + + // convert to array of struct data_in_code_entry + ld::Fixup::Kind prevKind = ld::Fixup::kindDataInCodeEnd; + uint32_t prevOffset = 0; + for ( std::vector::iterator sfit = dataInCodeLabels.begin(); sfit != dataInCodeLabels.end(); ++sfit) { + if ( ((*sfit)->kind != prevKind) && (prevKind != ld::Fixup::kindDataInCodeEnd) ) { + int len = (*sfit)->offsetInAtom - prevOffset; + if ( len == 0 ) + warning("multiple L$start$ labels found at same address in %s at offset 0x%04X", atom->name(), prevOffset); + this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, (*sfit)->offsetInAtom - prevOffset, prevKind); + } + prevKind = (*sfit)->kind; + prevOffset = (*sfit)->offsetInAtom; + } + if ( prevKind != ld::Fixup::kindDataInCodeEnd ) { + // add entry if function ends with data + this->encodeEntry(atom->finalAddress()+prevOffset-mhAddress, atom->size() - prevOffset, prevKind); + } + } + } + } + + this->_encoded = true; +} + + + + + + +template +class OptimizationHintsAtom : public LinkEditAtom +{ +public: + OptimizationHintsAtom(const Options& opts, ld::Internal& state, OutputFile& writer) + : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { + assert(opts.outputKind() == Options::kObjectFile); + } + + // overrides of ld::Atom + virtual const char* name() const { return "linker optimization hints"; } + // overrides of LinkEditAtom + virtual void encode() const; + +private: + typedef typename A::P P; + typedef typename A::P::E E; + typedef typename A::P::uint_t pint_t; + + static ld::Section _s_section; + +}; + +template +ld::Section OptimizationHintsAtom::_s_section("__LINKEDIT", "__opt_hints", ld::Section::typeLinkEdit, true); + +template +void OptimizationHintsAtom::encode() const +{ + if ( _state.someObjectHasOptimizationHints ) { + for (std::vector::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) { + ld::Internal::FinalSection* sect = *sit; + if ( sect->type() != ld::Section::typeCode ) + continue; + for (std::vector::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) { + const ld::Atom* atom = *ait; + uint64_t address = atom->finalAddress(); + for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) { + if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint) + continue; + ld::Fixup::LOH_arm64 extra; + extra.addend = fit->u.addend; + _encodedData.append_uleb128(extra.info.kind); + _encodedData.append_uleb128(extra.info.count+1); + _encodedData.append_uleb128((extra.info.delta1 << 2) + fit->offsetInAtom + address); + if ( extra.info.count > 0 ) + _encodedData.append_uleb128((extra.info.delta2 << 2) + fit->offsetInAtom + address); + if ( extra.info.count > 1 ) + _encodedData.append_uleb128((extra.info.delta3 << 2) + fit->offsetInAtom + address); + if ( extra.info.count > 2 ) + _encodedData.append_uleb128((extra.info.delta4 << 2) + fit->offsetInAtom + address); + } + } + } + + this->_encodedData.pad_to_size(sizeof(pint_t)); + } + + this->_encoded = true; +} + } // namespace tool } // namespace ld