X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/d425e3882ca60fabae080ddb890789ef2e73a66b..f410558f5d60087e4c310119a1751b437121c3b9:/src/ld/LinkEdit.hpp diff --git a/src/ld/LinkEdit.hpp b/src/ld/LinkEdit.hpp index 1149f0d..bde0473 100644 --- a/src/ld/LinkEdit.hpp +++ b/src/ld/LinkEdit.hpp @@ -32,6 +32,7 @@ #include #include +#include #include "Options.h" #include "ld.hpp" @@ -81,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); @@ -219,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)); @@ -969,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; @@ -983,7 +998,7 @@ void ExportInfoAtom::encode() const 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()); + warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->safeFilePath()); continue; } if ( atom->isAlias() ) { @@ -1005,6 +1020,14 @@ 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; @@ -1027,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 @@ -1035,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)); @@ -1043,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 @@ -1068,16 +1102,17 @@ private: 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, uint32_t extra) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { case ld::Fixup::kindStoreX86PCRel32: @@ -1092,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: @@ -1105,11 +1142,13 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind } template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) 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: @@ -1119,7 +1158,7 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki } template <> -void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const { switch (kind) { case ld::Fixup::kindStoreLittleEndian32: @@ -1145,10 +1184,37 @@ void SplitSegInfoAtom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki } } - +#if SUPPORT_ARCH_arm64 +template <> +void SplitSegInfoV1Atom::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const +{ + switch (kind) { + 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) { @@ -1175,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, it->extra); + this->addSplitSegInfo(it->fixupAddress, it->kind, it->extra); } // delta compress runs of addresses @@ -1201,6 +1267,14 @@ void SplitSegInfoAtom::encode() const this->_encodedData.append_byte(0); // terminator } + if ( _adrpLocations.size() != 0 ) { + this->_encodedData.append_byte(3); + //fprintf(stderr, "type 3:\n"); + 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"); @@ -1250,6 +1324,108 @@ void SplitSegInfoAtom::encode() const _64bitPointerLocations.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 { @@ -1449,16 +1625,18 @@ void DataInCodeAtom::encode() const -// linker needs to cache "Designated Requirements" in linked binary + template -class DependentDRAtom : public LinkEditAtom +class OptimizationHintsAtom : public LinkEditAtom { public: - DependentDRAtom(const Options& opts, ld::Internal& state, OutputFile& writer) - : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { } + 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 "dependent dylib DR info"; } + virtual const char* name() const { return "linker optimization hints"; } // overrides of LinkEditAtom virtual void encode() const; @@ -1472,41 +1650,44 @@ private: }; template -ld::Section DependentDRAtom::_s_section("__LINKEDIT", "__dependentDR", ld::Section::typeLinkEdit, true); - +ld::Section OptimizationHintsAtom::_s_section("__LINKEDIT", "__opt_hints", ld::Section::typeLinkEdit, true); template -void DependentDRAtom::encode() const +void OptimizationHintsAtom::encode() const { - Security::SuperBlobCore, Security::kSecCodeMagicDRList, uint32_t>::Maker maker; - - uint32_t index = 0; - for(std::vector::iterator it=_state.dylibs.begin(); it != _state.dylibs.end(); ++it) { - const ld::dylib::File* dylib = *it; - Security::BlobCore* dylibDR = (Security::BlobCore*)dylib->codeSignatureDR(); - void* dup = NULL; - if ( dylibDR != NULL ) { - // Maker takes ownership of every blob added - // We need to make a copy here because dylib still owns the pointer returned by codeSignatureDR() - dup = ::malloc(dylibDR->length()); - ::memcpy(dup, dylibDR, dylibDR->length()); + 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); + } + } } - maker.add(index, (Security::BlobCore*)dup); - ++index; + + this->_encodedData.pad_to_size(sizeof(pint_t)); } - Security::SuperBlob* topBlob = maker.make(); - const uint8_t* data = (uint8_t*)topBlob->data(); - for(size_t i=0; i < topBlob->length(); ++i) - _encodedData.append_byte(data[i]); - - this->_encodedData.pad_to_size(sizeof(pint_t)); - this->_encoded = true; } - } // namespace tool } // namespace ld