diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/ExecutionEngine | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'llvm/lib/ExecutionEngine')
51 files changed, 1927 insertions, 1218 deletions
diff --git a/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp b/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp index 1fb37ce7c57c..29a623ebe449 100644 --- a/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp +++ b/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include <mutex> @@ -70,7 +71,7 @@ LLVM_ATTRIBUTE_USED void requiredSymbolDefinitionsFromOrcTargetProcess() { } struct RegisteredObjectInfo { - RegisteredObjectInfo() {} + RegisteredObjectInfo() = default; RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, OwningBinary<ObjectFile> Obj) @@ -96,7 +97,7 @@ class GDBJITRegistrationListener : public JITEventListener { public: /// Instantiates the JIT service. - GDBJITRegistrationListener() {} + GDBJITRegistrationListener() = default; /// Unregisters each object that was previously registered and releases all /// internal resources. diff --git a/llvm/lib/ExecutionEngine/Interpreter/Interpreter.h b/llvm/lib/ExecutionEngine/Interpreter/Interpreter.h index fd7fa21df196..3dfe736dc5be 100644 --- a/llvm/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/llvm/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -37,7 +37,7 @@ class AllocaHolder { std::vector<void *> Allocations; public: - AllocaHolder() {} + AllocaHolder() = default; // Make this type move-only. AllocaHolder(AllocaHolder &&) = default; diff --git a/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp new file mode 100644 index 000000000000..0fc366bf505f --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.cpp @@ -0,0 +1,117 @@ +//===-------- JITLink_DWARFRecordSectionSplitter.cpp - JITLink-------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" +#include "llvm/Support/BinaryStreamReader.h" + +#define DEBUG_TYPE "jitlink" + +namespace llvm { +namespace jitlink { + +DWARFRecordSectionSplitter::DWARFRecordSectionSplitter(StringRef SectionName) + : SectionName(SectionName) {} + +Error DWARFRecordSectionSplitter::operator()(LinkGraph &G) { + auto *Section = G.findSectionByName(SectionName); + + if (!Section) { + LLVM_DEBUG({ + dbgs() << "DWARFRecordSectionSplitter: No " << SectionName + << " section. Nothing to do\n"; + }); + return Error::success(); + } + + LLVM_DEBUG({ + dbgs() << "DWARFRecordSectionSplitter: Processing " << SectionName + << "...\n"; + }); + + DenseMap<Block *, LinkGraph::SplitBlockCache> Caches; + + { + // Pre-build the split caches. + for (auto *B : Section->blocks()) + Caches[B] = LinkGraph::SplitBlockCache::value_type(); + for (auto *Sym : Section->symbols()) + Caches[&Sym->getBlock()]->push_back(Sym); + for (auto *B : Section->blocks()) + llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) { + return LHS->getOffset() > RHS->getOffset(); + }); + } + + // Iterate over blocks (we do this by iterating over Caches entries rather + // than Section->blocks() as we will be inserting new blocks along the way, + // which would invalidate iterators in the latter sequence. + for (auto &KV : Caches) { + auto &B = *KV.first; + auto &BCache = KV.second; + if (auto Err = processBlock(G, B, BCache)) + return Err; + } + + return Error::success(); +} + +Error DWARFRecordSectionSplitter::processBlock( + LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache) { + LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); + + // Section should not contain zero-fill blocks. + if (B.isZeroFill()) + return make_error<JITLinkError>("Unexpected zero-fill block in " + + SectionName + " section"); + + if (B.getSize() == 0) { + LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); + return Error::success(); + } + + BinaryStreamReader BlockReader( + StringRef(B.getContent().data(), B.getContent().size()), + G.getEndianness()); + + while (true) { + uint64_t RecordStartOffset = BlockReader.getOffset(); + + LLVM_DEBUG({ + dbgs() << " Processing CFI record at " + << formatv("{0:x16}", B.getAddress()) << "\n"; + }); + + uint32_t Length; + if (auto Err = BlockReader.readInteger(Length)) + return Err; + if (Length != 0xffffffff) { + if (auto Err = BlockReader.skip(Length)) + return Err; + } else { + uint64_t ExtendedLength; + if (auto Err = BlockReader.readInteger(ExtendedLength)) + return Err; + if (auto Err = BlockReader.skip(ExtendedLength)) + return Err; + } + + // If this was the last block then there's nothing to split + if (BlockReader.empty()) { + LLVM_DEBUG(dbgs() << " Extracted " << B << "\n"); + return Error::success(); + } + + uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset; + auto &NewBlock = G.splitBlock(B, BlockSize); + (void)NewBlock; + LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); + } +} + +} // namespace jitlink +} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp index 2ae193595fc0..b1492cd74508 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -10,6 +10,7 @@ #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" #include "llvm/Support/DynamicLibrary.h" @@ -18,109 +19,13 @@ namespace llvm { namespace jitlink { -EHFrameSplitter::EHFrameSplitter(StringRef EHFrameSectionName) - : EHFrameSectionName(EHFrameSectionName) {} - -Error EHFrameSplitter::operator()(LinkGraph &G) { - auto *EHFrame = G.findSectionByName(EHFrameSectionName); - - if (!EHFrame) { - LLVM_DEBUG({ - dbgs() << "EHFrameSplitter: No " << EHFrameSectionName - << " section. Nothing to do\n"; - }); - return Error::success(); - } - - LLVM_DEBUG({ - dbgs() << "EHFrameSplitter: Processing " << EHFrameSectionName << "...\n"; - }); - - DenseMap<Block *, LinkGraph::SplitBlockCache> Caches; - - { - // Pre-build the split caches. - for (auto *B : EHFrame->blocks()) - Caches[B] = LinkGraph::SplitBlockCache::value_type(); - for (auto *Sym : EHFrame->symbols()) - Caches[&Sym->getBlock()]->push_back(Sym); - for (auto *B : EHFrame->blocks()) - llvm::sort(*Caches[B], [](const Symbol *LHS, const Symbol *RHS) { - return LHS->getOffset() > RHS->getOffset(); - }); - } - - // Iterate over blocks (we do this by iterating over Caches entries rather - // than EHFrame->blocks() as we will be inserting new blocks along the way, - // which would invalidate iterators in the latter sequence. - for (auto &KV : Caches) { - auto &B = *KV.first; - auto &BCache = KV.second; - if (auto Err = processBlock(G, B, BCache)) - return Err; - } - - return Error::success(); -} - -Error EHFrameSplitter::processBlock(LinkGraph &G, Block &B, - LinkGraph::SplitBlockCache &Cache) { - LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); - - // eh-frame should not contain zero-fill blocks. - if (B.isZeroFill()) - return make_error<JITLinkError>("Unexpected zero-fill block in " + - EHFrameSectionName + " section"); - - if (B.getSize() == 0) { - LLVM_DEBUG(dbgs() << " Block is empty. Skipping.\n"); - return Error::success(); - } - - BinaryStreamReader BlockReader( - StringRef(B.getContent().data(), B.getContent().size()), - G.getEndianness()); - - while (true) { - uint64_t RecordStartOffset = BlockReader.getOffset(); - - LLVM_DEBUG({ - dbgs() << " Processing CFI record at " - << formatv("{0:x16}", B.getAddress()) << "\n"; - }); - - uint32_t Length; - if (auto Err = BlockReader.readInteger(Length)) - return Err; - if (Length != 0xffffffff) { - if (auto Err = BlockReader.skip(Length)) - return Err; - } else { - uint64_t ExtendedLength; - if (auto Err = BlockReader.readInteger(ExtendedLength)) - return Err; - if (auto Err = BlockReader.skip(ExtendedLength)) - return Err; - } - - // If this was the last block then there's nothing to split - if (BlockReader.empty()) { - LLVM_DEBUG(dbgs() << " Extracted " << B << "\n"); - return Error::success(); - } - - uint64_t BlockSize = BlockReader.getOffset() - RecordStartOffset; - auto &NewBlock = G.splitBlock(B, BlockSize); - (void)NewBlock; - LLVM_DEBUG(dbgs() << " Extracted " << NewBlock << "\n"); - } -} - EHFrameEdgeFixer::EHFrameEdgeFixer(StringRef EHFrameSectionName, - unsigned PointerSize, Edge::Kind Delta64, - Edge::Kind Delta32, Edge::Kind NegDelta32) + unsigned PointerSize, Edge::Kind Pointer32, + Edge::Kind Pointer64, Edge::Kind Delta32, + Edge::Kind Delta64, Edge::Kind NegDelta32) : EHFrameSectionName(EHFrameSectionName), PointerSize(PointerSize), - Delta64(Delta64), Delta32(Delta32), NegDelta32(NegDelta32) {} + Pointer32(Pointer32), Pointer64(Pointer64), Delta32(Delta32), + Delta64(Delta64), NegDelta32(NegDelta32) {} Error EHFrameEdgeFixer::operator()(LinkGraph &G) { auto *EHFrame = G.findSectionByName(EHFrameSectionName); @@ -147,7 +52,16 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) { // Build a map of all blocks and symbols in the text sections. We will use // these for finding / building edge targets when processing FDEs. for (auto &Sec : G.sections()) { - PC.AddrToSyms.addSymbols(Sec.symbols()); + // Just record the most-canonical symbol (for eh-frame purposes) at each + // address. + for (auto *Sym : Sec.symbols()) { + auto &CurSym = PC.AddrToSym[Sym->getAddress()]; + if (!CurSym || (std::make_tuple(Sym->getLinkage(), Sym->getScope(), + !Sym->hasName(), Sym->getName()) < + std::make_tuple(CurSym->getLinkage(), CurSym->getScope(), + !CurSym->hasName(), CurSym->getName()))) + CurSym = Sym; + } if (auto Err = PC.AddrToBlock.addBlocks(Sec.blocks(), BlockAddressMap::includeNonNull)) return Err; @@ -172,10 +86,7 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) { Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { - LLVM_DEBUG({ - dbgs() << " Processing block at " << formatv("{0:x16}", B.getAddress()) - << "\n"; - }); + LLVM_DEBUG(dbgs() << " Processing block at " << B.getAddress() << "\n"); // eh-frame should not contain zero-fill blocks. if (B.isZeroFill()) @@ -209,7 +120,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { LLVM_DEBUG({ dbgs() << " Processing CFI record at " - << formatv("{0:x16}", B.getAddress() + RecordStartOffset) << "\n"; + << (B.getAddress() + RecordStartOffset) << "\n"; }); // Get the record length. @@ -244,7 +155,7 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { if (CIEDelta == 0) { if (auto Err = processCIE(PC, B, RecordStartOffset, CIEDeltaFieldOffset + RecordRemaining, - CIEDeltaFieldOffset)) + CIEDeltaFieldOffset, BlockEdges)) return Err; } else { if (auto Err = processFDE(PC, B, RecordStartOffset, @@ -263,7 +174,8 @@ Error EHFrameEdgeFixer::processBlock(ParseContext &PC, Block &B) { Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B, size_t RecordOffset, size_t RecordLength, - size_t CIEDeltaFieldOffset) { + size_t CIEDeltaFieldOffset, + const BlockEdgeMap &BlockEdges) { LLVM_DEBUG(dbgs() << " Record is CIE\n"); @@ -301,10 +213,6 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B, uint64_t CodeAlignmentFactor = 0; if (auto Err = RecordReader.readULEB128(CodeAlignmentFactor)) return Err; - if (CodeAlignmentFactor != 1) - return make_error<JITLinkError>("Unsupported CIE code alignment factor " + - Twine(CodeAlignmentFactor) + - " (expected 1)"); } // Read and validate the data alignment factor. @@ -312,76 +220,65 @@ Error EHFrameEdgeFixer::processCIE(ParseContext &PC, Block &B, int64_t DataAlignmentFactor = 0; if (auto Err = RecordReader.readSLEB128(DataAlignmentFactor)) return Err; - if (DataAlignmentFactor != -8) - return make_error<JITLinkError>("Unsupported CIE data alignment factor " + - Twine(DataAlignmentFactor) + - " (expected -8)"); } // Skip the return address register field. if (auto Err = RecordReader.skip(1)) return Err; - uint64_t AugmentationDataLength = 0; - if (auto Err = RecordReader.readULEB128(AugmentationDataLength)) - return Err; + if (AugInfo->AugmentationDataPresent) { - uint32_t AugmentationDataStartOffset = RecordReader.getOffset(); + CIEInfo.AugmentationDataPresent = true; - uint8_t *NextField = &AugInfo->Fields[0]; - while (uint8_t Field = *NextField++) { - switch (Field) { - case 'L': { - CIEInfo.FDEsHaveLSDAField = true; - uint8_t LSDAPointerEncoding; - if (auto Err = RecordReader.readInteger(LSDAPointerEncoding)) - return Err; - if (!isSupportedPointerEncoding(LSDAPointerEncoding)) - return make_error<JITLinkError>( - "Unsupported LSDA pointer encoding " + - formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " + - formatv("{0:x16}", CIESymbol.getAddress())); - CIEInfo.LSDAPointerEncoding = LSDAPointerEncoding; - break; - } - case 'P': { - uint8_t PersonalityPointerEncoding = 0; - if (auto Err = RecordReader.readInteger(PersonalityPointerEncoding)) - return Err; - if (PersonalityPointerEncoding != - (dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | - dwarf::DW_EH_PE_sdata4)) - return make_error<JITLinkError>( - "Unspported personality pointer " - "encoding " + - formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " + - formatv("{0:x16}", CIESymbol.getAddress())); - uint32_t PersonalityPointerAddress; - if (auto Err = RecordReader.readInteger(PersonalityPointerAddress)) - return Err; - break; - } - case 'R': { - uint8_t FDEPointerEncoding; - if (auto Err = RecordReader.readInteger(FDEPointerEncoding)) - return Err; - if (!isSupportedPointerEncoding(FDEPointerEncoding)) - return make_error<JITLinkError>( - "Unsupported FDE pointer encoding " + - formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " + - formatv("{0:x16}", CIESymbol.getAddress())); - CIEInfo.FDEPointerEncoding = FDEPointerEncoding; - break; - } - default: - llvm_unreachable("Invalid augmentation string field"); + uint64_t AugmentationDataLength = 0; + if (auto Err = RecordReader.readULEB128(AugmentationDataLength)) + return Err; + + uint32_t AugmentationDataStartOffset = RecordReader.getOffset(); + + uint8_t *NextField = &AugInfo->Fields[0]; + while (uint8_t Field = *NextField++) { + switch (Field) { + case 'L': + CIEInfo.LSDAPresent = true; + if (auto PE = readPointerEncoding(RecordReader, B, "LSDA")) + CIEInfo.LSDAEncoding = *PE; + else + return PE.takeError(); + break; + case 'P': { + auto PersonalityPointerEncoding = + readPointerEncoding(RecordReader, B, "personality"); + if (!PersonalityPointerEncoding) + return PersonalityPointerEncoding.takeError(); + if (auto Err = + getOrCreateEncodedPointerEdge( + PC, BlockEdges, *PersonalityPointerEncoding, RecordReader, + B, RecordOffset + RecordReader.getOffset(), "personality") + .takeError()) + return Err; + break; + } + case 'R': + if (auto PE = readPointerEncoding(RecordReader, B, "address")) { + CIEInfo.AddressEncoding = *PE; + if (CIEInfo.AddressEncoding == dwarf::DW_EH_PE_omit) + return make_error<JITLinkError>( + "Invalid address encoding DW_EH_PE_omit in CIE at " + + formatv("{0:x}", (B.getAddress() + RecordOffset).getValue())); + } else + return PE.takeError(); + break; + default: + llvm_unreachable("Invalid augmentation string field"); + } } - } - if (RecordReader.getOffset() - AugmentationDataStartOffset > - AugmentationDataLength) - return make_error<JITLinkError>("Read past the end of the augmentation " - "data while parsing fields"); + if (RecordReader.getOffset() - AugmentationDataStartOffset > + AugmentationDataLength) + return make_error<JITLinkError>("Read past the end of the augmentation " + "data while parsing fields"); + } assert(!PC.CIEInfos.count(CIESymbol.getAddress()) && "Multiple CIEs recorded at the same address?"); @@ -394,7 +291,7 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, size_t RecordOffset, size_t RecordLength, size_t CIEDeltaFieldOffset, uint32_t CIEDelta, - BlockEdgeMap &BlockEdges) { + const BlockEdgeMap &BlockEdges) { LLVM_DEBUG(dbgs() << " Record is FDE\n"); orc::ExecutorAddr RecordAddress = B.getAddress() + RecordOffset; @@ -422,8 +319,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, LLVM_DEBUG({ dbgs() << " Adding edge at " - << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) - << " to CIE at: " << formatv("{0:x16}", CIEAddress) << "\n"; + << (RecordAddress + CIEDeltaFieldOffset) + << " to CIE at: " << CIEAddress << "\n"; }); if (auto CIEInfoOrErr = PC.findCIEInfo(CIEAddress)) CIEInfo = *CIEInfoOrErr; @@ -435,8 +332,8 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, } else { LLVM_DEBUG({ dbgs() << " Already has edge at " - << formatv("{0:x16}", RecordAddress + CIEDeltaFieldOffset) - << " to CIE at " << formatv("{0:x16}", CIEAddress) << "\n"; + << (RecordAddress + CIEDeltaFieldOffset) << " to CIE at " + << CIEAddress << "\n"; }); auto &EI = CIEEdgeItr->second; if (EI.Addend) @@ -451,107 +348,41 @@ Error EHFrameEdgeFixer::processFDE(ParseContext &PC, Block &B, } } - { - // Process the PC-Begin field. - Block *PCBeginBlock = nullptr; - orc::ExecutorAddrDiff PCBeginFieldOffset = RecordReader.getOffset(); - auto PCEdgeItr = BlockEdges.find(RecordOffset + PCBeginFieldOffset); - if (PCEdgeItr == BlockEdges.end()) { - auto PCBeginPtrInfo = - readEncodedPointer(CIEInfo->FDEPointerEncoding, - RecordAddress + PCBeginFieldOffset, RecordReader); - if (!PCBeginPtrInfo) - return PCBeginPtrInfo.takeError(); - orc::ExecutorAddr PCBegin = PCBeginPtrInfo->first; - Edge::Kind PCBeginEdgeKind = PCBeginPtrInfo->second; - LLVM_DEBUG({ - dbgs() << " Adding edge at " - << (RecordAddress + PCBeginFieldOffset) << " to PC at " - << formatv("{0:x16}", PCBegin) << "\n"; - }); - auto PCBeginSym = getOrCreateSymbol(PC, PCBegin); - if (!PCBeginSym) - return PCBeginSym.takeError(); - B.addEdge(PCBeginEdgeKind, RecordOffset + PCBeginFieldOffset, *PCBeginSym, - 0); - PCBeginBlock = &PCBeginSym->getBlock(); - } else { - auto &EI = PCEdgeItr->second; - LLVM_DEBUG({ - dbgs() << " Already has edge at " - << formatv("{0:x16}", RecordAddress + PCBeginFieldOffset) - << " to PC at " << formatv("{0:x16}", EI.Target->getAddress()); - if (EI.Addend) - dbgs() << " + " << formatv("{0:x16}", EI.Addend); - dbgs() << "\n"; - }); - - // Make sure the existing edge points at a defined block. - if (!EI.Target->isDefined()) { - auto EdgeAddr = RecordAddress + PCBeginFieldOffset; - return make_error<JITLinkError>("FDE edge at " + - formatv("{0:x16}", EdgeAddr) + - " points at external block"); - } - PCBeginBlock = &EI.Target->getBlock(); - if (auto Err = RecordReader.skip( - getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding))) - return Err; - } - + // Process the PC-Begin field. + LLVM_DEBUG({ + dbgs() << " Processing PC-begin at " + << (RecordAddress + RecordReader.getOffset()) << "\n"; + }); + if (auto PCBegin = getOrCreateEncodedPointerEdge( + PC, BlockEdges, CIEInfo->AddressEncoding, RecordReader, B, + RecordReader.getOffset(), "PC begin")) { + assert(*PCBegin && "PC-begin symbol not set"); // Add a keep-alive edge from the FDE target to the FDE to ensure that the // FDE is kept alive if its target is. - assert(PCBeginBlock && "PC-begin block not recorded"); LLVM_DEBUG({ dbgs() << " Adding keep-alive edge from target at " - << formatv("{0:x16}", PCBeginBlock->getAddress()) << " to FDE at " - << formatv("{0:x16}", RecordAddress) << "\n"; + << (*PCBegin)->getBlock().getAddress() << " to FDE at " + << RecordAddress << "\n"; }); - PCBeginBlock->addEdge(Edge::KeepAlive, 0, FDESymbol, 0); - } + (*PCBegin)->getBlock().addEdge(Edge::KeepAlive, 0, FDESymbol, 0); + } else + return PCBegin.takeError(); // Skip over the PC range size field. - if (auto Err = RecordReader.skip( - getPointerEncodingDataSize(CIEInfo->FDEPointerEncoding))) + if (auto Err = skipEncodedPointer(CIEInfo->AddressEncoding, RecordReader)) return Err; - if (CIEInfo->FDEsHaveLSDAField) { + if (CIEInfo->AugmentationDataPresent) { uint64_t AugmentationDataSize; if (auto Err = RecordReader.readULEB128(AugmentationDataSize)) return Err; - orc::ExecutorAddrDiff LSDAFieldOffset = RecordReader.getOffset(); - auto LSDAEdgeItr = BlockEdges.find(RecordOffset + LSDAFieldOffset); - if (LSDAEdgeItr == BlockEdges.end()) { - auto LSDAPointerInfo = - readEncodedPointer(CIEInfo->LSDAPointerEncoding, - RecordAddress + LSDAFieldOffset, RecordReader); - if (!LSDAPointerInfo) - return LSDAPointerInfo.takeError(); - orc::ExecutorAddr LSDA = LSDAPointerInfo->first; - Edge::Kind LSDAEdgeKind = LSDAPointerInfo->second; - auto LSDASym = getOrCreateSymbol(PC, LSDA); - if (!LSDASym) - return LSDASym.takeError(); - LLVM_DEBUG({ - dbgs() << " Adding edge at " - << formatv("{0:x16}", RecordAddress + LSDAFieldOffset) - << " to LSDA at " << formatv("{0:x16}", LSDA) << "\n"; - }); - B.addEdge(LSDAEdgeKind, RecordOffset + LSDAFieldOffset, *LSDASym, 0); - } else { - LLVM_DEBUG({ - auto &EI = LSDAEdgeItr->second; - dbgs() << " Already has edge at " - << formatv("{0:x16}", RecordAddress + LSDAFieldOffset) - << " to LSDA at " << formatv("{0:x16}", EI.Target->getAddress()); - if (EI.Addend) - dbgs() << " + " << formatv("{0:x16}", EI.Addend); - dbgs() << "\n"; - }); - if (auto Err = RecordReader.skip(AugmentationDataSize)) + if (CIEInfo->LSDAPresent) + if (auto Err = getOrCreateEncodedPointerEdge( + PC, BlockEdges, CIEInfo->LSDAEncoding, RecordReader, B, + RecordReader.getOffset(), "LSDA") + .takeError()) return Err; - } } else { LLVM_DEBUG(dbgs() << " Record does not have LSDA field.\n"); } @@ -600,129 +431,163 @@ EHFrameEdgeFixer::parseAugmentationString(BinaryStreamReader &RecordReader) { return std::move(AugInfo); } -bool EHFrameEdgeFixer::isSupportedPointerEncoding(uint8_t PointerEncoding) { +Expected<uint8_t> EHFrameEdgeFixer::readPointerEncoding(BinaryStreamReader &R, + Block &InBlock, + const char *FieldName) { using namespace dwarf; - // We only support PC-rel for now. - if ((PointerEncoding & 0x70) != DW_EH_PE_pcrel) - return false; - - // readEncodedPointer does not handle indirect. - if (PointerEncoding & DW_EH_PE_indirect) - return false; + uint8_t PointerEncoding; + if (auto Err = R.readInteger(PointerEncoding)) + return std::move(Err); - // Supported datatypes. + bool Supported = true; switch (PointerEncoding & 0xf) { - case DW_EH_PE_absptr: - case DW_EH_PE_udata4: - case DW_EH_PE_udata8: - case DW_EH_PE_sdata4: - case DW_EH_PE_sdata8: - return true; + case DW_EH_PE_uleb128: + case DW_EH_PE_udata2: + case DW_EH_PE_sleb128: + case DW_EH_PE_sdata2: + Supported = false; + break; + } + if (Supported) { + switch (PointerEncoding & 0x70) { + case DW_EH_PE_textrel: + case DW_EH_PE_datarel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + Supported = false; + break; + } } - return false; + if (Supported) + return PointerEncoding; + + return make_error<JITLinkError>("Unsupported pointer encoding " + + formatv("{0:x2}", PointerEncoding) + " for " + + FieldName + "in CFI record at " + + formatv("{0:x16}", InBlock.getAddress())); } -unsigned EHFrameEdgeFixer::getPointerEncodingDataSize(uint8_t PointerEncoding) { +Error EHFrameEdgeFixer::skipEncodedPointer(uint8_t PointerEncoding, + BinaryStreamReader &RecordReader) { using namespace dwarf; - assert(isSupportedPointerEncoding(PointerEncoding) && - "Unsupported pointer encoding"); + // Switch absptr to corresponding udata encoding. + if ((PointerEncoding & 0xf) == DW_EH_PE_absptr) + PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; + switch (PointerEncoding & 0xf) { - case DW_EH_PE_absptr: - return PointerSize; case DW_EH_PE_udata4: case DW_EH_PE_sdata4: - return 4; + if (auto Err = RecordReader.skip(4)) + return Err; + break; case DW_EH_PE_udata8: case DW_EH_PE_sdata8: - return 8; + if (auto Err = RecordReader.skip(8)) + return Err; + break; default: - llvm_unreachable("Unsupported encoding"); + llvm_unreachable("Unrecognized encoding"); } + return Error::success(); } -Expected<std::pair<orc::ExecutorAddr, Edge::Kind>> -EHFrameEdgeFixer::readEncodedPointer(uint8_t PointerEncoding, - orc::ExecutorAddr PointerFieldAddress, - BinaryStreamReader &RecordReader) { - assert(isSupportedPointerEncoding(PointerEncoding) && - "Unsupported pointer encoding"); - +Expected<Symbol *> EHFrameEdgeFixer::getOrCreateEncodedPointerEdge( + ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding, + BinaryStreamReader &RecordReader, Block &BlockToFix, + size_t PointerFieldOffset, const char *FieldName) { using namespace dwarf; - // Isolate data type, remap absptr to udata4 or udata8. This relies on us - // having verified that the graph uses 32-bit or 64-bit pointers only at the - // start of this pass. - uint8_t EffectiveType = PointerEncoding & 0xf; - if (EffectiveType == DW_EH_PE_absptr) - EffectiveType = (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; + if (PointerEncoding == DW_EH_PE_omit) + return nullptr; - orc::ExecutorAddr Addr; - Edge::Kind PointerEdgeKind = Edge::Invalid; - switch (EffectiveType) { + // If there's already an edge here then just skip the encoded pointer and + // return the edge's target. + { + auto EdgeI = BlockEdges.find(PointerFieldOffset); + if (EdgeI != BlockEdges.end()) { + LLVM_DEBUG({ + dbgs() << " Existing edge at " + << (BlockToFix.getAddress() + PointerFieldOffset) << " to " + << FieldName << " at " << EdgeI->second.Target->getAddress(); + if (EdgeI->second.Target->hasName()) + dbgs() << " (" << EdgeI->second.Target->getName() << ")"; + dbgs() << "\n"; + }); + if (auto Err = skipEncodedPointer(PointerEncoding, RecordReader)) + return std::move(Err); + return EdgeI->second.Target; + } + } + + // Switch absptr to corresponding udata encoding. + if ((PointerEncoding & 0xf) == DW_EH_PE_absptr) + PointerEncoding |= (PointerSize == 8) ? DW_EH_PE_udata8 : DW_EH_PE_udata4; + + // We need to create an edge. Start by reading the field value. + uint64_t FieldValue; + bool Is64Bit = false; + switch (PointerEncoding & 0xf) { case DW_EH_PE_udata4: { uint32_t Val; if (auto Err = RecordReader.readInteger(Val)) return std::move(Err); - Addr = PointerFieldAddress + Val; - PointerEdgeKind = Delta32; - break; - } - case DW_EH_PE_udata8: { - uint64_t Val; - if (auto Err = RecordReader.readInteger(Val)) - return std::move(Err); - Addr = PointerFieldAddress + Val; - PointerEdgeKind = Delta64; + FieldValue = Val; break; } case DW_EH_PE_sdata4: { - int32_t Val; + uint32_t Val; if (auto Err = RecordReader.readInteger(Val)) return std::move(Err); - Addr = PointerFieldAddress + Val; - PointerEdgeKind = Delta32; + FieldValue = Val; break; } - case DW_EH_PE_sdata8: { - int64_t Val; - if (auto Err = RecordReader.readInteger(Val)) + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + Is64Bit = true; + if (auto Err = RecordReader.readInteger(FieldValue)) return std::move(Err); - Addr = PointerFieldAddress + Val; - PointerEdgeKind = Delta64; break; - } + default: + llvm_unreachable("Unsupported encoding"); } - if (PointerEdgeKind == Edge::Invalid) - return make_error<JITLinkError>( - "Unspported edge kind for encoded pointer at " + - formatv("{0:x}", PointerFieldAddress)); + // Find the edge target and edge kind to use. + orc::ExecutorAddr Target; + Edge::Kind PtrEdgeKind = Edge::Invalid; + if ((PointerEncoding & 0x70) == DW_EH_PE_pcrel) { + Target = BlockToFix.getAddress() + PointerFieldOffset; + PtrEdgeKind = Is64Bit ? Delta64 : Delta32; + } else + PtrEdgeKind = Is64Bit ? Pointer64 : Pointer32; + Target += FieldValue; + + // Find or create a symbol to point the edge at. + auto TargetSym = getOrCreateSymbol(PC, Target); + if (!TargetSym) + return TargetSym.takeError(); + BlockToFix.addEdge(PtrEdgeKind, PointerFieldOffset, *TargetSym, 0); + + LLVM_DEBUG({ + dbgs() << " Adding edge at " + << (BlockToFix.getAddress() + PointerFieldOffset) << " to " + << FieldName << " at " << TargetSym->getAddress(); + if (TargetSym->hasName()) + dbgs() << " (" << TargetSym->getName() << ")"; + dbgs() << "\n"; + }); - return std::make_pair(Addr, Delta64); + return &*TargetSym; } Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC, orc::ExecutorAddr Addr) { - Symbol *CanonicalSym = nullptr; - - auto UpdateCanonicalSym = [&](Symbol *Sym) { - if (!CanonicalSym || Sym->getLinkage() < CanonicalSym->getLinkage() || - Sym->getScope() < CanonicalSym->getScope() || - (Sym->hasName() && !CanonicalSym->hasName()) || - Sym->getName() < CanonicalSym->getName()) - CanonicalSym = Sym; - }; - - if (auto *SymbolsAtAddr = PC.AddrToSyms.getSymbolsAt(Addr)) - for (auto *Sym : *SymbolsAtAddr) - UpdateCanonicalSym(Sym); - - // If we found an existing symbol at the given address then use it. - if (CanonicalSym) - return *CanonicalSym; + // See whether we have a canonical symbol for the given address already. + auto CanonicalSymI = PC.AddrToSym.find(Addr); + if (CanonicalSymI != PC.AddrToSym.end()) + return *CanonicalSymI->second; // Otherwise search for a block covering the address and create a new symbol. auto *B = PC.AddrToBlock.getBlockCovering(Addr); @@ -730,7 +595,10 @@ Expected<Symbol &> EHFrameEdgeFixer::getOrCreateSymbol(ParseContext &PC, return make_error<JITLinkError>("No symbol or block covering address " + formatv("{0:x16}", Addr)); - return PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false); + auto &S = + PC.G.addAnonymousSymbol(*B, Addr - B->getAddress(), 0, false, false); + PC.AddrToSym[S.getAddress()] = &S; + return S; } char EHFrameNullTerminator::NullTerminatorBlockContent[4] = {0, 0, 0, 0}; @@ -756,7 +624,7 @@ Error EHFrameNullTerminator::operator()(LinkGraph &G) { return Error::success(); } -EHFrameRegistrar::~EHFrameRegistrar() {} +EHFrameRegistrar::~EHFrameRegistrar() = default; Error InProcessEHFrameRegistrar::registerEHFrames( orc::ExecutorAddrRange EHFrameSection) { diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h index ef4b47b9aa28..55cf7fc63ee7 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupportImpl.h @@ -21,27 +21,16 @@ namespace llvm { namespace jitlink { -/// A LinkGraph pass that splits blocks in an eh-frame section into sub-blocks -/// representing individual eh-frames. -/// EHFrameSplitter should not be run without EHFrameEdgeFixer, which is -/// responsible for adding FDE-to-CIE edges. -class EHFrameSplitter { -public: - EHFrameSplitter(StringRef EHFrameSectionName); - Error operator()(LinkGraph &G); - -private: - Error processBlock(LinkGraph &G, Block &B, LinkGraph::SplitBlockCache &Cache); - - StringRef EHFrameSectionName; -}; - /// A LinkGraph pass that adds missing FDE-to-CIE, FDE-to-PC and FDE-to-LSDA /// edges. class EHFrameEdgeFixer { public: + /// Create an eh-frame edge fixer. + /// If a given edge-kind is not supported on the target architecture then + /// Edge::Invalid should be used. EHFrameEdgeFixer(StringRef EHFrameSectionName, unsigned PointerSize, - Edge::Kind Delta64, Edge::Kind Delta32, + Edge::Kind Pointer32, Edge::Kind Pointer64, + Edge::Kind Delta32, Edge::Kind Delta64, Edge::Kind NegDelta32); Error operator()(LinkGraph &G); @@ -57,9 +46,10 @@ private: CIEInformation() = default; CIEInformation(Symbol &CIESymbol) : CIESymbol(&CIESymbol) {} Symbol *CIESymbol = nullptr; - bool FDEsHaveLSDAField = false; - uint8_t FDEPointerEncoding = 0; - uint8_t LSDAPointerEncoding = 0; + bool AugmentationDataPresent = false; + bool LSDAPresent = false; + uint8_t LSDAEncoding = 0; + uint8_t AddressEncoding = 0; }; struct EdgeTarget { @@ -87,33 +77,38 @@ private: LinkGraph &G; CIEInfosMap CIEInfos; BlockAddressMap AddrToBlock; - SymbolAddressMap AddrToSyms; + DenseMap<orc::ExecutorAddr, Symbol *> AddrToSym; }; Error processBlock(ParseContext &PC, Block &B); Error processCIE(ParseContext &PC, Block &B, size_t RecordOffset, - size_t RecordLength, size_t CIEDeltaFieldOffset); + size_t RecordLength, size_t CIEDeltaFieldOffset, + const BlockEdgeMap &BlockEdges); Error processFDE(ParseContext &PC, Block &B, size_t RecordOffset, size_t RecordLength, size_t CIEDeltaFieldOffset, - uint32_t CIEDelta, BlockEdgeMap &BlockEdges); + uint32_t CIEDelta, const BlockEdgeMap &BlockEdges); Expected<AugmentationInfo> parseAugmentationString(BinaryStreamReader &RecordReader); - static bool isSupportedPointerEncoding(uint8_t PointerEncoding); - unsigned getPointerEncodingDataSize(uint8_t PointerEncoding); - Expected<std::pair<orc::ExecutorAddr, Edge::Kind>> - readEncodedPointer(uint8_t PointerEncoding, - orc::ExecutorAddr PointerFieldAddress, - BinaryStreamReader &RecordReader); + Expected<uint8_t> readPointerEncoding(BinaryStreamReader &RecordReader, + Block &InBlock, const char *FieldName); + Error skipEncodedPointer(uint8_t PointerEncoding, + BinaryStreamReader &RecordReader); + Expected<Symbol *> getOrCreateEncodedPointerEdge( + ParseContext &PC, const BlockEdgeMap &BlockEdges, uint8_t PointerEncoding, + BinaryStreamReader &RecordReader, Block &BlockToFix, + size_t PointerFieldOffset, const char *FieldName); Expected<Symbol &> getOrCreateSymbol(ParseContext &PC, orc::ExecutorAddr Addr); StringRef EHFrameSectionName; unsigned PointerSize; - Edge::Kind Delta64; + Edge::Kind Pointer32; + Edge::Kind Pointer64; Edge::Kind Delta32; + Edge::Kind Delta64; Edge::Kind NegDelta32; }; diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp index 2194a4fbf1f4..5a983c219627 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp @@ -27,7 +27,7 @@ namespace jitlink { StringRef ELFLinkGraphBuilderBase::CommonSectionName(".common"); ArrayRef<const char *> ELFLinkGraphBuilderBase::DwarfSectionNames = DWSecNames; -ELFLinkGraphBuilderBase::~ELFLinkGraphBuilderBase() {} +ELFLinkGraphBuilderBase::~ELFLinkGraphBuilderBase() = default; } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp index dd3eb97c21a0..98da3f155c3e 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp @@ -11,20 +11,21 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/ELF_aarch64.h" +#include "EHFrameSupportImpl.h" #include "ELFLinkGraphBuilder.h" #include "JITLinkGeneric.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/aarch64.h" #include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Endian.h" #define DEBUG_TYPE "jitlink" using namespace llvm; using namespace llvm::jitlink; -namespace llvm { -namespace jitlink { +namespace { class ELFJITLinker_aarch64 : public JITLinker<ELFJITLinker_aarch64> { friend class JITLinker<ELFJITLinker_aarch64>; @@ -37,50 +38,77 @@ public: private: Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { - using namespace aarch64; - using namespace llvm::support; - - char *BlockWorkingMem = B.getAlreadyMutableContent().data(); - char *FixupPtr = BlockWorkingMem + E.getOffset(); - auto FixupAddress = B.getAddress() + E.getOffset(); - switch (E.getKind()) { - case aarch64::R_AARCH64_CALL26: { - assert((FixupAddress.getValue() & 0x3) == 0 && - "Call-inst is not 32-bit aligned"); - int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); - - if (static_cast<uint64_t>(Value) & 0x3) - return make_error<JITLinkError>("Call target is not 32-bit aligned"); - - if (!isInt<28>(Value)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - assert((RawInstr & 0x7fffffff) == 0x14000000 && - "RawInstr isn't a B or BR immediate instruction"); - uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2; - uint32_t FixedInstr = RawInstr | Imm; - *(little32_t *)FixupPtr = FixedInstr; - break; - } - } - return Error::success(); + return aarch64::applyFixup(G, B, E); } }; template <typename ELFT> class ELFLinkGraphBuilder_aarch64 : public ELFLinkGraphBuilder<ELFT> { private: - static Expected<aarch64::EdgeKind_aarch64> + enum ELFAArch64RelocationKind : Edge::Kind { + ELFCall26 = Edge::FirstRelocation, + ELFAdrPage21, + ELFAddAbs12, + ELFLdSt8Abs12, + ELFLdSt16Abs12, + ELFLdSt32Abs12, + ELFLdSt64Abs12, + ELFLdSt128Abs12, + ELFMovwAbsG0, + ELFMovwAbsG1, + ELFMovwAbsG2, + ELFMovwAbsG3, + ELFAbs64, + ELFPrel32, + ELFPrel64, + ELFAdrGOTPage21, + ELFLd64GOTLo12, + }; + + static Expected<ELFAArch64RelocationKind> getRelocationKind(const uint32_t Type) { using namespace aarch64; switch (Type) { case ELF::R_AARCH64_CALL26: - return EdgeKind_aarch64::R_AARCH64_CALL26; + case ELF::R_AARCH64_JUMP26: + return ELFCall26; + case ELF::R_AARCH64_ADR_PREL_PG_HI21: + return ELFAdrPage21; + case ELF::R_AARCH64_ADD_ABS_LO12_NC: + return ELFAddAbs12; + case ELF::R_AARCH64_LDST8_ABS_LO12_NC: + return ELFLdSt8Abs12; + case ELF::R_AARCH64_LDST16_ABS_LO12_NC: + return ELFLdSt16Abs12; + case ELF::R_AARCH64_LDST32_ABS_LO12_NC: + return ELFLdSt32Abs12; + case ELF::R_AARCH64_LDST64_ABS_LO12_NC: + return ELFLdSt64Abs12; + case ELF::R_AARCH64_LDST128_ABS_LO12_NC: + return ELFLdSt128Abs12; + case ELF::R_AARCH64_MOVW_UABS_G0_NC: + return ELFMovwAbsG0; + case ELF::R_AARCH64_MOVW_UABS_G1_NC: + return ELFMovwAbsG1; + case ELF::R_AARCH64_MOVW_UABS_G2_NC: + return ELFMovwAbsG2; + case ELF::R_AARCH64_MOVW_UABS_G3: + return ELFMovwAbsG3; + case ELF::R_AARCH64_ABS64: + return ELFAbs64; + case ELF::R_AARCH64_PREL32: + return ELFPrel32; + case ELF::R_AARCH64_PREL64: + return ELFPrel64; + case ELF::R_AARCH64_ADR_GOT_PAGE: + return ELFAdrGOTPage21; + case ELF::R_AARCH64_LD64_GOT_LO12_NC: + return ELFLd64GOTLo12; } - return make_error<JITLinkError>("Unsupported aarch64 relocation:" + - formatv("{0:d}", Type)); + return make_error<JITLinkError>( + "Unsupported aarch64 relocation:" + formatv("{0:d}: ", Type) + + object::getELFRelocationTypeName(ELF::EM_AARCH64, Type)); } Error addRelocations() override { @@ -99,6 +127,7 @@ private: Error addSingleRelocation(const typename ELFT::Rela &Rel, const typename ELFT::Shdr &FixupSect, Block &BlockToFix) { + using support::ulittle32_t; using Base = ELFLinkGraphBuilder<ELFT>; uint32_t SymbolIndex = Rel.getSymbol(false); @@ -116,18 +145,159 @@ private: inconvertibleErrorCode()); uint32_t Type = Rel.getType(false); - Expected<aarch64::EdgeKind_aarch64> Kind = getRelocationKind(Type); - if (!Kind) - return Kind.takeError(); + Expected<ELFAArch64RelocationKind> RelocKind = getRelocationKind(Type); + if (!RelocKind) + return RelocKind.takeError(); int64_t Addend = Rel.r_addend; orc::ExecutorAddr FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); - Edge GE(*Kind, Offset, *GraphSymbol, Addend); + + // Get a pointer to the fixup content. + const void *FixupContent = BlockToFix.getContent().data() + + (FixupAddress - BlockToFix.getAddress()); + + Edge::Kind Kind = Edge::Invalid; + + switch (*RelocKind) { + case ELFCall26: { + Kind = aarch64::Branch26; + break; + } + case ELFAdrPage21: { + Kind = aarch64::Page21; + break; + } + case ELFAddAbs12: { + Kind = aarch64::PageOffset12; + break; + } + case ELFLdSt8Abs12: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isLoadStoreImm12(Instr) || + aarch64::getPageOffset12Shift(Instr) != 0) + return make_error<JITLinkError>( + "R_AARCH64_LDST8_ABS_LO12_NC target is not a " + "LDRB/STRB (imm12) instruction"); + + Kind = aarch64::PageOffset12; + break; + } + case ELFLdSt16Abs12: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isLoadStoreImm12(Instr) || + aarch64::getPageOffset12Shift(Instr) != 1) + return make_error<JITLinkError>( + "R_AARCH64_LDST16_ABS_LO12_NC target is not a " + "LDRH/STRH (imm12) instruction"); + + Kind = aarch64::PageOffset12; + break; + } + case ELFLdSt32Abs12: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isLoadStoreImm12(Instr) || + aarch64::getPageOffset12Shift(Instr) != 2) + return make_error<JITLinkError>( + "R_AARCH64_LDST32_ABS_LO12_NC target is not a " + "LDR/STR (imm12, 32 bit) instruction"); + + Kind = aarch64::PageOffset12; + break; + } + case ELFLdSt64Abs12: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isLoadStoreImm12(Instr) || + aarch64::getPageOffset12Shift(Instr) != 3) + return make_error<JITLinkError>( + "R_AARCH64_LDST64_ABS_LO12_NC target is not a " + "LDR/STR (imm12, 64 bit) instruction"); + + Kind = aarch64::PageOffset12; + break; + } + case ELFLdSt128Abs12: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isLoadStoreImm12(Instr) || + aarch64::getPageOffset12Shift(Instr) != 4) + return make_error<JITLinkError>( + "R_AARCH64_LDST128_ABS_LO12_NC target is not a " + "LDR/STR (imm12, 128 bit) instruction"); + + Kind = aarch64::PageOffset12; + break; + } + case ELFMovwAbsG0: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isMoveWideImm16(Instr) || + aarch64::getMoveWide16Shift(Instr) != 0) + return make_error<JITLinkError>( + "R_AARCH64_MOVW_UABS_G0_NC target is not a " + "MOVK/MOVZ (imm16, LSL #0) instruction"); + + Kind = aarch64::MoveWide16; + break; + } + case ELFMovwAbsG1: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isMoveWideImm16(Instr) || + aarch64::getMoveWide16Shift(Instr) != 16) + return make_error<JITLinkError>( + "R_AARCH64_MOVW_UABS_G1_NC target is not a " + "MOVK/MOVZ (imm16, LSL #16) instruction"); + + Kind = aarch64::MoveWide16; + break; + } + case ELFMovwAbsG2: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isMoveWideImm16(Instr) || + aarch64::getMoveWide16Shift(Instr) != 32) + return make_error<JITLinkError>( + "R_AARCH64_MOVW_UABS_G2_NC target is not a " + "MOVK/MOVZ (imm16, LSL #32) instruction"); + + Kind = aarch64::MoveWide16; + break; + } + case ELFMovwAbsG3: { + uint32_t Instr = *(const ulittle32_t *)FixupContent; + if (!aarch64::isMoveWideImm16(Instr) || + aarch64::getMoveWide16Shift(Instr) != 48) + return make_error<JITLinkError>( + "R_AARCH64_MOVW_UABS_G3 target is not a " + "MOVK/MOVZ (imm16, LSL #48) instruction"); + + Kind = aarch64::MoveWide16; + break; + } + case ELFAbs64: { + Kind = aarch64::Pointer64; + break; + } + case ELFPrel32: { + Kind = aarch64::Delta32; + break; + } + case ELFPrel64: { + Kind = aarch64::Delta64; + break; + } + case ELFAdrGOTPage21: { + Kind = aarch64::GOTPage21; + break; + } + case ELFLd64GOTLo12: { + Kind = aarch64::GOTPageOffset12; + break; + } + }; + + Edge GE(Kind, Offset, *GraphSymbol, Addend); LLVM_DEBUG({ dbgs() << " "; - printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(*Kind)); + printEdge(dbgs(), BlockToFix, GE, aarch64::getEdgeKindName(Kind)); dbgs() << "\n"; }); @@ -135,6 +305,48 @@ private: return Error::success(); } + /// Return the string name of the given ELF aarch64 edge kind. + const char *getELFAArch64RelocationKindName(Edge::Kind R) { + switch (R) { + case ELFCall26: + return "ELFCall26"; + case ELFAdrPage21: + return "ELFAdrPage21"; + case ELFAddAbs12: + return "ELFAddAbs12"; + case ELFLdSt8Abs12: + return "ELFLdSt8Abs12"; + case ELFLdSt16Abs12: + return "ELFLdSt16Abs12"; + case ELFLdSt32Abs12: + return "ELFLdSt32Abs12"; + case ELFLdSt64Abs12: + return "ELFLdSt64Abs12"; + case ELFLdSt128Abs12: + return "ELFLdSt128Abs12"; + case ELFMovwAbsG0: + return "ELFMovwAbsG0"; + case ELFMovwAbsG1: + return "ELFMovwAbsG1"; + case ELFMovwAbsG2: + return "ELFMovwAbsG2"; + case ELFMovwAbsG3: + return "ELFMovwAbsG3"; + case ELFAbs64: + return "ELFAbs64"; + case ELFPrel32: + return "ELFPrel32"; + case ELFPrel64: + return "ELFPrel64"; + case ELFAdrGOTPage21: + return "ELFAdrGOTPage21"; + case ELFLd64GOTLo12: + return "ELFLd64GOTLo12"; + default: + return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); + } + } + public: ELFLinkGraphBuilder_aarch64(StringRef FileName, const object::ELFFile<ELFT> &Obj, const Triple T) @@ -142,6 +354,20 @@ public: aarch64::getEdgeKindName) {} }; +Error buildTables_ELF_aarch64(LinkGraph &G) { + LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); + + aarch64::GOTTableManager GOT; + aarch64::PLTTableManager PLT(GOT); + visitExistingEdges(G, GOT, PLT); + return Error::success(); +} + +} // namespace + +namespace llvm { +namespace jitlink { + Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_aarch64(MemoryBufferRef ObjectBuffer) { LLVM_DEBUG({ @@ -168,11 +394,22 @@ void link_ELF_aarch64(std::unique_ptr<LinkGraph> G, PassConfiguration Config; const Triple &TT = G->getTargetTriple(); if (Ctx->shouldAddDefaultTargetPasses(TT)) { + // Add eh-frame passses. + Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); + Config.PrePrunePasses.push_back(EHFrameEdgeFixer( + ".eh_frame", 8, aarch64::Pointer32, aarch64::Pointer64, + aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32)); + + // Add a mark-live pass. if (auto MarkLive = Ctx->getMarkLivePass(TT)) Config.PrePrunePasses.push_back(std::move(MarkLive)); else Config.PrePrunePasses.push_back(markAllSymbolsLive); + + // Add an in-place GOT/Stubs build pass. + Config.PostPrunePasses.push_back(buildTables_ELF_aarch64); } + if (auto Err = Ctx->modifyPassConfig(*G, Config)) return Ctx->notifyFailed(std::move(Err)); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp index f83001417e94..197ab71f5274 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp @@ -160,23 +160,16 @@ static Expected<const Edge &> getRISCVPCRelHi20(const Edge &E) { } static uint32_t extractBits(uint32_t Num, unsigned Low, unsigned Size) { - return (Num & (((1ULL << (Size + 1)) - 1) << Low)) >> Low; + return (Num & (((1ULL << Size) - 1) << Low)) >> Low; } -inline Error checkAlignment(llvm::orc::ExecutorAddr loc, uint64_t v, int n, - const Edge &E) { - if (v & (n - 1)) - return make_error<JITLinkError>("0x" + llvm::utohexstr(loc.getValue()) + - " improper alignment for relocation " + - formatv("{0:d}", E.getKind()) + ": 0x" + - llvm::utohexstr(v) + " is not aligned to " + - Twine(n) + " bytes"); - return Error::success(); +static inline bool isAlignmentCorrect(uint64_t Value, int N) { + return (Value & (N - 1)) ? false : true; } -static inline bool isInRangeForImmS32(int64_t Value) { - return (Value >= std::numeric_limits<int32_t>::min() && - Value <= std::numeric_limits<int32_t>::max()); +// Requires 0 < N <= 64. +static inline bool isInRangeForImm(int64_t Value, int N) { + return Value == llvm::SignExtend64(Value, N); } class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> { @@ -208,23 +201,36 @@ private: } case R_RISCV_BRANCH: { int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; - Error AlignmentIssue = checkAlignment(FixupAddress, Value, 2, E); - if (AlignmentIssue) { - return AlignmentIssue; - } - int64_t Lo = Value & 0xFFF; - uint32_t Imm31_25 = extractBits(Lo, 5, 6) << 25 | extractBits(Lo, 12, 1) - << 31; - uint32_t Imm11_7 = extractBits(Lo, 1, 4) << 8 | extractBits(Lo, 11, 1) - << 7; + if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 12))) + return makeTargetOutOfRangeError(G, B, E); + if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) + return makeAlignmentError(FixupAddress, Value, 2, E); + uint32_t Imm31_25 = + extractBits(Value, 5, 6) << 25 | extractBits(Value, 12, 1) << 31; + uint32_t Imm11_7 = + extractBits(Value, 1, 4) << 8 | extractBits(Value, 11, 1) << 7; uint32_t RawInstr = *(little32_t *)FixupPtr; *(little32_t *)FixupPtr = (RawInstr & 0x1FFF07F) | Imm31_25 | Imm11_7; break; } + case R_RISCV_JAL: { + int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; + if (LLVM_UNLIKELY(!isInRangeForImm(Value >> 1, 20))) + return makeTargetOutOfRangeError(G, B, E); + if (LLVM_UNLIKELY(!isAlignmentCorrect(Value, 2))) + return makeAlignmentError(FixupAddress, Value, 2, E); + uint32_t Imm20 = extractBits(Value, 20, 1) << 31; + uint32_t Imm10_1 = extractBits(Value, 1, 10) << 21; + uint32_t Imm11 = extractBits(Value, 11, 1) << 20; + uint32_t Imm19_12 = extractBits(Value, 12, 8) << 12; + uint32_t RawInstr = *(little32_t *)FixupPtr; + *(little32_t *)FixupPtr = RawInstr | Imm20 | Imm10_1 | Imm11 | Imm19_12; + break; + } case R_RISCV_HI20: { int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); int64_t Hi = Value + 0x800; - if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi))) + if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) return makeTargetOutOfRangeError(G, B, E); uint32_t RawInstr = *(little32_t *)FixupPtr; *(little32_t *)FixupPtr = @@ -244,7 +250,7 @@ private: case R_RISCV_CALL: { int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; int64_t Hi = Value + 0x800; - if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi))) + if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) return makeTargetOutOfRangeError(G, B, E); int32_t Lo = Value & 0xFFF; uint32_t RawInstrAuipc = *(little32_t *)FixupPtr; @@ -258,7 +264,7 @@ private: case R_RISCV_PCREL_HI20: { int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress; int64_t Hi = Value + 0x800; - if (LLVM_UNLIKELY(!isInRangeForImmS32(Hi))) + if (LLVM_UNLIKELY(!isInRangeForImm(Hi, 32))) return makeTargetOutOfRangeError(G, B, E); uint32_t RawInstr = *(little32_t *)FixupPtr; *(little32_t *)FixupPtr = @@ -359,6 +365,13 @@ private: *FixupPtr = static_cast<uint8_t>(Value); break; } + case R_RISCV_SUB6: { + int64_t Value = + *(reinterpret_cast<const uint8_t *>(FixupAddress.getValue())) & 0x3f; + Value -= E.getTarget().getAddress().getValue() - E.getAddend(); + *FixupPtr = (*FixupPtr & 0xc0) | (static_cast<uint8_t>(Value) & 0x3f); + break; + } case R_RISCV_SET6: { int64_t Value = (E.getTarget().getAddress() + E.getAddend()).getValue(); uint32_t RawData = *(little32_t *)FixupPtr; @@ -410,6 +423,8 @@ private: return EdgeKind_riscv::R_RISCV_64; case ELF::R_RISCV_BRANCH: return EdgeKind_riscv::R_RISCV_BRANCH; + case ELF::R_RISCV_JAL: + return EdgeKind_riscv::R_RISCV_JAL; case ELF::R_RISCV_HI20: return EdgeKind_riscv::R_RISCV_HI20; case ELF::R_RISCV_LO12_I: @@ -442,6 +457,8 @@ private: return EdgeKind_riscv::R_RISCV_SUB16; case ELF::R_RISCV_SUB8: return EdgeKind_riscv::R_RISCV_SUB8; + case ELF::R_RISCV_SUB6: + return EdgeKind_riscv::R_RISCV_SUB6; case ELF::R_RISCV_SET6: return EdgeKind_riscv::R_RISCV_SET6; case ELF::R_RISCV_SET8: @@ -454,8 +471,9 @@ private: return EdgeKind_riscv::R_RISCV_32_PCREL; } - return make_error<JITLinkError>("Unsupported riscv relocation:" + - formatv("{0:d}", Type)); + return make_error<JITLinkError>( + "Unsupported riscv relocation:" + formatv("{0:d}: ", Type) + + object::getELFRelocationTypeName(ELF::EM_RISCV, Type)); } Error addRelocations() override { diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp index 79d2cdbb30f1..8f21274bd1a3 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/JITLink/TableManager.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" @@ -96,17 +97,6 @@ Error buildTables_ELF_x86_64(LinkGraph &G) { } } // namespace -static const char *getELFX86_64RelocName(uint32_t Type) { - switch (Type) { -#define ELF_RELOC(Name, Number) \ - case Number: \ - return #Name; -#include "llvm/BinaryFormat/ELFRelocs/x86_64.def" -#undef ELF_RELOC - } - return "Unrecognized ELF/x86-64 relocation type"; -} - namespace llvm { namespace jitlink { @@ -145,9 +135,9 @@ private: case ELF::R_X86_64_TLSGD: return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32TLV; } - return make_error<JITLinkError>("Unsupported x86-64 relocation type " + - formatv("{0:d}: ", Type) + - getELFX86_64RelocName(Type)); + return make_error<JITLinkError>( + "Unsupported x86-64 relocation type " + formatv("{0:d}: ", Type) + + object::getELFRelocationTypeName(ELF::EM_X86_64, Type)); } Error addRelocations() override { @@ -379,10 +369,10 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G, if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { - Config.PrePrunePasses.push_back(EHFrameSplitter(".eh_frame")); - Config.PrePrunePasses.push_back( - EHFrameEdgeFixer(".eh_frame", x86_64::PointerSize, x86_64::Delta64, - x86_64::Delta32, x86_64::NegDelta32)); + Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); + Config.PrePrunePasses.push_back(EHFrameEdgeFixer( + ".eh_frame", x86_64::PointerSize, x86_64::Pointer32, x86_64::Pointer64, + x86_64::Delta32, x86_64::Delta64, x86_64::NegDelta32)); Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); // Construct a JITLinker and run the link function. diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 78a603cfed17..43efe0725cfe 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -336,7 +336,7 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolLookupFlags &LF) { void JITLinkAsyncLookupContinuation::anchor() {} -JITLinkContext::~JITLinkContext() {} +JITLinkContext::~JITLinkContext() = default; bool JITLinkContext::shouldAddDefaultTargetPasses(const Triple &TT) const { return true; @@ -393,6 +393,15 @@ Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B, return make_error<JITLinkError>(std::move(ErrMsg)); } +Error makeAlignmentError(llvm::orc::ExecutorAddr Loc, uint64_t Value, int N, + const Edge &E) { + return make_error<JITLinkError>("0x" + llvm::utohexstr(Loc.getValue()) + + " improper alignment for relocation " + + formatv("{0:d}", E.getKind()) + ": 0x" + + llvm::utohexstr(Value) + + " is not aligned to " + Twine(N) + " bytes"); +} + Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) { auto Magic = identify_magic(ObjectBuffer.getBuffer()); diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp index 35ee050c8566..6d321a080829 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp @@ -20,7 +20,7 @@ namespace llvm { namespace jitlink { -JITLinkerBase::~JITLinkerBase() {} +JITLinkerBase::~JITLinkerBase() = default; void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) { diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp index 9315ac4f6120..acb759d6ce79 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp @@ -211,7 +211,7 @@ SimpleSegmentAlloc::Create(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD, SimpleSegmentAlloc::SimpleSegmentAlloc(SimpleSegmentAlloc &&) = default; SimpleSegmentAlloc & SimpleSegmentAlloc::operator=(SimpleSegmentAlloc &&) = default; -SimpleSegmentAlloc::~SimpleSegmentAlloc() {} +SimpleSegmentAlloc::~SimpleSegmentAlloc() = default; SimpleSegmentAlloc::SegmentInfo SimpleSegmentAlloc::getSegInfo(AllocGroup AG) { auto I = ContentBlocks.find(AG); diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp index 62574604458c..1bf12f438be0 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp @@ -19,7 +19,7 @@ static const char *CommonSectionName = "__common"; namespace llvm { namespace jitlink { -MachOLinkGraphBuilder::~MachOLinkGraphBuilder() {} +MachOLinkGraphBuilder::~MachOLinkGraphBuilder() = default; Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() { @@ -368,7 +368,7 @@ Error MachOLinkGraphBuilder::graphifyRegularSymbols() { Twine(KV.first)); NSym.GraphSymbol = &G->addAbsoluteSymbol( *NSym.Name, orc::ExecutorAddr(NSym.Value), 0, Linkage::Strong, - Scope::Default, NSym.Desc & MachO::N_NO_DEAD_STRIP); + getScope(*NSym.Name, NSym.Type), NSym.Desc & MachO::N_NO_DEAD_STRIP); break; case MachO::N_SECT: SecIndexToSymbols[NSym.Sect - 1].push_back(&NSym); @@ -644,17 +644,27 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( // Scan section for null characters. for (size_t I = 0; I != NSec.Size; ++I) if (NSec.Data[I] == '\0') { - orc::ExecutorAddrDiff BlockEnd = I + 1; - size_t BlockSize = BlockEnd - BlockStart; + size_t BlockSize = I + 1 - BlockStart; // Create a block for this null terminated string. auto &B = G->createContentBlock(*NSec.GraphSection, {NSec.Data + BlockStart, BlockSize}, - NSec.Address + BlockStart, 1, 0); + NSec.Address + BlockStart, NSec.Alignment, + BlockStart % NSec.Alignment); LLVM_DEBUG({ - dbgs() << " Created block " << formatv("{0:x}", B.getAddress()) - << " -- " << formatv("{0:x}", B.getAddress() + B.getSize()) - << " for \"" << StringRef(B.getContent().data()) << "\"\n"; + dbgs() << " Created block " << B.getRange() + << ", align = " << B.getAlignment() + << ", align-ofs = " << B.getAlignmentOffset() << " for \""; + for (size_t J = 0; J != std::min(B.getSize(), size_t(16)); ++J) + switch (B.getContent()[J]) { + case '\0': break; + case '\n': dbgs() << "\\n"; break; + case '\t': dbgs() << "\\t"; break; + default: dbgs() << B.getContent()[J]; break; + } + if (B.getSize() > 16) + dbgs() << "..."; + dbgs() << "\"\n"; }); // If there's no symbol at the start of this block then create one. @@ -663,15 +673,13 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( auto &S = G->addAnonymousSymbol(B, 0, BlockSize, false, false); setCanonicalSymbol(NSec, S); LLVM_DEBUG({ - dbgs() << " Adding anonymous symbol for c-string block " - << formatv("{0:x16} -- {1:x16}", S.getAddress(), - S.getAddress() + BlockSize) - << "\n"; + dbgs() << " Adding symbol for c-string block " << B.getRange() + << ": <anonymous symbol> at offset 0\n"; }); } // Process any remaining symbols that point into this block. - auto LastCanonicalAddr = B.getAddress() + BlockEnd; + auto LastCanonicalAddr = B.getAddress() + BlockSize; while (!NSyms.empty() && orc::ExecutorAddr(NSyms.back()->Value) < B.getAddress() + BlockSize) { auto &NSym = *NSyms.back(); @@ -686,8 +694,15 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( LastCanonicalAddr = orc::ExecutorAddr(NSym.Value); } - createStandardGraphSymbol(NSym, B, SymSize, SectionIsText, SymLive, - IsCanonical); + auto &Sym = createStandardGraphSymbol(NSym, B, SymSize, SectionIsText, + SymLive, IsCanonical); + (void)Sym; + LLVM_DEBUG({ + dbgs() << " Adding symbol for c-string block " << B.getRange() + << ": " + << (Sym.hasName() ? Sym.getName() : "<anonymous symbol>") + << " at offset " << formatv("{0:x}", Sym.getOffset()) << "\n"; + }); NSyms.pop_back(); } diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp index 3ca2e40c7263..dd50314d3ed7 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -11,15 +11,15 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" +#include "llvm/ExecutionEngine/JITLink/aarch64.h" #include "MachOLinkGraphBuilder.h" -#include "PerGraphGOTAndPLTStubsBuilder.h" #define DEBUG_TYPE "jitlink" using namespace llvm; using namespace llvm::jitlink; -using namespace llvm::jitlink::MachO_arm64_Edges; namespace { @@ -27,19 +27,39 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder { public: MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj) : MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin"), - getMachOARM64RelocationKindName), + aarch64::getEdgeKindName), NumSymbols(Obj.getSymtabLoadCommand().nsyms) {} private: + enum MachOARM64RelocationKind : Edge::Kind { + MachOBranch26 = Edge::FirstRelocation, + MachOPointer32, + MachOPointer64, + MachOPointer64Anon, + MachOPage21, + MachOPageOffset12, + MachOGOTPage21, + MachOGOTPageOffset12, + MachOTLVPage21, + MachOTLVPageOffset12, + MachOPointerToGOT, + MachOPairedAddend, + MachOLDRLiteral19, + MachODelta32, + MachODelta64, + MachONegDelta32, + MachONegDelta64, + }; + static Expected<MachOARM64RelocationKind> getRelocationKind(const MachO::relocation_info &RI) { switch (RI.r_type) { case MachO::ARM64_RELOC_UNSIGNED: if (!RI.r_pcrel) { if (RI.r_length == 3) - return RI.r_extern ? Pointer64 : Pointer64Anon; + return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; else if (RI.r_length == 2) - return Pointer32; + return MachOPointer32; } break; case MachO::ARM64_RELOC_SUBTRACTOR: @@ -48,46 +68,46 @@ private: // They may be turned into NegDelta<W> by parsePairRelocation. if (!RI.r_pcrel && RI.r_extern) { if (RI.r_length == 2) - return Delta32; + return MachODelta32; else if (RI.r_length == 3) - return Delta64; + return MachODelta64; } break; case MachO::ARM64_RELOC_BRANCH26: if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return Branch26; + return MachOBranch26; break; case MachO::ARM64_RELOC_PAGE21: if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return Page21; + return MachOPage21; break; case MachO::ARM64_RELOC_PAGEOFF12: if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return PageOffset12; + return MachOPageOffset12; break; case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return GOTPage21; + return MachOGOTPage21; break; case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return GOTPageOffset12; + return MachOGOTPageOffset12; break; case MachO::ARM64_RELOC_POINTER_TO_GOT: if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return PointerToGOT; + return MachOPointerToGOT; break; case MachO::ARM64_RELOC_ADDEND: if (!RI.r_pcrel && !RI.r_extern && RI.r_length == 2) - return PairedAddend; + return MachOPairedAddend; break; case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return TLVPage21; + return MachOTLVPage21; break; case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: if (!RI.r_pcrel && RI.r_extern && RI.r_length == 2) - return TLVPageOffset12; + return MachOTLVPageOffset12; break; } @@ -101,8 +121,7 @@ private: ", length=" + formatv("{0:d}", RI.r_length)); } - using PairRelocInfo = - std::tuple<MachOARM64RelocationKind, Symbol *, uint64_t>; + using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success, // returns the edge kind and addend to be used. @@ -114,8 +133,8 @@ private: object::relocation_iterator &RelEnd) { using namespace support; - assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) || - (SubtractorKind == Delta64 && SubRI.r_length == 3)) && + assert(((SubtractorKind == MachODelta32 && SubRI.r_length == 2) || + (SubtractorKind == MachODelta64 && SubRI.r_length == 3)) && "Subtractor kind should match length"); assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); @@ -165,17 +184,18 @@ private: FixupValue -= ToSymbol->getAddress().getValue(); } - MachOARM64RelocationKind DeltaKind; + Edge::Kind DeltaKind; Symbol *TargetSymbol; uint64_t Addend; if (&BlockToFix == &FromSymbol->getAddressable()) { TargetSymbol = ToSymbol; - DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32; + DeltaKind = (SubRI.r_length == 3) ? aarch64::Delta64 : aarch64::Delta32; Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); // FIXME: handle extern 'from'. } else if (&BlockToFix == &ToSymbol->getAddressable()) { TargetSymbol = &*FromSymbol; - DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32; + DeltaKind = + (SubRI.r_length == 3) ? aarch64::NegDelta64 : aarch64::NegDelta32; Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); } else { // BlockToFix was neither FromSymbol nor ToSymbol. @@ -229,9 +249,9 @@ private: MachO::relocation_info RI = getRelocationInfo(RelItr); // Validate the relocation kind. - auto Kind = getRelocationKind(RI); - if (!Kind) - return Kind.takeError(); + auto MachORelocKind = getRelocationKind(RI); + if (!MachORelocKind) + return MachORelocKind.takeError(); // Find the address of the value to fix up. orc::ExecutorAddr FixupAddress = @@ -255,6 +275,8 @@ private: return make_error<JITLinkError>( "Relocation content extends past end of fixup block"); + Edge::Kind Kind = Edge::Invalid; + // Get a pointer to the fixup content. const char *FixupContent = BlockToFix->getContent().data() + (FixupAddress - BlockToFix->getAddress()); @@ -263,7 +285,7 @@ private: Symbol *TargetSymbol = nullptr; uint64_t Addend = 0; - if (*Kind == PairedAddend) { + if (*MachORelocKind == MachOPairedAddend) { // If this is an Addend relocation then process it and move to the // paired reloc. @@ -275,19 +297,21 @@ private: ++RelItr; RI = getRelocationInfo(RelItr); - Kind = getRelocationKind(RI); - if (!Kind) - return Kind.takeError(); + MachORelocKind = getRelocationKind(RI); + if (!MachORelocKind) + return MachORelocKind.takeError(); - if (*Kind != Branch26 && *Kind != Page21 && *Kind != PageOffset12) + if (*MachORelocKind != MachOBranch26 && + *MachORelocKind != MachOPage21 && + *MachORelocKind != MachOPageOffset12) return make_error<JITLinkError>( "Invalid relocation pair: Addend + " + - StringRef(getMachOARM64RelocationKindName(*Kind))); + StringRef(getMachOARM64RelocationKindName(*MachORelocKind))); LLVM_DEBUG({ dbgs() << " Addend: value = " << formatv("{0:x6}", Addend) - << ", pair is " << getMachOARM64RelocationKindName(*Kind) - << "\n"; + << ", pair is " + << getMachOARM64RelocationKindName(*MachORelocKind) << "\n"; }); // Find the address of the value to fix up. @@ -298,8 +322,8 @@ private: "different target"); } - switch (*Kind) { - case Branch26: { + switch (*MachORelocKind) { + case MachOBranch26: { if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else @@ -308,23 +332,26 @@ private: if ((Instr & 0x7fffffff) != 0x14000000) return make_error<JITLinkError>("BRANCH26 target is not a B or BL " "instruction with a zero addend"); + Kind = aarch64::Branch26; break; } - case Pointer32: + case MachOPointer32: if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else return TargetSymbolOrErr.takeError(); Addend = *(const ulittle32_t *)FixupContent; + Kind = aarch64::Pointer32; break; - case Pointer64: + case MachOPointer64: if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else return TargetSymbolOrErr.takeError(); Addend = *(const ulittle64_t *)FixupContent; + Kind = aarch64::Pointer64; break; - case Pointer64Anon: { + case MachOPointer64Anon: { orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent); auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1); if (!TargetNSec) @@ -335,11 +362,12 @@ private: else return TargetSymbolOrErr.takeError(); Addend = TargetAddress - TargetSymbol->getAddress(); + Kind = aarch64::Pointer64Anon; break; } - case Page21: - case TLVPage21: - case GOTPage21: { + case MachOPage21: + case MachOTLVPage21: + case MachOGOTPage21: { if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else @@ -349,9 +377,17 @@ private: return make_error<JITLinkError>("PAGE21/GOTPAGE21 target is not an " "ADRP instruction with a zero " "addend"); + + if (*MachORelocKind == MachOPage21) { + Kind = aarch64::Page21; + } else if (*MachORelocKind == MachOTLVPage21) { + Kind = aarch64::TLVPage21; + } else if (*MachORelocKind == MachOGOTPage21) { + Kind = aarch64::GOTPage21; + } break; } - case PageOffset12: { + case MachOPageOffset12: { if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else @@ -361,10 +397,11 @@ private: if (EncodedAddend != 0) return make_error<JITLinkError>("GOTPAGEOFF12 target has non-zero " "encoded addend"); + Kind = aarch64::PageOffset12; break; } - case TLVPageOffset12: - case GOTPageOffset12: { + case MachOTLVPageOffset12: + case MachOGOTPageOffset12: { if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else @@ -374,27 +411,35 @@ private: return make_error<JITLinkError>("GOTPAGEOFF12 target is not an LDR " "immediate instruction with a zero " "addend"); + + if (*MachORelocKind == MachOTLVPageOffset12) { + Kind = aarch64::TLVPageOffset12; + } else if (*MachORelocKind == MachOGOTPageOffset12) { + Kind = aarch64::GOTPageOffset12; + } break; } - case PointerToGOT: + case MachOPointerToGOT: if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) TargetSymbol = TargetSymbolOrErr->GraphSymbol; else return TargetSymbolOrErr.takeError(); + + Kind = aarch64::PointerToGOT; break; - case Delta32: - case Delta64: { + case MachODelta32: + case MachODelta64: { // We use Delta32/Delta64 to represent SUBTRACTOR relocations. // parsePairRelocation handles the paired reloc, and returns the // edge kind to be used (either Delta32/Delta64, or // NegDelta32/NegDelta64, depending on the direction of the // subtraction) along with the addend. auto PairInfo = - parsePairRelocation(*BlockToFix, *Kind, RI, FixupAddress, - FixupContent, ++RelItr, RelEnd); + parsePairRelocation(*BlockToFix, *MachORelocKind, RI, + FixupAddress, FixupContent, ++RelItr, RelEnd); if (!PairInfo) return PairInfo.takeError(); - std::tie(*Kind, TargetSymbol, Addend) = *PairInfo; + std::tie(Kind, TargetSymbol, Addend) = *PairInfo; assert(TargetSymbol && "No target symbol from parsePairRelocation?"); break; } @@ -405,108 +450,59 @@ private: LLVM_DEBUG({ dbgs() << " "; - Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, + Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, Addend); - printEdge(dbgs(), *BlockToFix, GE, - getMachOARM64RelocationKindName(*Kind)); + printEdge(dbgs(), *BlockToFix, GE, aarch64::getEdgeKindName(Kind)); dbgs() << "\n"; }); - BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(), + BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, Addend); } } return Error::success(); } - unsigned NumSymbols = 0; -}; - -class PerGraphGOTAndPLTStubsBuilder_MachO_arm64 - : public PerGraphGOTAndPLTStubsBuilder< - PerGraphGOTAndPLTStubsBuilder_MachO_arm64> { -public: - using PerGraphGOTAndPLTStubsBuilder< - PerGraphGOTAndPLTStubsBuilder_MachO_arm64>::PerGraphGOTAndPLTStubsBuilder; - - bool isGOTEdgeToFix(Edge &E) const { - return E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 || - E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12 || - E.getKind() == PointerToGOT; - } - - Symbol &createGOTEntry(Symbol &Target) { - auto &GOTEntryBlock = G.createContentBlock( - getGOTSection(), getGOTEntryBlockContent(), orc::ExecutorAddr(), 8, 0); - GOTEntryBlock.addEdge(Pointer64, 0, Target, 0); - return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false); - } - - void fixGOTEdge(Edge &E, Symbol &GOTEntry) { - if (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 || - E.getKind() == TLVPage21 || E.getKind() == TLVPageOffset12) { - // Update the target, but leave the edge addend as-is. - E.setTarget(GOTEntry); - } else if (E.getKind() == PointerToGOT) { - E.setTarget(GOTEntry); - E.setKind(Delta32); - } else - llvm_unreachable("Not a GOT edge?"); - } - - bool isExternalBranchEdge(Edge &E) { - return E.getKind() == Branch26 && !E.getTarget().isDefined(); - } - - Symbol &createPLTStub(Symbol &Target) { - auto &StubContentBlock = G.createContentBlock( - getStubsSection(), getStubBlockContent(), orc::ExecutorAddr(), 1, 0); - // Re-use GOT entries for stub targets. - auto &GOTEntrySymbol = getGOTEntry(Target); - StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0); - return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false); - } - - void fixPLTEdge(Edge &E, Symbol &Stub) { - assert(E.getKind() == Branch26 && "Not a Branch32 edge?"); - assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?"); - E.setTarget(Stub); - } - -private: - Section &getGOTSection() { - if (!GOTSection) - GOTSection = &G.createSection("$__GOT", MemProt::Read | MemProt::Exec); - return *GOTSection; - } - - Section &getStubsSection() { - if (!StubsSection) - StubsSection = - &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec); - return *StubsSection; - } - - ArrayRef<char> getGOTEntryBlockContent() { - return {reinterpret_cast<const char *>(NullGOTEntryContent), - sizeof(NullGOTEntryContent)}; - } - - ArrayRef<char> getStubBlockContent() { - return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)}; + /// Return the string name of the given MachO arm64 edge kind. + const char *getMachOARM64RelocationKindName(Edge::Kind R) { + switch (R) { + case MachOBranch26: + return "MachOBranch26"; + case MachOPointer64: + return "MachOPointer64"; + case MachOPointer64Anon: + return "MachOPointer64Anon"; + case MachOPage21: + return "MachOPage21"; + case MachOPageOffset12: + return "MachOPageOffset12"; + case MachOGOTPage21: + return "MachOGOTPage21"; + case MachOGOTPageOffset12: + return "MachOGOTPageOffset12"; + case MachOTLVPage21: + return "MachOTLVPage21"; + case MachOTLVPageOffset12: + return "MachOTLVPageOffset12"; + case MachOPointerToGOT: + return "MachOPointerToGOT"; + case MachOPairedAddend: + return "MachOPairedAddend"; + case MachOLDRLiteral19: + return "MachOLDRLiteral19"; + case MachODelta32: + return "MachODelta32"; + case MachODelta64: + return "MachODelta64"; + case MachONegDelta32: + return "MachONegDelta32"; + case MachONegDelta64: + return "MachONegDelta64"; + default: + return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); + } } - static const uint8_t NullGOTEntryContent[8]; - static const uint8_t StubContent[8]; - Section *GOTSection = nullptr; - Section *StubsSection = nullptr; -}; - -const uint8_t - PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = { - 0x10, 0x00, 0x00, 0x58, // LDR x16, <literal> - 0x00, 0x02, 0x1f, 0xd6 // BR x16 + unsigned NumSymbols = 0; }; } // namespace @@ -514,6 +510,15 @@ const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = { namespace llvm { namespace jitlink { +Error buildTables_MachO_arm64(LinkGraph &G) { + LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); + + aarch64::GOTTableManager GOT; + aarch64::PLTTableManager PLT(GOT); + visitExistingEdges(G, GOT, PLT); + return Error::success(); +} + class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> { friend class JITLinker<MachOJITLinker_arm64>; @@ -524,162 +529,8 @@ public: : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} private: - - static unsigned getPageOffset12Shift(uint32_t Instr) { - constexpr uint32_t LoadStoreImm12Mask = 0x3b000000; - constexpr uint32_t Vec128Mask = 0x04800000; - - if ((Instr & LoadStoreImm12Mask) == 0x39000000) { - uint32_t ImplicitShift = Instr >> 30; - if (ImplicitShift == 0) - if ((Instr & Vec128Mask) == Vec128Mask) - ImplicitShift = 4; - - return ImplicitShift; - } - - return 0; - } - Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { - using namespace support; - - char *BlockWorkingMem = B.getAlreadyMutableContent().data(); - char *FixupPtr = BlockWorkingMem + E.getOffset(); - orc::ExecutorAddr FixupAddress = B.getAddress() + E.getOffset(); - - switch (E.getKind()) { - case Branch26: { - assert((FixupAddress.getValue() & 0x3) == 0 && - "Branch-inst is not 32-bit aligned"); - - int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); - - if (static_cast<uint64_t>(Value) & 0x3) - return make_error<JITLinkError>("Branch26 target is not 32-bit " - "aligned"); - - if (Value < -(1 << 27) || Value > ((1 << 27) - 1)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t RawInstr = *(little32_t *)FixupPtr; - assert((RawInstr & 0x7fffffff) == 0x14000000 && - "RawInstr isn't a B or BR immediate instruction"); - uint32_t Imm = (static_cast<uint32_t>(Value) & ((1 << 28) - 1)) >> 2; - uint32_t FixedInstr = RawInstr | Imm; - *(little32_t *)FixupPtr = FixedInstr; - break; - } - case Pointer32: { - uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); - if (Value > std::numeric_limits<uint32_t>::max()) - return makeTargetOutOfRangeError(G, B, E); - *(ulittle32_t *)FixupPtr = Value; - break; - } - case Pointer64: - case Pointer64Anon: { - uint64_t Value = E.getTarget().getAddress().getValue() + E.getAddend(); - *(ulittle64_t *)FixupPtr = Value; - break; - } - case Page21: - case TLVPage21: - case GOTPage21: { - assert((E.getKind() != GOTPage21 || E.getAddend() == 0) && - "GOTPAGE21 with non-zero addend"); - uint64_t TargetPage = - (E.getTarget().getAddress().getValue() + E.getAddend()) & - ~static_cast<uint64_t>(4096 - 1); - uint64_t PCPage = - FixupAddress.getValue() & ~static_cast<uint64_t>(4096 - 1); - - int64_t PageDelta = TargetPage - PCPage; - if (PageDelta < -(1 << 30) || PageDelta > ((1 << 30) - 1)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - assert((RawInstr & 0xffffffe0) == 0x90000000 && - "RawInstr isn't an ADRP instruction"); - uint32_t ImmLo = (static_cast<uint64_t>(PageDelta) >> 12) & 0x3; - uint32_t ImmHi = (static_cast<uint64_t>(PageDelta) >> 14) & 0x7ffff; - uint32_t FixedInstr = RawInstr | (ImmLo << 29) | (ImmHi << 5); - *(ulittle32_t *)FixupPtr = FixedInstr; - break; - } - case PageOffset12: { - uint64_t TargetOffset = - (E.getTarget().getAddress() + E.getAddend()).getValue() & 0xfff; - - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - unsigned ImmShift = getPageOffset12Shift(RawInstr); - - if (TargetOffset & ((1 << ImmShift) - 1)) - return make_error<JITLinkError>("PAGEOFF12 target is not aligned"); - - uint32_t EncodedImm = (TargetOffset >> ImmShift) << 10; - uint32_t FixedInstr = RawInstr | EncodedImm; - *(ulittle32_t *)FixupPtr = FixedInstr; - break; - } - case TLVPageOffset12: - case GOTPageOffset12: { - assert(E.getAddend() == 0 && "GOTPAGEOF12 with non-zero addend"); - - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - assert((RawInstr & 0xfffffc00) == 0xf9400000 && - "RawInstr isn't a 64-bit LDR immediate"); - - uint32_t TargetOffset = E.getTarget().getAddress().getValue() & 0xfff; - assert((TargetOffset & 0x7) == 0 && "GOT entry is not 8-byte aligned"); - uint32_t EncodedImm = (TargetOffset >> 3) << 10; - uint32_t FixedInstr = RawInstr | EncodedImm; - *(ulittle32_t *)FixupPtr = FixedInstr; - break; - } - case LDRLiteral19: { - assert((FixupAddress.getValue() & 0x3) == 0 && - "LDR is not 32-bit aligned"); - assert(E.getAddend() == 0 && "LDRLiteral19 with non-zero addend"); - uint32_t RawInstr = *(ulittle32_t *)FixupPtr; - assert(RawInstr == 0x58000010 && "RawInstr isn't a 64-bit LDR literal"); - int64_t Delta = E.getTarget().getAddress() - FixupAddress; - if (Delta & 0x3) - return make_error<JITLinkError>("LDR literal target is not 32-bit " - "aligned"); - if (Delta < -(1 << 20) || Delta > ((1 << 20) - 1)) - return makeTargetOutOfRangeError(G, B, E); - - uint32_t EncodedImm = - ((static_cast<uint32_t>(Delta) >> 2) & 0x7ffff) << 5; - uint32_t FixedInstr = RawInstr | EncodedImm; - *(ulittle32_t *)FixupPtr = FixedInstr; - break; - } - case Delta32: - case Delta64: - case NegDelta32: - case NegDelta64: { - int64_t Value; - if (E.getKind() == Delta32 || E.getKind() == Delta64) - Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); - else - Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); - - if (E.getKind() == Delta32 || E.getKind() == NegDelta32) { - if (Value < std::numeric_limits<int32_t>::min() || - Value > std::numeric_limits<int32_t>::max()) - return makeTargetOutOfRangeError(G, B, E); - *(little32_t *)FixupPtr = Value; - } else - *(little64_t *)FixupPtr = Value; - break; - } - default: - llvm_unreachable("Unrecognized edge kind"); - } - - return Error::success(); + return aarch64::applyFixup(G, B, E); } uint64_t NullValue = 0; @@ -712,13 +563,14 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G, // Add eh-frame passses. // FIXME: Prune eh-frames for which compact-unwind is available once // we support compact-unwind registration with libunwind. - Config.PrePrunePasses.push_back(EHFrameSplitter("__TEXT,__eh_frame")); Config.PrePrunePasses.push_back( - EHFrameEdgeFixer("__TEXT,__eh_frame", 8, Delta64, Delta32, NegDelta32)); + DWARFRecordSectionSplitter("__TEXT,__eh_frame")); + Config.PrePrunePasses.push_back(EHFrameEdgeFixer( + "__TEXT,__eh_frame", 8, aarch64::Pointer32, aarch64::Pointer64, + aarch64::Delta32, aarch64::Delta64, aarch64::NegDelta32)); // Add an in-place GOT/Stubs pass. - Config.PostPrunePasses.push_back( - PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass); + Config.PostPrunePasses.push_back(buildTables_MachO_arm64); } if (auto Err = Ctx->modifyPassConfig(*G, Config)) @@ -728,44 +580,5 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G, MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config)); } -const char *getMachOARM64RelocationKindName(Edge::Kind R) { - switch (R) { - case Branch26: - return "Branch26"; - case Pointer64: - return "Pointer64"; - case Pointer64Anon: - return "Pointer64Anon"; - case Page21: - return "Page21"; - case PageOffset12: - return "PageOffset12"; - case GOTPage21: - return "GOTPage21"; - case GOTPageOffset12: - return "GOTPageOffset12"; - case TLVPage21: - return "TLVPage21"; - case TLVPageOffset12: - return "TLVPageOffset12"; - case PointerToGOT: - return "PointerToGOT"; - case PairedAddend: - return "PairedAddend"; - case LDRLiteral19: - return "LDRLiteral19"; - case Delta32: - return "Delta32"; - case Delta64: - return "Delta64"; - case NegDelta32: - return "NegDelta32"; - case NegDelta64: - return "NegDelta64"; - default: - return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); - } -} - } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp index 82afaa3aa3c5..6dfd5548fcfd 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" +#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "MachOLinkGraphBuilder.h" -#include "PerGraphGOTAndPLTStubsBuilder.h" #define DEBUG_TYPE "jitlink" @@ -504,12 +504,13 @@ void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, } LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() { - return EHFrameSplitter("__TEXT,__eh_frame"); + return DWARFRecordSectionSplitter("__TEXT,__eh_frame"); } LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() { return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize, - x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32); + x86_64::Pointer32, x86_64::Pointer64, x86_64::Delta32, + x86_64::Delta64, x86_64::NegDelta32); } } // end namespace jitlink diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp index 6dccc4811885..28a6f9ce90d9 100644 --- a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp @@ -18,13 +18,55 @@ namespace llvm { namespace jitlink { namespace aarch64 { -const char *getEdgeKindName(Edge::Kind K) { - switch (K) { - case R_AARCH64_CALL26: - return "R_AARCH64_CALL26"; +const uint8_t NullGOTEntryContent[8] = {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + +const uint8_t StubContent[8] = { + 0x10, 0x00, 0x00, 0x58, // LDR x16, <literal> + 0x00, 0x02, 0x1f, 0xd6 // BR x16 +}; + +const char *getEdgeKindName(Edge::Kind R) { + switch (R) { + case Branch26: + return "Branch26"; + case Pointer64: + return "Pointer64"; + case Pointer64Anon: + return "Pointer64Anon"; + case Page21: + return "Page21"; + case PageOffset12: + return "PageOffset12"; + case MoveWide16: + return "MoveWide16"; + case GOTPage21: + return "GOTPage21"; + case GOTPageOffset12: + return "GOTPageOffset12"; + case TLVPage21: + return "TLVPage21"; + case TLVPageOffset12: + return "TLVPageOffset12"; + case PointerToGOT: + return "PointerToGOT"; + case PairedAddend: + return "PairedAddend"; + case LDRLiteral19: + return "LDRLiteral19"; + case Delta32: + return "Delta32"; + case Delta64: + return "Delta64"; + case NegDelta32: + return "NegDelta32"; + case NegDelta64: + return "NegDelta64"; + default: + return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); } - return getGenericEdgeKindName(K); } + } // namespace aarch64 } // namespace jitlink } // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp index 3ce2cf10a24c..3848cc6b5f01 100644 --- a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp @@ -26,6 +26,8 @@ const char *getEdgeKindName(Edge::Kind K) { return "R_RISCV_64"; case R_RISCV_BRANCH: return "R_RISCV_BRANCH"; + case R_RISCV_JAL: + return "R_RISCV_JAL"; case R_RISCV_HI20: return "R_RISCV_HI20"; case R_RISCV_LO12_I: @@ -56,6 +58,8 @@ const char *getEdgeKindName(Edge::Kind K) { return "R_RISCV_SUB16"; case R_RISCV_SUB8: return "R_RISCV_SUB8"; + case R_RISCV_SUB6: + return "R_RISCV_SUB6"; case R_RISCV_SET6: return "R_RISCV_SET6"; case R_RISCV_SET8: diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp index ed912280ac82..4ac901daa5c8 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -19,6 +19,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" +#include "llvm/MC/MCContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/DynamicLibrary.h" diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h index a5dd420c9132..f6c4cdbb8c91 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -72,8 +72,7 @@ class MCJIT : public ExecutionEngine { class OwningModuleContainer { public: - OwningModuleContainer() { - } + OwningModuleContainer() = default; ~OwningModuleContainer() { freeModulePtrSet(AddedModules); freeModulePtrSet(LoadedModules); diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp index f34247005258..fad7428e1f90 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp @@ -12,6 +12,7 @@ #include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" +#include "llvm/MC/MCContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index e5cb8103919a..dd80630a33c1 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -62,7 +62,7 @@ void ResourceTracker::makeDefunct() { JDAndFlag.store(Val); } -ResourceManager::~ResourceManager() {} +ResourceManager::~ResourceManager() = default; ResourceTrackerDefunct::ResourceTrackerDefunct(ResourceTrackerSP RT) : RT(std::move(RT)) {} @@ -76,9 +76,21 @@ void ResourceTrackerDefunct::log(raw_ostream &OS) const { } FailedToMaterialize::FailedToMaterialize( + std::shared_ptr<SymbolStringPool> SSP, std::shared_ptr<SymbolDependenceMap> Symbols) - : Symbols(std::move(Symbols)) { + : SSP(std::move(SSP)), Symbols(std::move(Symbols)) { + assert(this->SSP && "String pool cannot be null"); assert(!this->Symbols->empty() && "Can not fail to resolve an empty set"); + + // FIXME: Use a new dep-map type for FailedToMaterialize errors so that we + // don't have to manually retain/release. + for (auto &KV : *this->Symbols) + KV.first->Retain(); +} + +FailedToMaterialize::~FailedToMaterialize() { + for (auto &KV : *Symbols) + KV.first->Release(); } std::error_code FailedToMaterialize::convertToErrorCode() const { @@ -251,9 +263,21 @@ StringRef AbsoluteSymbolsMaterializationUnit::getName() const { void AbsoluteSymbolsMaterializationUnit::materialize( std::unique_ptr<MaterializationResponsibility> R) { - // No dependencies, so these calls can't fail. - cantFail(R->notifyResolved(Symbols)); - cantFail(R->notifyEmitted()); + // Even though these are just absolute symbols we need to check for failure + // to resolve/emit: the tracker for these symbols may have been removed while + // the materialization was in flight (e.g. due to a failure in some action + // triggered by the queries attached to the resolution/emission of these + // symbols). + if (auto Err = R->notifyResolved(Symbols)) { + R->getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } + if (auto Err = R->notifyEmitted()) { + R->getExecutionSession().reportError(std::move(Err)); + R->failMaterialization(); + return; + } } void AbsoluteSymbolsMaterializationUnit::discard(const JITDylib &JD, @@ -485,13 +509,16 @@ Expected<SymbolAliasMap> buildSimpleReexportsAliasMap(JITDylib &SourceJD, class InProgressLookupState { public: + // FIXME: Reduce the number of SymbolStringPtrs here. See + // https://github.com/llvm/llvm-project/issues/55576. + InProgressLookupState(LookupKind K, JITDylibSearchOrder SearchOrder, SymbolLookupSet LookupSet, SymbolState RequiredState) : K(K), SearchOrder(std::move(SearchOrder)), LookupSet(std::move(LookupSet)), RequiredState(RequiredState) { DefGeneratorCandidates = this->LookupSet; } - virtual ~InProgressLookupState() {} + virtual ~InProgressLookupState() = default; virtual void complete(std::unique_ptr<InProgressLookupState> IPLS) = 0; virtual void fail(Error Err) = 0; @@ -609,7 +636,7 @@ void LookupState::continueLookup(Error Err) { ES.OL_applyQueryPhase1(std::move(IPLS), std::move(Err)); } -DefinitionGenerator::~DefinitionGenerator() {} +DefinitionGenerator::~DefinitionGenerator() = default; JITDylib::~JITDylib() { LLVM_DEBUG(dbgs() << "Destroying JITDylib " << getName() << "\n"); @@ -959,6 +986,7 @@ Error JITDylib::resolve(MaterializationResponsibility &MR, auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>(); (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); return make_error<FailedToMaterialize>( + getExecutionSession().getSymbolStringPool(), std::move(FailedSymbolsDepMap)); } @@ -1036,6 +1064,7 @@ Error JITDylib::emit(MaterializationResponsibility &MR, auto FailedSymbolsDepMap = std::make_shared<SymbolDependenceMap>(); (*FailedSymbolsDepMap)[this] = std::move(SymbolsInErrorState); return make_error<FailedToMaterialize>( + getExecutionSession().getSymbolStringPool(), std::move(FailedSymbolsDepMap)); } @@ -1411,12 +1440,11 @@ void JITDylib::dump(raw_ostream &OS) { for (auto &KV : Symbols) { OS << " \"" << *KV.first << "\": "; if (auto Addr = KV.second.getAddress()) - OS << format("0x%016" PRIx64, Addr) << ", " << KV.second.getFlags() - << " "; + OS << format("0x%016" PRIx64, Addr); else OS << "<not resolved> "; - OS << KV.second.getFlags() << " " << KV.second.getState(); + OS << " " << KV.second.getFlags() << " " << KV.second.getState(); if (KV.second.hasMaterializerAttached()) { OS << " (Materializer "; @@ -1751,7 +1779,7 @@ void JITDylib::transferEmittedNodeDependencies( } } -Platform::~Platform() {} +Platform::~Platform() = default; Expected<DenseMap<JITDylib *, SymbolMap>> Platform::lookupInitSymbols( ExecutionSession &ES, @@ -1858,6 +1886,12 @@ ExecutionSession::ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC) this->EPC->ES = this; } +ExecutionSession::~ExecutionSession() { + // You must call endSession prior to destroying the session. + assert(!SessionOpen && + "Session still open. Did you forget to call endSession?"); +} + Error ExecutionSession::endSession() { LLVM_DEBUG(dbgs() << "Ending ExecutionSession " << this << "\n"); @@ -1869,7 +1903,7 @@ Error ExecutionSession::endSession() { // TODO: notifiy platform? run static deinits? Error Err = Error::success(); - for (auto &JD : JITDylibsToClose) + for (auto &JD : reverse(JITDylibsToClose)) Err = joinErrors(std::move(Err), JD->clear()); Err = joinErrors(std::move(Err), EPC->disconnect()); @@ -1987,9 +2021,8 @@ JITDylib::getDFSLinkOrder(ArrayRef<JITDylibSP> JDs) { for (auto &KV : llvm::reverse(Result.back()->LinkOrder)) { auto &JD = *KV.first; - if (Visited.count(&JD)) + if (!Visited.insert(&JD).second) continue; - Visited.insert(&JD); WorkStack.push_back(&JD); } } @@ -2071,7 +2104,7 @@ void ExecutionSession::lookup( Expected<SymbolMap> ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, - const SymbolLookupSet &Symbols, LookupKind K, + SymbolLookupSet Symbols, LookupKind K, SymbolState RequiredState, RegisterDependenciesFunction RegisterDependencies) { #if LLVM_ENABLE_THREADS @@ -2103,7 +2136,7 @@ ExecutionSession::lookup(const JITDylibSearchOrder &SearchOrder, #endif // Perform the asynchronous lookup. - lookup(K, SearchOrder, Symbols, RequiredState, NotifyComplete, + lookup(K, SearchOrder, std::move(Symbols), RequiredState, NotifyComplete, RegisterDependencies); #if LLVM_ENABLE_THREADS @@ -2257,7 +2290,8 @@ Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) { joinErrors(std::move(Err), L->handleRemoveResources(RT.getKeyUnsafe())); for (auto &Q : QueriesToFail) - Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); + Q->handleFailed( + make_error<FailedToMaterialize>(getSymbolStringPool(), FailedSymbols)); return Err; } @@ -2337,7 +2371,8 @@ Error ExecutionSession::IL_updateCandidatesFor( if (SymI->second.getFlags().hasError()) { auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>(); (*FailedSymbolsMap)[&JD] = {Name}; - return make_error<FailedToMaterialize>(std::move(FailedSymbolsMap)); + return make_error<FailedToMaterialize>(getSymbolStringPool(), + std::move(FailedSymbolsMap)); } // Otherwise this is a match. Remove it from the candidate set. @@ -2611,7 +2646,7 @@ void ExecutionSession::OL_completeLookup( auto FailedSymbolsMap = std::make_shared<SymbolDependenceMap>(); (*FailedSymbolsMap)[&JD] = {Name}; return make_error<FailedToMaterialize>( - std::move(FailedSymbolsMap)); + getSymbolStringPool(), std::move(FailedSymbolsMap)); } // Otherwise this is a match. @@ -2947,7 +2982,8 @@ void ExecutionSession::OL_notifyFailed(MaterializationResponsibility &MR) { }); for (auto &Q : FailedQueries) - Q->handleFailed(make_error<FailedToMaterialize>(FailedSymbols)); + Q->handleFailed( + make_error<FailedToMaterialize>(getSymbolStringPool(), FailedSymbols)); } Error ExecutionSession::OL_replace(MaterializationResponsibility &MR, diff --git a/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp index 4ff6b7fd54df..1e68ea1225e6 100644 --- a/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp +++ b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp @@ -42,7 +42,7 @@ class DebugObjectSection { public: virtual void setTargetMemoryRange(SectionRange Range) = 0; virtual void dump(raw_ostream &OS, StringRef Name) {} - virtual ~DebugObjectSection() {} + virtual ~DebugObjectSection() = default; }; template <typename ELFT> diff --git a/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp b/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp index 5b386a458f1f..028bd245fb55 100644 --- a/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/DebugUtils.cpp @@ -297,6 +297,13 @@ raw_ostream &operator<<(raw_ostream &OS, const SymbolState &S) { llvm_unreachable("Invalid state"); } +raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPool &SSP) { + std::lock_guard<std::mutex> Lock(SSP.PoolMutex); + for (auto &KV : SSP.Pool) + OS << KV.first() << ": " << KV.second << "\n"; + return OS; +} + DumpObjects::DumpObjects(std::string DumpDir, std::string IdentifierOverride) : DumpDir(std::move(DumpDir)), IdentifierOverride(std::move(IdentifierOverride)) { diff --git a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp index 6916ee4a827f..3c44fe81b4a9 100644 --- a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp +++ b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp @@ -48,7 +48,7 @@ public: MachODebugObjectSynthesizerBase(LinkGraph &G, ExecutorAddr RegisterActionAddr) : G(G), RegisterActionAddr(RegisterActionAddr) {} - virtual ~MachODebugObjectSynthesizerBase() {} + virtual ~MachODebugObjectSynthesizerBase() = default; Error preserveDebugSections() { if (G.findSectionByName(SynthDebugSectionName)) { @@ -349,10 +349,11 @@ public: } SectionRange R(MachOContainerBlock->getSection()); - G.allocActions().push_back({cantFail(shared::WrapperFunctionCall::Create< - SPSArgList<SPSExecutorAddrRange>>( - RegisterActionAddr, R.getRange())), - {}}); + G.allocActions().push_back( + {cantFail(shared::WrapperFunctionCall::Create< + shared::SPSArgList<shared::SPSExecutorAddrRange>>( + RegisterActionAddr, R.getRange())), + {}}); return Error::success(); } diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index d02760703f06..e476c549412a 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -10,6 +10,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" +#include "llvm/ExecutionEngine/JITLink/aarch64.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" @@ -47,6 +48,11 @@ public: Endianness = support::endianness::little; EdgeKind = jitlink::x86_64::Pointer64; break; + case Triple::aarch64: + PointerSize = 8; + Endianness = support::endianness::little; + EdgeKind = jitlink::aarch64::Pointer64; + break; default: llvm_unreachable("Unrecognized architecture"); } @@ -95,8 +101,6 @@ StringRef InitArrayFuncSectionName = ".init_array"; StringRef ThreadBSSSectionName = ".tbss"; StringRef ThreadDataSectionName = ".tdata"; -StringRef InitSectionNames[] = {InitArrayFuncSectionName}; - } // end anonymous namespace namespace llvm { @@ -117,8 +121,12 @@ ELFNixPlatform::Create(ExecutionSession &ES, inconvertibleErrorCode()); // Create default aliases if the caller didn't supply any. - if (!RuntimeAliases) - RuntimeAliases = standardPlatformAliases(ES); + if (!RuntimeAliases) { + auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD); + if (!StandardRuntimeAliases) + return StandardRuntimeAliases.takeError(); + RuntimeAliases = std::move(*StandardRuntimeAliases); + } // Define the aliases. if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases)))) @@ -189,10 +197,53 @@ static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, } } -SymbolAliasMap ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES) { +Expected<SymbolAliasMap> +ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES, + JITDylib &PlatformJD) { SymbolAliasMap Aliases; addAliases(ES, Aliases, requiredCXXAliases()); addAliases(ES, Aliases, standardRuntimeUtilityAliases()); + + // Determine whether or not the libunwind extended-API function for + // dynamically registering an entire .eh_frame section is available. + // If it is not, we assume that libgcc_s is being used, and alias to + // its __register_frame with the same functionality. + auto RTRegisterFrame = ES.intern("__orc_rt_register_eh_frame_section"); + auto LibUnwindRegisterFrame = ES.intern("__unw_add_dynamic_eh_frame_section"); + auto RTDeregisterFrame = ES.intern("__orc_rt_deregister_eh_frame_section"); + auto LibUnwindDeregisterFrame = + ES.intern("__unw_remove_dynamic_eh_frame_section"); + auto SM = ES.lookup(makeJITDylibSearchOrder(&PlatformJD), + SymbolLookupSet() + .add(LibUnwindRegisterFrame, + SymbolLookupFlags::WeaklyReferencedSymbol) + .add(LibUnwindDeregisterFrame, + SymbolLookupFlags::WeaklyReferencedSymbol)); + if (!SM) { // Weak-ref means no "missing symbol" errors, so this must be + // something more serious that we should report. + return SM.takeError(); + } else if (SM->size() == 2) { + LLVM_DEBUG({ + dbgs() << "Using libunwind " << LibUnwindRegisterFrame + << " for unwind info registration\n"; + }); + Aliases[std::move(RTRegisterFrame)] = {LibUnwindRegisterFrame, + JITSymbolFlags::Exported}; + Aliases[std::move(RTDeregisterFrame)] = {LibUnwindDeregisterFrame, + JITSymbolFlags::Exported}; + } else { + // Since LLVM libunwind is not present, we assume that unwinding + // is provided by libgcc + LLVM_DEBUG({ + dbgs() << "Using libgcc __register_frame" + << " for unwind info registration\n"; + }); + Aliases[std::move(RTRegisterFrame)] = {ES.intern("__register_frame"), + JITSymbolFlags::Exported}; + Aliases[std::move(RTDeregisterFrame)] = {ES.intern("__deregister_frame"), + JITSymbolFlags::Exported}; + } + return Aliases; } @@ -210,6 +261,10 @@ ELFNixPlatform::standardRuntimeUtilityAliases() { static const std::pair<const char *, const char *> StandardRuntimeUtilityAliases[] = { {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"}, + {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"}, + {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"}, + {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"}, + {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"}, {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; return ArrayRef<std::pair<const char *, const char *>>( @@ -217,16 +272,16 @@ ELFNixPlatform::standardRuntimeUtilityAliases() { } bool ELFNixPlatform::isInitializerSection(StringRef SecName) { - for (auto &Name : InitSectionNames) { - if (Name.equals(SecName)) - return true; - } + if (SecName.consume_front(InitArrayFuncSectionName) && + (SecName.empty() || SecName[0] == '.')) + return true; return false; } bool ELFNixPlatform::supportedTarget(const Triple &TT) { switch (TT.getArch()) { case Triple::x86_64: + case Triple::aarch64: return true; default: return false; @@ -723,16 +778,15 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections( jitlink::LinkGraph &G, MaterializationResponsibility &MR) { JITLinkSymbolSet InitSectionSymbols; - for (auto &InitSectionName : InitSectionNames) { + for (auto &InitSection : G.sections()) { // Skip non-init sections. - auto *InitSection = G.findSectionByName(InitSectionName); - if (!InitSection) + if (!isInitializerSection(InitSection.getName())) continue; // Make a pass over live symbols in the section: those blocks are already // preserved. DenseSet<jitlink::Block *> AlreadyLiveBlocks; - for (auto &Sym : InitSection->symbols()) { + for (auto &Sym : InitSection.symbols()) { auto &B = Sym->getBlock(); if (Sym->isLive() && Sym->getOffset() == 0 && Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(&B)) { @@ -742,7 +796,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::preserveInitSections( } // Add anonymous symbols to preserve any not-already-preserved blocks. - for (auto *B : InitSection->blocks()) + for (auto *B : InitSection.blocks()) if (!AlreadyLiveBlocks.count(B)) InitSectionSymbols.insert( &G.addAnonymousSymbol(*B, 0, B->getSize(), false, true)); @@ -763,9 +817,9 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections( LLVM_DEBUG({ dbgs() << "ELFNixPlatform::registerInitSections\n"; }); - for (auto InitSectionName : InitSectionNames) { - if (auto *Sec = G.findSectionByName(InitSectionName)) { - InitSections.push_back(Sec); + for (auto &Sec : G.sections()) { + if (isInitializerSection(Sec.getName())) { + InitSections.push_back(&Sec); } } diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp index f3fe0555fa75..c591acdd646b 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCDebugObjectRegistrar.cpp @@ -45,7 +45,8 @@ createJITLoaderGDBRegistrar(ExecutionSession &ES) { Error EPCDebugObjectRegistrar::registerDebugObject( ExecutorAddrRange TargetMem) { - return ES.callSPSWrapper<void(SPSExecutorAddrRange)>(RegisterFn, TargetMem); + return ES.callSPSWrapper<void(shared::SPSExecutorAddrRange)>(RegisterFn, + TargetMem); } } // namespace orc diff --git a/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp index b901a2d2da23..48aaab96e71f 100644 --- a/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/EPCIndirectionUtils.cpp @@ -88,7 +88,6 @@ EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU) } Error EPCTrampolinePool::deallocatePool() { - Error Err = Error::success(); std::promise<MSVCPError> DeallocResultP; auto DeallocResultF = DeallocResultP.get_future(); @@ -234,7 +233,7 @@ Error EPCIndirectStubsManager::updatePointer(StringRef Name, namespace llvm { namespace orc { -EPCIndirectionUtils::ABISupport::~ABISupport() {} +EPCIndirectionUtils::ABISupport::~ABISupport() = default; Expected<std::unique_ptr<EPCIndirectionUtils>> EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) { @@ -261,6 +260,9 @@ EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) { case Triple::mips64el: return CreateWithABI<OrcMips64>(EPC); + case Triple::riscv64: + return CreateWithABI<OrcRiscv64>(EPC); + case Triple::x86_64: if (TT.getOS() == Triple::OSType::Win32) return CreateWithABI<OrcX86_64_Win32>(EPC); @@ -302,7 +304,8 @@ EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr, return Alloc.takeError(); auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec); - ABI->writeResolverCode(SegInfo.WorkingMem.data(), SegInfo.Addr.getValue(), + ResolverBlockAddr = SegInfo.Addr.getValue(); + ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr, ReentryFnAddr, ReentryCtxAddr); auto FA = Alloc->finalize(); @@ -310,7 +313,7 @@ EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr, return FA.takeError(); ResolverBlock = std::move(*FA); - return SegInfo.Addr.getValue(); + return ResolverBlockAddr; } std::unique_ptr<IndirectStubsManager> diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp index ae2d47fb8c5e..95cf89ec3f8b 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -62,7 +62,7 @@ CtorDtorIterator::Element CtorDtorIterator::operator*() const { break; } else if (ConstantExpr *CE = dyn_cast_or_null<ConstantExpr>(FuncC)) { if (CE->isCast()) - FuncC = dyn_cast_or_null<ConstantExpr>(CE->getOperand(0)); + FuncC = CE->getOperand(0); else break; } else { @@ -273,10 +273,10 @@ Expected<std::unique_ptr<StaticLibraryDefinitionGenerator>> StaticLibraryDefinitionGenerator::Load( ObjectLayer &L, const char *FileName, GetObjectFileInterface GetObjFileInterface) { - auto ArchiveBuffer = errorOrToExpected(MemoryBuffer::getFile(FileName)); + auto ArchiveBuffer = MemoryBuffer::getFile(FileName); if (!ArchiveBuffer) - return ArchiveBuffer.takeError(); + return createFileError(FileName, ArchiveBuffer.getError()); return Create(L, std::move(*ArchiveBuffer), std::move(GetObjFileInterface)); } @@ -288,7 +288,7 @@ StaticLibraryDefinitionGenerator::Load( auto B = object::createBinary(FileName); if (!B) - return B.takeError(); + return createFileError(FileName, B.takeError()); // If this is a regular archive then create an instance from it. if (isa<object::Archive>(B->getBinary())) diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp index 2eb835551adb..412b9f95ea62 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -19,9 +19,9 @@ namespace llvm { namespace orc { -ExecutorProcessControl::MemoryAccess::~MemoryAccess() {} +ExecutorProcessControl::MemoryAccess::~MemoryAccess() = default; -ExecutorProcessControl::~ExecutorProcessControl() {} +ExecutorProcessControl::~ExecutorProcessControl() = default; SelfExecutorProcessControl::SelfExecutorProcessControl( std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, diff --git a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp index aadc437c80c4..69aba1fff59a 100644 --- a/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IRCompileLayer.cpp @@ -11,7 +11,7 @@ namespace llvm { namespace orc { -IRCompileLayer::IRCompiler::~IRCompiler() {} +IRCompileLayer::IRCompiler::~IRCompiler() = default; IRCompileLayer::IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer, std::unique_ptr<IRCompiler> Compile) diff --git a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp index 7a71d2f781d7..38cab526704f 100644 --- a/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -59,7 +59,7 @@ private: namespace llvm { namespace orc { -TrampolinePool::~TrampolinePool() {} +TrampolinePool::~TrampolinePool() = default; void IndirectStubsManager::anchor() {} Expected<JITTargetAddress> @@ -152,6 +152,11 @@ createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, return CCMgrT::Create(ES, ErrorHandlerAddress); } + case Triple::riscv64: { + typedef orc::LocalJITCompileCallbackManager<orc::OrcRiscv64> CCMgrT; + return CCMgrT::Create(ES, ErrorHandlerAddress); + } + case Triple::x86_64: { if (T.getOS() == Triple::OSType::Win32) { typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64_Win32> CCMgrT; @@ -206,6 +211,12 @@ createLocalIndirectStubsManagerBuilder(const Triple &T) { orc::LocalIndirectStubsManager<orc::OrcMips64>>(); }; + case Triple::riscv64: + return []() { + return std::make_unique< + orc::LocalIndirectStubsManager<orc::OrcRiscv64>>(); + }; + case Triple::x86_64: if (T.getOS() == Triple::OSType::Win32) { return [](){ @@ -431,8 +442,7 @@ Error addFunctionPointerRelocationsToCurrentSymbol(jitlink::Symbol &Sym, auto RelocOffInInstr = MIA.getMemoryOperandRelocationOffset(Instr, InstrSize); - if (!RelocOffInInstr.hasValue() || - InstrSize - RelocOffInInstr.getValue() != 4) { + if (!RelocOffInInstr || InstrSize - *RelocOffInInstr != 4) { LLVM_DEBUG(dbgs() << "Skipping unknown self-relocation at " << InstrStart); continue; diff --git a/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp b/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp index 0fbf79b8a56d..c60f4b3b263c 100644 --- a/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp +++ b/llvm/lib/ExecutionEngine/Orc/JITTargetMachineBuilder.cpp @@ -19,6 +19,7 @@ JITTargetMachineBuilder::JITTargetMachineBuilder(Triple TT) : TT(std::move(TT)) { Options.EmulatedTLS = true; Options.ExplicitEmulatedTLS = true; + Options.UseInitArray = true; } Expected<JITTargetMachineBuilder> JITTargetMachineBuilder::detectHost() { diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 91949c9d7eeb..6d67e6d87b56 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -143,7 +143,7 @@ public: JITEvaluatedSymbol(pointerToJITTargetAddress(this), JITSymbolFlags::Exported); StdInterposes[J.mangleAndIntern("__lljit.cxa_atexit_helper")] = - JITEvaluatedSymbol(pointerToJITTargetAddress(registerAtExitHelper), + JITEvaluatedSymbol(pointerToJITTargetAddress(registerCxaAtExitHelper), JITSymbolFlags()); cantFail( @@ -162,6 +162,9 @@ public: PerJDInterposes[J.mangleAndIntern("__lljit.run_atexits_helper")] = JITEvaluatedSymbol(pointerToJITTargetAddress(runAtExitsHelper), JITSymbolFlags()); + PerJDInterposes[J.mangleAndIntern("__lljit.atexit_helper")] = + JITEvaluatedSymbol(pointerToJITTargetAddress(registerAtExitHelper), + JITSymbolFlags()); cantFail(JD.define(absoluteSymbols(std::move(PerJDInterposes)))); auto Ctx = std::make_unique<LLVMContext>(); @@ -190,6 +193,14 @@ public: GlobalValue::HiddenVisibility, "__lljit.run_atexits_helper", {PlatformInstanceDecl, DSOHandle}); + auto *IntTy = Type::getIntNTy(*Ctx, sizeof(int) * CHAR_BIT); + auto *AtExitCallbackTy = FunctionType::get(VoidTy, {}, false); + auto *AtExitCallbackPtrTy = PointerType::getUnqual(AtExitCallbackTy); + addHelperAndWrapper(*M, "atexit", + FunctionType::get(IntTy, {AtExitCallbackPtrTy}, false), + GlobalValue::HiddenVisibility, "__lljit.atexit_helper", + {PlatformInstanceDecl, DSOHandle}); + return J.addIRModule(JD, ThreadSafeModule(std::move(M), std::move(Ctx))); } @@ -413,16 +424,25 @@ private: .takeError(); } - static void registerAtExitHelper(void *Self, void (*F)(void *), void *Ctx, - void *DSOHandle) { + static void registerCxaAtExitHelper(void *Self, void (*F)(void *), void *Ctx, + void *DSOHandle) { LLVM_DEBUG({ - dbgs() << "Registering atexit function " << (void *)F << " for JD " + dbgs() << "Registering cxa atexit function " << (void *)F << " for JD " << (*static_cast<JITDylib **>(DSOHandle))->getName() << "\n"; }); static_cast<GenericLLVMIRPlatformSupport *>(Self)->AtExitMgr.registerAtExit( F, Ctx, DSOHandle); } + static void registerAtExitHelper(void *Self, void *DSOHandle, void (*F)()) { + LLVM_DEBUG({ + dbgs() << "Registering atexit function " << (void *)F << " for JD " + << (*static_cast<JITDylib **>(DSOHandle))->getName() << "\n"; + }); + static_cast<GenericLLVMIRPlatformSupport *>(Self)->AtExitMgr.registerAtExit( + reinterpret_cast<void (*)(void *)>(F), nullptr, DSOHandle); + } + static void runAtExitsHelper(void *Self, void *DSOHandle) { LLVM_DEBUG({ dbgs() << "Running atexit functions for JD " @@ -450,12 +470,12 @@ private: auto *IntTy = Type::getIntNTy(*Ctx, sizeof(int) * CHAR_BIT); auto *VoidTy = Type::getVoidTy(*Ctx); auto *BytePtrTy = PointerType::getUnqual(Int8Ty); - auto *AtExitCallbackTy = FunctionType::get(VoidTy, {BytePtrTy}, false); - auto *AtExitCallbackPtrTy = PointerType::getUnqual(AtExitCallbackTy); + auto *CxaAtExitCallbackTy = FunctionType::get(VoidTy, {BytePtrTy}, false); + auto *CxaAtExitCallbackPtrTy = PointerType::getUnqual(CxaAtExitCallbackTy); addHelperAndWrapper( *M, "__cxa_atexit", - FunctionType::get(IntTy, {AtExitCallbackPtrTy, BytePtrTy, BytePtrTy}, + FunctionType::get(IntTy, {CxaAtExitCallbackPtrTy, BytePtrTy, BytePtrTy}, false), GlobalValue::DefaultVisibility, "__lljit.cxa_atexit_helper", {PlatformInstanceDecl}); @@ -521,11 +541,7 @@ GlobalCtorDtorScraper::operator()(ThreadSafeModule TSM, for (auto E : COrDtors) InitsOrDeInits.push_back(std::make_pair(E.Func, E.Priority)); - llvm::sort(InitsOrDeInits, - [](const std::pair<Function *, unsigned> &LHS, - const std::pair<Function *, unsigned> &RHS) { - return LHS.first < RHS.first; - }); + llvm::sort(InitsOrDeInits, llvm::less_second()); auto *InitOrDeInitFuncEntryBlock = BasicBlock::Create(Ctx, "entry", InitOrDeInitFunc); @@ -589,7 +605,7 @@ void LLJIT::PlatformSupport::setInitTransform( J.InitHelperTransformLayer->setTransform(std::move(T)); } -LLJIT::PlatformSupport::~PlatformSupport() {} +LLJIT::PlatformSupport::~PlatformSupport() = default; Error LLJITBuilderState::prepareForConstruction() { @@ -701,10 +717,14 @@ Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) { return addObjectFile(JD.getDefaultResourceTracker(), std::move(Obj)); } -Expected<JITEvaluatedSymbol> LLJIT::lookupLinkerMangled(JITDylib &JD, - SymbolStringPtr Name) { - return ES->lookup( - makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols), Name); +Expected<ExecutorAddr> LLJIT::lookupLinkerMangled(JITDylib &JD, + SymbolStringPtr Name) { + if (auto Sym = ES->lookup( + makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols), + Name)) + return ExecutorAddr(Sym->getAddress()); + else + return Sym.takeError(); } Expected<std::unique_ptr<ObjectLayer>> @@ -897,7 +917,7 @@ LLLazyJIT::LLLazyJIT(LLLazyJITBuilderState &S, Error &Err) : LLJIT(S, Err) { LCTMgr = std::move(S.LCTMgr); else { if (auto LCTMgrOrErr = createLocalLazyCallThroughManager( - S.TT, *ES, S.LazyCompileFailureAddr)) + S.TT, *ES, S.LazyCompileFailureAddr.getValue())) LCTMgr = std::move(*LCTMgrOrErr); else { Err = LCTMgrOrErr.takeError(); diff --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp b/llvm/lib/ExecutionEngine/Orc/Layer.cpp index adb8861793b1..4a50f2d7a153 100644 --- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp @@ -19,7 +19,7 @@ namespace llvm { namespace orc { -IRLayer::~IRLayer() {} +IRLayer::~IRLayer() = default; Error IRLayer::add(ResourceTrackerSP RT, ThreadSafeModule TSM) { assert(RT && "RT can not be null"); @@ -158,7 +158,7 @@ char ObjectLayer::ID; ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {} -ObjectLayer::~ObjectLayer() {} +ObjectLayer::~ObjectLayer() = default; Error ObjectLayer::add(ResourceTrackerSP RT, std::unique_ptr<MemoryBuffer> O, MaterializationUnit::Interface I) { diff --git a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp index 66453e6a632f..20b655bdf4b1 100644 --- a/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -131,6 +131,10 @@ createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, case Triple::mips64el: return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr); + case Triple::riscv64: + return LocalLazyCallThroughManager::Create<OrcRiscv64>(ES, + ErrorHandlerAddr); + case Triple::x86_64: if (T.getOS() == Triple::OSType::Win32) return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>( diff --git a/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp b/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp index 44cb78c773c9..3452267e4df4 100644 --- a/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LookupAndRecordAddrs.cpp @@ -24,7 +24,7 @@ void lookupAndRecordAddrs( Symbols.add(KV.first, LookupFlags); ES.lookup( - K, SearchOrder, Symbols, SymbolState::Ready, + K, SearchOrder, std::move(Symbols), SymbolState::Ready, [Pairs = std::move(Pairs), OnRec = std::move(OnRecorded)](Expected<SymbolMap> Result) mutable { if (!Result) @@ -47,7 +47,7 @@ Error lookupAndRecordAddrs( std::promise<MSVCPError> ResultP; auto ResultF = ResultP.get_future(); lookupAndRecordAddrs([&](Error Err) { ResultP.set_value(std::move(Err)); }, - ES, K, SearchOrder, Pairs, LookupFlags); + ES, K, SearchOrder, std::move(Pairs), LookupFlags); return ResultF.get(); } diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp index a364719855b4..d5274b06a76f 100644 --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -22,6 +22,39 @@ using namespace llvm; using namespace llvm::orc; using namespace llvm::orc::shared; +namespace llvm { +namespace orc { +namespace shared { + +using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>; +using SPSMachOJITDylibDepInfoMap = + SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>; + +template <> +class SPSSerializationTraits<SPSMachOJITDylibDepInfo, + MachOPlatform::MachOJITDylibDepInfo> { +public: + static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) { + return SPSMachOJITDylibDepInfo::AsArgList::size(DDI.Sealed, DDI.DepHeaders); + } + + static bool serialize(SPSOutputBuffer &OB, + const MachOPlatform::MachOJITDylibDepInfo &DDI) { + return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, DDI.Sealed, + DDI.DepHeaders); + } + + static bool deserialize(SPSInputBuffer &IB, + MachOPlatform::MachOJITDylibDepInfo &DDI) { + return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, DDI.Sealed, + DDI.DepHeaders); + } +}; + +} // namespace shared +} // namespace orc +} // namespace llvm + namespace { class MachOHeaderMaterializationUnit : public MaterializationUnit { @@ -199,11 +232,25 @@ MachOPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, } Error MachOPlatform::setupJITDylib(JITDylib &JD) { - return JD.define(std::make_unique<MachOHeaderMaterializationUnit>( - *this, MachOHeaderStartSymbol)); + if (auto Err = JD.define(std::make_unique<MachOHeaderMaterializationUnit>( + *this, MachOHeaderStartSymbol))) + return Err; + + return ES.lookup({&JD}, MachOHeaderStartSymbol).takeError(); } -Error MachOPlatform::teardownJITDylib(JITDylib &JD) { return Error::success(); } +Error MachOPlatform::teardownJITDylib(JITDylib &JD) { + std::lock_guard<std::mutex> Lock(PlatformMutex); + auto I = JITDylibToHeaderAddr.find(&JD); + if (I != JITDylibToHeaderAddr.end()) { + assert(HeaderAddrToJITDylib.count(I->second) && + "HeaderAddrToJITDylib missing entry"); + HeaderAddrToJITDylib.erase(I->second); + JITDylibToHeaderAddr.erase(I); + } + JITDylibToPThreadKey.erase(&JD); + return Error::success(); +} Error MachOPlatform::notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) { @@ -255,6 +302,10 @@ MachOPlatform::standardRuntimeUtilityAliases() { static const std::pair<const char *, const char *> StandardRuntimeUtilityAliases[] = { {"___orc_rt_run_program", "___orc_rt_macho_run_program"}, + {"___orc_rt_jit_dlerror", "___orc_rt_macho_jit_dlerror"}, + {"___orc_rt_jit_dlopen", "___orc_rt_macho_jit_dlopen"}, + {"___orc_rt_jit_dlclose", "___orc_rt_macho_jit_dlclose"}, + {"___orc_rt_jit_dlsym", "___orc_rt_macho_jit_dlsym"}, {"___orc_rt_log_error", "___orc_rt_log_error_to_stderr"}}; return ArrayRef<std::pair<const char *, const char *>>( @@ -305,16 +356,6 @@ MachOPlatform::MachOPlatform( State = BootstrapPhase2; - // PlatformJD hasn't been 'set-up' by the platform yet (since we're creating - // the platform now), so set it up. - if (auto E2 = setupJITDylib(PlatformJD)) { - Err = std::move(E2); - return; - } - - RegisteredInitSymbols[&PlatformJD].add( - MachOHeaderStartSymbol, SymbolLookupFlags::WeaklyReferencedSymbol); - // Associate wrapper function tags with JIT-side function implementations. if (auto E2 = associateRuntimeSupportFunctions(PlatformJD)) { Err = std::move(E2); @@ -329,23 +370,24 @@ MachOPlatform::MachOPlatform( return; } + // PlatformJD hasn't been set up by the platform yet (since we're creating + // the platform now), so set it up. + if (auto E2 = setupJITDylib(PlatformJD)) { + Err = std::move(E2); + return; + } + State = Initialized; } Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { ExecutionSession::JITDispatchHandlerAssociationMap WFs; - using GetInitializersSPSSig = - SPSExpected<SPSMachOJITDylibInitializerSequence>(SPSString); - WFs[ES.intern("___orc_rt_macho_get_initializers_tag")] = - ES.wrapAsyncWithSPS<GetInitializersSPSSig>( - this, &MachOPlatform::rt_getInitializers); - - using GetDeinitializersSPSSig = - SPSExpected<SPSMachOJITDylibDeinitializerSequence>(SPSExecutorAddr); - WFs[ES.intern("___orc_rt_macho_get_deinitializers_tag")] = - ES.wrapAsyncWithSPS<GetDeinitializersSPSSig>( - this, &MachOPlatform::rt_getDeinitializers); + using PushInitializersSPSSig = + SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr); + WFs[ES.intern("___orc_rt_macho_push_initializers_tag")] = + ES.wrapAsyncWithSPS<PushInitializersSPSSig>( + this, &MachOPlatform::rt_pushInitializers); using LookupSymbolSPSSig = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSString); @@ -356,53 +398,83 @@ Error MachOPlatform::associateRuntimeSupportFunctions(JITDylib &PlatformJD) { return ES.registerJITDispatchHandlers(PlatformJD, std::move(WFs)); } -void MachOPlatform::getInitializersBuildSequencePhase( - SendInitializerSequenceFn SendResult, JITDylib &JD, - std::vector<JITDylibSP> DFSLinkOrder) { - MachOJITDylibInitializerSequence FullInitSeq; - { - std::lock_guard<std::mutex> Lock(PlatformMutex); - for (auto &InitJD : reverse(DFSLinkOrder)) { - LLVM_DEBUG({ - dbgs() << "MachOPlatform: Appending inits for \"" << InitJD->getName() - << "\" to sequence\n"; - }); - auto ISItr = InitSeqs.find(InitJD.get()); - if (ISItr != InitSeqs.end()) { - FullInitSeq.emplace_back(std::move(ISItr->second)); - InitSeqs.erase(ISItr); - } - } - } +void MachOPlatform::pushInitializersLoop( + PushInitializersSendResultFn SendResult, JITDylibSP JD) { + DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; + DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap; + SmallVector<JITDylib *, 16> Worklist({JD.get()}); - SendResult(std::move(FullInitSeq)); -} + ES.runSessionLocked([&]() { + while (!Worklist.empty()) { + // FIXME: Check for defunct dylibs. -void MachOPlatform::getInitializersLookupPhase( - SendInitializerSequenceFn SendResult, JITDylib &JD) { + auto DepJD = Worklist.back(); + Worklist.pop_back(); - auto DFSLinkOrder = JD.getDFSLinkOrder(); - if (!DFSLinkOrder) { - SendResult(DFSLinkOrder.takeError()); - return; - } + // If we've already visited this JITDylib on this iteration then continue. + if (JDDepMap.count(DepJD)) + continue; - DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; - ES.runSessionLocked([&]() { - for (auto &InitJD : *DFSLinkOrder) { - auto RISItr = RegisteredInitSymbols.find(InitJD.get()); + // Add dep info. + auto &DM = JDDepMap[DepJD]; + DepJD->withLinkOrderDo([&](const JITDylibSearchOrder &O) { + for (auto &KV : O) { + if (KV.first == DepJD) + continue; + DM.push_back(KV.first); + Worklist.push_back(KV.first); + } + }); + + // Add any registered init symbols. + auto RISItr = RegisteredInitSymbols.find(DepJD); if (RISItr != RegisteredInitSymbols.end()) { - NewInitSymbols[InitJD.get()] = std::move(RISItr->second); + NewInitSymbols[DepJD] = std::move(RISItr->second); RegisteredInitSymbols.erase(RISItr); } } }); - // If there are no further init symbols to look up then move on to the next - // phase. + // If there are no further init symbols to look up then send the link order + // (as a list of header addresses) to the caller. if (NewInitSymbols.empty()) { - getInitializersBuildSequencePhase(std::move(SendResult), JD, - std::move(*DFSLinkOrder)); + + // To make the list intelligible to the runtime we need to convert all + // JITDylib pointers to their header addresses. + DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs; + HeaderAddrs.reserve(JDDepMap.size()); + { + std::lock_guard<std::mutex> Lock(PlatformMutex); + for (auto &KV : JDDepMap) { + auto I = JITDylibToHeaderAddr.find(KV.first); + if (I == JITDylibToHeaderAddr.end()) { + // The header address should have been materialized by the previous + // round, but we need to handle the pathalogical case where someone + // removes the symbol on another thread while we're running. + SendResult( + make_error<StringError>("JITDylib " + KV.first->getName() + + " has no registered header address", + inconvertibleErrorCode())); + return; + } + HeaderAddrs[KV.first] = I->second; + } + } + + // Build the dep info map to return. + MachOJITDylibDepInfoMap DIM; + DIM.reserve(JDDepMap.size()); + for (auto &KV : JDDepMap) { + assert(HeaderAddrs.count(KV.first) && "Missing header addr"); + auto H = HeaderAddrs[KV.first]; + MachOJITDylibDepInfo DepInfo; + for (auto &Dep : KV.second) { + assert(HeaderAddrs.count(Dep) && "Missing header addr"); + DepInfo.DepHeaders.push_back(HeaderAddrs[Dep]); + } + DIM.push_back(std::make_pair(H, std::move(DepInfo))); + } + SendResult(DIM); return; } @@ -412,58 +484,38 @@ void MachOPlatform::getInitializersLookupPhase( if (Err) SendResult(std::move(Err)); else - getInitializersLookupPhase(std::move(SendResult), JD); + pushInitializersLoop(std::move(SendResult), JD); }, ES, std::move(NewInitSymbols)); } -void MachOPlatform::rt_getInitializers(SendInitializerSequenceFn SendResult, - StringRef JDName) { - LLVM_DEBUG({ - dbgs() << "MachOPlatform::rt_getInitializers(\"" << JDName << "\")\n"; - }); - - JITDylib *JD = ES.getJITDylibByName(JDName); - if (!JD) { - LLVM_DEBUG({ - dbgs() << " No such JITDylib \"" << JDName << "\". Sending error.\n"; - }); - SendResult(make_error<StringError>("No JITDylib named " + JDName, - inconvertibleErrorCode())); - return; - } - - getInitializersLookupPhase(std::move(SendResult), *JD); -} - -void MachOPlatform::rt_getDeinitializers(SendDeinitializerSequenceFn SendResult, - ExecutorAddr Handle) { - LLVM_DEBUG({ - dbgs() << "MachOPlatform::rt_getDeinitializers(\"" - << formatv("{0:x}", Handle.getValue()) << "\")\n"; - }); - - JITDylib *JD = nullptr; - +void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult, + ExecutorAddr JDHeaderAddr) { + JITDylibSP JD; { std::lock_guard<std::mutex> Lock(PlatformMutex); - auto I = HeaderAddrToJITDylib.find(Handle); + auto I = HeaderAddrToJITDylib.find(JDHeaderAddr); if (I != HeaderAddrToJITDylib.end()) JD = I->second; } + LLVM_DEBUG({ + dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") "; + if (JD) + dbgs() << "pushing initializers for " << JD->getName() << "\n"; + else + dbgs() << "No JITDylib for header address.\n"; + }); + if (!JD) { - LLVM_DEBUG({ - dbgs() << " No JITDylib for handle " - << formatv("{0:x}", Handle.getValue()) << "\n"; - }); - SendResult(make_error<StringError>("No JITDylib associated with handle " + - formatv("{0:x}", Handle.getValue()), - inconvertibleErrorCode())); + SendResult( + make_error<StringError>("No JITDylib with header addr " + + formatv("{0:x}", JDHeaderAddr.getValue()), + inconvertibleErrorCode())); return; } - SendResult(MachOJITDylibDeinitializerSequence()); + pushInitializersLoop(std::move(SendResult), JD); } void MachOPlatform::rt_lookupSymbol(SendSymbolAddressFn SendResult, @@ -526,10 +578,14 @@ Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { &orc_rt_macho_platform_bootstrap}, {ES.intern("___orc_rt_macho_platform_shutdown"), &orc_rt_macho_platform_shutdown}, - {ES.intern("___orc_rt_macho_register_thread_data_section"), - &orc_rt_macho_register_thread_data_section}, - {ES.intern("___orc_rt_macho_deregister_thread_data_section"), - &orc_rt_macho_deregister_thread_data_section}, + {ES.intern("___orc_rt_macho_register_jitdylib"), + &orc_rt_macho_register_jitdylib}, + {ES.intern("___orc_rt_macho_deregister_jitdylib"), + &orc_rt_macho_deregister_jitdylib}, + {ES.intern("___orc_rt_macho_register_object_platform_sections"), + &orc_rt_macho_register_object_platform_sections}, + {ES.intern("___orc_rt_macho_deregister_object_platform_sections"), + &orc_rt_macho_deregister_object_platform_sections}, {ES.intern("___orc_rt_macho_create_pthread_key"), &orc_rt_macho_create_pthread_key}})) return Err; @@ -537,45 +593,6 @@ Error MachOPlatform::bootstrapMachORuntime(JITDylib &PlatformJD) { return ES.callSPSWrapper<void()>(orc_rt_macho_platform_bootstrap); } -Error MachOPlatform::registerInitInfo( - JITDylib &JD, ExecutorAddr ObjCImageInfoAddr, - ArrayRef<jitlink::Section *> InitSections) { - - std::unique_lock<std::mutex> Lock(PlatformMutex); - - MachOJITDylibInitializers *InitSeq = nullptr; - { - auto I = InitSeqs.find(&JD); - if (I == InitSeqs.end()) { - // If there's no init sequence entry yet then we need to look up the - // header symbol to force creation of one. - Lock.unlock(); - - auto SearchOrder = - JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); - if (auto Err = ES.lookup(SearchOrder, MachOHeaderStartSymbol).takeError()) - return Err; - - Lock.lock(); - I = InitSeqs.find(&JD); - assert(I != InitSeqs.end() && - "Entry missing after header symbol lookup?"); - } - InitSeq = &I->second; - } - - InitSeq->ObjCImageInfoAddress = ObjCImageInfoAddr; - - for (auto *Sec : InitSections) { - // FIXME: Avoid copy here. - jitlink::SectionRange R(*Sec); - InitSeq->InitSections[Sec->getName()].push_back( - {ExecutorAddr(R.getStart()), ExecutorAddr(R.getEnd())}); - } - - return Error::success(); -} - Expected<uint64_t> MachOPlatform::createPThreadKey() { if (!orc_rt_macho_create_pthread_key) return make_error<StringError>( @@ -617,11 +634,6 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( return Err; return processObjCImageInfo(G, MR); }); - - Config.PostFixupPasses.push_back( - [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { - return registerInitSections(G, JD); - }); } // --- Add passes for eh-frame and TLV support --- @@ -639,10 +651,12 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( return fixTLVSectionsAndEdges(G, JD); }); - // Add a pass to register the final addresses of the eh-frame and TLV sections - // with the runtime. - Config.PostFixupPasses.push_back( - [this](jitlink::LinkGraph &G) { return registerEHAndTLVSections(G); }); + // Add a pass to register the final addresses of any special sections in the + // object with the runtime. + Config.PostAllocationPasses.push_back( + [this, &JD = MR.getTargetJITDylib()](jitlink::LinkGraph &G) { + return registerObjectPlatformSections(G, JD); + }); } ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap @@ -661,7 +675,6 @@ MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol( jitlink::LinkGraph &G, MaterializationResponsibility &MR) { - auto I = llvm::find_if(G.defined_symbols(), [this](jitlink::Symbol *Sym) { return Sym->getName() == *MP.MachOHeaderStartSymbol; }); @@ -670,10 +683,14 @@ Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol( auto &JD = MR.getTargetJITDylib(); std::lock_guard<std::mutex> Lock(MP.PlatformMutex); auto HeaderAddr = (*I)->getAddress(); + MP.JITDylibToHeaderAddr[&JD] = HeaderAddr; MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; - assert(!MP.InitSeqs.count(&JD) && "InitSeq entry for JD already exists"); - MP.InitSeqs.insert( - std::make_pair(&JD, MachOJITDylibInitializers(JD.getName(), HeaderAddr))); + G.allocActions().push_back( + {cantFail( + WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>( + MP.orc_rt_macho_register_jitdylib, JD.getName(), HeaderAddr)), + cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( + MP.orc_rt_macho_deregister_jitdylib, HeaderAddr))}); return Error::success(); } @@ -792,37 +809,6 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( return Error::success(); } -Error MachOPlatform::MachOPlatformPlugin::registerInitSections( - jitlink::LinkGraph &G, JITDylib &JD) { - - ExecutorAddr ObjCImageInfoAddr; - SmallVector<jitlink::Section *> InitSections; - - if (auto *ObjCImageInfoSec = G.findSectionByName(ObjCImageInfoSectionName)) { - if (auto Addr = jitlink::SectionRange(*ObjCImageInfoSec).getStart()) - ObjCImageInfoAddr = Addr; - } - - for (auto InitSectionName : InitSectionNames) - if (auto *Sec = G.findSectionByName(InitSectionName)) - InitSections.push_back(Sec); - - // Dump the scraped inits. - LLVM_DEBUG({ - dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; - if (ObjCImageInfoAddr) - dbgs() << " " << ObjCImageInfoSectionName << ": " - << formatv("{0:x}", ObjCImageInfoAddr.getValue()) << "\n"; - for (auto *Sec : InitSections) { - jitlink::SectionRange R(*Sec); - dbgs() << " " << Sec->getName() << ": " - << formatv("[ {0:x} -- {1:x} ]", R.getStart(), R.getEnd()) << "\n"; - } - }); - - return MP.registerInitInfo(JD, ObjCImageInfoAddr, InitSections); -} - Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( jitlink::LinkGraph &G, JITDylib &JD) { @@ -879,11 +865,10 @@ Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( return Error::success(); } -Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections( - jitlink::LinkGraph &G) { +Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( + jitlink::LinkGraph &G, JITDylib &JD) { - // Add a pass to register the final addresses of the eh-frame and TLV sections - // with the runtime. + // Add an action to register the eh-frame. if (auto *EHFrameSection = G.findSectionByName(EHFrameSectionName)) { jitlink::SectionRange R(*EHFrameSection); if (!R.empty()) @@ -912,6 +897,8 @@ Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections( ThreadDataSection = ThreadBSSSection; } + SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs; + // Having merged thread BSS (if present) and thread data (if present), // record the resulting section range. if (ThreadDataSection) { @@ -922,16 +909,64 @@ Error MachOPlatform::MachOPlatformPlugin::registerEHAndTLVSections( "MachOPlatform has not finished booting", inconvertibleErrorCode()); - G.allocActions().push_back( - {cantFail( - WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - MP.orc_rt_macho_register_thread_data_section, R.getRange())), - cantFail( - WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>( - MP.orc_rt_macho_deregister_thread_data_section, - R.getRange()))}); + MachOPlatformSecs.push_back({ThreadDataSectionName, R.getRange()}); + } + } + + // If any platform sections were found then add an allocation action to call + // the registration function. + StringRef PlatformSections[] = { + ModInitFuncSectionName, ObjCClassListSectionName, + ObjCImageInfoSectionName, ObjCSelRefsSectionName, + Swift5ProtoSectionName, Swift5ProtosSectionName, + Swift5TypesSectionName, + }; + + for (auto &SecName : PlatformSections) { + auto *Sec = G.findSectionByName(SecName); + if (!Sec) + continue; + jitlink::SectionRange R(*Sec); + if (R.empty()) + continue; + + MachOPlatformSecs.push_back({SecName, R.getRange()}); + } + + if (!MachOPlatformSecs.empty()) { + Optional<ExecutorAddr> HeaderAddr; + { + std::lock_guard<std::mutex> Lock(MP.PlatformMutex); + auto I = MP.JITDylibToHeaderAddr.find(&JD); + if (I != MP.JITDylibToHeaderAddr.end()) + HeaderAddr = I->second; } + + if (!HeaderAddr) + return make_error<StringError>("Missing header for " + JD.getName(), + inconvertibleErrorCode()); + + // Dump the scraped inits. + LLVM_DEBUG({ + dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n"; + for (auto &KV : MachOPlatformSecs) + dbgs() << " " << KV.first << ": " << KV.second << "\n"; + }); + + using SPSRegisterObjectPlatformSectionsArgs = + SPSArgList<SPSExecutorAddr, + SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>; + G.allocActions().push_back( + {cantFail( + WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( + MP.orc_rt_macho_register_object_platform_sections, *HeaderAddr, + MachOPlatformSecs)), + cantFail( + WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( + MP.orc_rt_macho_deregister_object_platform_sections, + *HeaderAddr, MachOPlatformSecs))}); } + return Error::success(); } diff --git a/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp b/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp new file mode 100644 index 000000000000..8b3fbd7117e2 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/MemoryMapper.cpp @@ -0,0 +1,152 @@ +//===- MemoryMapper.cpp - Cross-process memory mapper ------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/Orc/MemoryMapper.h" + +namespace llvm { +namespace orc { + +MemoryMapper::~MemoryMapper() {} + +void InProcessMemoryMapper::reserve(size_t NumBytes, + OnReservedFunction OnReserved) { + std::error_code EC; + auto MB = sys::Memory::allocateMappedMemory( + NumBytes, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); + + if (EC) + return OnReserved(errorCodeToError(EC)); + + { + std::lock_guard<std::mutex> Lock(Mutex); + Reservations[MB.base()].Size = MB.allocatedSize(); + } + + OnReserved( + ExecutorAddrRange(ExecutorAddr::fromPtr(MB.base()), MB.allocatedSize())); +} + +char *InProcessMemoryMapper::prepare(ExecutorAddr Addr, size_t ContentSize) { + return Addr.toPtr<char *>(); +} + +void InProcessMemoryMapper::initialize(MemoryMapper::AllocInfo &AI, + OnInitializedFunction OnInitialized) { + ExecutorAddr MinAddr(~0ULL); + + for (auto &Segment : AI.Segments) { + auto Base = AI.MappingBase + Segment.Offset; + auto Size = Segment.ContentSize + Segment.ZeroFillSize; + + if (Base < MinAddr) + MinAddr = Base; + + std::memset((Base + Segment.ContentSize).toPtr<void *>(), 0, + Segment.ZeroFillSize); + + if (auto EC = sys::Memory::protectMappedMemory({Base.toPtr<void *>(), Size}, + Segment.Prot)) { + return OnInitialized(errorCodeToError(EC)); + } + if (Segment.Prot & sys::Memory::MF_EXEC) + sys::Memory::InvalidateInstructionCache(Base.toPtr<void *>(), Size); + } + + auto DeinitializeActions = shared::runFinalizeActions(AI.Actions); + if (!DeinitializeActions) + return OnInitialized(DeinitializeActions.takeError()); + + { + std::lock_guard<std::mutex> Lock(Mutex); + Allocations[MinAddr].DeinitializationActions = + std::move(*DeinitializeActions); + Reservations[AI.MappingBase.toPtr<void *>()].Allocations.push_back(MinAddr); + } + + OnInitialized(MinAddr); +} + +void InProcessMemoryMapper::deinitialize( + ArrayRef<ExecutorAddr> Bases, + MemoryMapper::OnDeinitializedFunction OnDeinitialized) { + Error AllErr = Error::success(); + + { + std::lock_guard<std::mutex> Lock(Mutex); + + for (auto Base : Bases) { + + if (Error Err = shared::runDeallocActions( + Allocations[Base].DeinitializationActions)) { + AllErr = joinErrors(std::move(AllErr), std::move(Err)); + } + + Allocations.erase(Base); + } + } + + OnDeinitialized(std::move(AllErr)); +} + +void InProcessMemoryMapper::release(ArrayRef<ExecutorAddr> Bases, + OnReleasedFunction OnReleased) { + Error Err = Error::success(); + + for (auto Base : Bases) { + std::vector<ExecutorAddr> AllocAddrs; + size_t Size; + { + std::lock_guard<std::mutex> Lock(Mutex); + auto &R = Reservations[Base.toPtr<void *>()]; + Size = R.Size; + AllocAddrs.swap(R.Allocations); + } + + // deinitialize sub allocations + std::promise<MSVCPError> P; + auto F = P.get_future(); + deinitialize(AllocAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); + if (Error E = F.get()) { + Err = joinErrors(std::move(Err), std::move(E)); + } + + // free the memory + auto MB = sys::MemoryBlock(Base.toPtr<void *>(), Size); + + auto EC = sys::Memory::releaseMappedMemory(MB); + if (EC) { + Err = joinErrors(std::move(Err), errorCodeToError(EC)); + } + + std::lock_guard<std::mutex> Lock(Mutex); + Reservations.erase(Base.toPtr<void *>()); + } + + OnReleased(std::move(Err)); +} + +InProcessMemoryMapper::~InProcessMemoryMapper() { + std::vector<ExecutorAddr> ReservationAddrs; + { + std::lock_guard<std::mutex> Lock(Mutex); + + ReservationAddrs.reserve(Reservations.size()); + for (const auto &R : Reservations) { + ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst())); + } + } + + std::promise<MSVCPError> P; + auto F = P.get_future(); + release(ReservationAddrs, [&](Error Err) { P.set_value(std::move(Err)); }); + cantFail(F.get()); +} + +} // namespace orc + +} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp index c1ad569dd65d..394a555e453b 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp @@ -63,7 +63,6 @@ getMachOObjectFileSymbolInfo(ExecutionSession &ES, auto Name = Sym.getName(); if (!Name) return Name.takeError(); - auto InternedName = ES.intern(*Name); auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); if (!SymFlags) return SymFlags.takeError(); @@ -72,7 +71,7 @@ getMachOObjectFileSymbolInfo(ExecutionSession &ES, if (Name->startswith("l")) *SymFlags &= ~JITSymbolFlags::Exported; - I.SymbolFlags[InternedName] = std::move(*SymFlags); + I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); } for (auto &Sec : Obj.sections()) { @@ -121,7 +120,7 @@ getELFObjectFileSymbolInfo(ExecutionSession &ES, auto Name = Sym.getName(); if (!Name) return Name.takeError(); - auto InternedName = ES.intern(*Name); + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); if (!SymFlags) return SymFlags.takeError(); @@ -130,7 +129,7 @@ getELFObjectFileSymbolInfo(ExecutionSession &ES, if (Sym.getBinding() == ELF::STB_GNU_UNIQUE) *SymFlags |= JITSymbolFlags::Weak; - I.SymbolFlags[InternedName] = std::move(*SymFlags); + I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); } SymbolStringPtr InitSymbol; @@ -175,12 +174,12 @@ getGenericObjectFileSymbolInfo(ExecutionSession &ES, auto Name = Sym.getName(); if (!Name) return Name.takeError(); - auto InternedName = ES.intern(*Name); + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); if (!SymFlags) return SymFlags.takeError(); - I.SymbolFlags[InternedName] = std::move(*SymFlags); + I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); } return I; diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index 32c5998a789b..5ddb35cbafd5 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -78,9 +78,12 @@ private: } static bool hasELFInitSection(LinkGraph &G) { - for (auto &Sec : G.sections()) - if (Sec.getName() == ".init_array") + for (auto &Sec : G.sections()) { + auto SecName = Sec.getName(); + if (SecName.consume_front(".init_array") && + (SecName.empty() || SecName[0] == '.')) return true; + } return false; } @@ -226,12 +229,13 @@ public: } for (auto *Sym : G.absolute_symbols()) - if (Sym->hasName()) { + if (Sym->hasName() && Sym->getScope() != Scope::Local) { auto InternedName = ES.intern(Sym->getName()); JITSymbolFlags Flags; - Flags |= JITSymbolFlags::Absolute; if (Sym->isCallable()) Flags |= JITSymbolFlags::Callable; + if (Sym->getScope() == Scope::Default) + Flags |= JITSymbolFlags::Exported; if (Sym->getLinkage() == Linkage::Weak) Flags |= JITSymbolFlags::Weak; InternedResult[InternedName] = @@ -607,7 +611,7 @@ private: DenseMap<SymbolStringPtr, SymbolNameSet> InternalNamedSymbolDeps; }; -ObjectLinkingLayer::Plugin::~Plugin() {} +ObjectLinkingLayer::Plugin::~Plugin() = default; char ObjectLinkingLayer::ID; diff --git a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp index 18b3c5e12b1c..ef764a3f0d7f 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp @@ -906,5 +906,176 @@ void OrcMips64::writeIndirectStubsBlock( Stub[8 * I + 7] = 0x00000000; // nop } } + +void OrcRiscv64::writeResolverCode(char *ResolverWorkingMem, + JITTargetAddress ResolverTargetAddress, + JITTargetAddress ReentryFnAddr, + JITTargetAddress ReentryCtxAddr) { + + const uint32_t ResolverCode[] = { + 0xef810113, // 0x00: addi sp,sp,-264 + 0x00813023, // 0x04: sd s0,0(sp) + 0x00913423, // 0x08: sd s1,8(sp) + 0x01213823, // 0x0c: sd s2,16(sp) + 0x01313c23, // 0x10: sd s3,24(sp) + 0x03413023, // 0x14: sd s4,32(sp) + 0x03513423, // 0x18: sd s5,40(sp) + 0x03613823, // 0x1c: sd s6,48(sp) + 0x03713c23, // 0x20: sd s7,56(sp) + 0x05813023, // 0x24: sd s8,64(sp) + 0x05913423, // 0x28: sd s9,72(sp) + 0x05a13823, // 0x2c: sd s10,80(sp) + 0x05b13c23, // 0x30: sd s11,88(sp) + 0x06113023, // 0x34: sd ra,96(sp) + 0x06a13423, // 0x38: sd a0,104(sp) + 0x06b13823, // 0x3c: sd a1,112(sp) + 0x06c13c23, // 0x40: sd a2,120(sp) + 0x08d13023, // 0x44: sd a3,128(sp) + 0x08e13423, // 0x48: sd a4,136(sp) + 0x08f13823, // 0x4c: sd a5,144(sp) + 0x09013c23, // 0x50: sd a6,152(sp) + 0x0b113023, // 0x54: sd a7,160(sp) + 0x0a813427, // 0x58: fsd fs0,168(sp) + 0x0a913827, // 0x5c: fsd fs1,176(sp) + 0x0b213c27, // 0x60: fsd fs2,184(sp) + 0x0d313027, // 0x64: fsd fs3,192(sp) + 0x0d413427, // 0x68: fsd fs4,200(sp) + 0x0d513827, // 0x6c: fsd fs5,208(sp) + 0x0d613c27, // 0x70: fsd fs6,216(sp) + 0x0f713027, // 0x74: fsd fs7,224(sp) + 0x0f813427, // 0x78: fsd fs8,232(sp) + 0x0f913827, // 0x7c: fsd fs9,240(sp) + 0x0fa13c27, // 0x80: fsd fs10,248(sp) + 0x11b13027, // 0x84: fsd fs11,256(sp) + 0x00000517, // 0x88: auipc a0,0x0 + 0x0b053503, // 0x8c: ld a0,176(a0) # 0x138 + 0x00030593, // 0x90: mv a1,t1 + 0xff458593, // 0x94: addi a1,a1,-12 + 0x00000617, // 0x98: auipc a2,0x0 + 0x0a863603, // 0x9c: ld a2,168(a2) # 0x140 + 0x000600e7, // 0xa0: jalr a2 + 0x00050293, // 0xa4: mv t0,a0 + 0x00013403, // 0xa8: ld s0,0(sp) + 0x00813483, // 0xac: ld s1,8(sp) + 0x01013903, // 0xb0: ld s2,16(sp) + 0x01813983, // 0xb4: ld s3,24(sp) + 0x02013a03, // 0xb8: ld s4,32(sp) + 0x02813a83, // 0xbc: ld s5,40(sp) + 0x03013b03, // 0xc0: ld s6,48(sp) + 0x03813b83, // 0xc4: ld s7,56(sp) + 0x04013c03, // 0xc8: ld s8,64(sp) + 0x04813c83, // 0xcc: ld s9,72(sp) + 0x05013d03, // 0xd0: ld s10,80(sp) + 0x05813d83, // 0xd4: ld s11,88(sp) + 0x06013083, // 0xd8: ld ra,96(sp) + 0x06813503, // 0xdc: ld a0,104(sp) + 0x07013583, // 0xe0: ld a1,112(sp) + 0x07813603, // 0xe4: ld a2,120(sp) + 0x08013683, // 0xe8: ld a3,128(sp) + 0x08813703, // 0xec: ld a4,136(sp) + 0x09013783, // 0xf0: ld a5,144(sp) + 0x09813803, // 0xf4: ld a6,152(sp) + 0x0a013883, // 0xf8: ld a7,160(sp) + 0x0a813407, // 0xfc: fld fs0,168(sp) + 0x0b013487, // 0x100: fld fs1,176(sp) + 0x0b813907, // 0x104: fld fs2,184(sp) + 0x0c013987, // 0x108: fld fs3,192(sp) + 0x0c813a07, // 0x10c: fld fs4,200(sp) + 0x0d013a87, // 0x110: fld fs5,208(sp) + 0x0d813b07, // 0x114: fld fs6,216(sp) + 0x0e013b87, // 0x118: fld fs7,224(sp) + 0x0e813c07, // 0x11c: fld fs8,232(sp) + 0x0f013c87, // 0x120: fld fs9,240(sp) + 0x0f813d07, // 0x124: fld fs10,248(sp) + 0x10013d87, // 0x128: fld fs11,256(sp) + 0x10810113, // 0x12c: addi sp,sp,264 + 0x00028067, // 0x130: jr t0 + 0x12345678, // 0x134: padding to align at 8 byte + 0x12345678, // 0x138: Lreentry_ctx_ptr: + 0xdeadbeef, // 0x13c: .quad 0 + 0x98765432, // 0x140: Lreentry_fn_ptr: + 0xcafef00d // 0x144: .quad 0 + }; + + const unsigned ReentryCtxAddrOffset = 0x138; + const unsigned ReentryFnAddrOffset = 0x140; + + memcpy(ResolverWorkingMem, ResolverCode, sizeof(ResolverCode)); + memcpy(ResolverWorkingMem + ReentryFnAddrOffset, &ReentryFnAddr, + sizeof(uint64_t)); + memcpy(ResolverWorkingMem + ReentryCtxAddrOffset, &ReentryCtxAddr, + sizeof(uint64_t)); +} + +void OrcRiscv64::writeTrampolines(char *TrampolineBlockWorkingMem, + JITTargetAddress TrampolineBlockTargetAddress, + JITTargetAddress ResolverAddr, + unsigned NumTrampolines) { + + unsigned OffsetToPtr = alignTo(NumTrampolines * TrampolineSize, 8); + + memcpy(TrampolineBlockWorkingMem + OffsetToPtr, &ResolverAddr, + sizeof(uint64_t)); + + uint32_t *Trampolines = + reinterpret_cast<uint32_t *>(TrampolineBlockWorkingMem); + for (unsigned I = 0; I < NumTrampolines; ++I, OffsetToPtr -= TrampolineSize) { + uint32_t Hi20 = (OffsetToPtr + 0x800) & 0xFFFFF000; + uint32_t Lo12 = OffsetToPtr - Hi20; + Trampolines[4 * I + 0] = 0x00000297 | Hi20; // auipc t0, %hi(Lptr) + Trampolines[4 * I + 1] = + 0x0002b283 | ((Lo12 & 0xFFF) << 20); // ld t0, %lo(Lptr) + Trampolines[4 * I + 2] = 0x00028367; // jalr t1, t0 + Trampolines[4 * I + 3] = 0xdeadface; // padding + } +} + +void OrcRiscv64::writeIndirectStubsBlock( + char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, + JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) { + // Stub format is: + // + // .section __orc_stubs + // stub1: + // auipc t0, %hi(ptr1) ; PC-rel load of ptr1 + // ld t0, %lo(t0) + // jr t0 ; Jump to resolver + // .quad 0 ; Pad to 16 bytes + // stub2: + // auipc t0, %hi(ptr1) ; PC-rel load of ptr1 + // ld t0, %lo(t0) + // jr t0 ; Jump to resolver + // .quad 0 + // + // ... + // + // .section __orc_ptrs + // ptr1: + // .quad 0x0 + // ptr2: + // .quad 0x0 + // + // ... + + assert(stubAndPointerRangesOk<OrcRiscv64>( + StubsBlockTargetAddress, PointersBlockTargetAddress, NumStubs) && + "PointersBlock is out of range"); + + uint32_t *Stub = reinterpret_cast<uint32_t *>(StubsBlockWorkingMem); + + for (unsigned I = 0; I < NumStubs; ++I) { + uint64_t PtrDisplacement = + PointersBlockTargetAddress - StubsBlockTargetAddress; + uint32_t Hi20 = (PtrDisplacement + 0x800) & 0xFFFFF000; + uint32_t Lo12 = PtrDisplacement - Hi20; + Stub[4 * I + 0] = 0x00000297 | Hi20; // auipc t0, %hi(Lptr) + Stub[4 * I + 1] = 0x0002b283 | ((Lo12 & 0xFFF) << 20); // ld t0, %lo(Lptr) + Stub[4 * I + 2] = 0x00028067; // jr t0 + Stub[4 * I + 3] = 0xfeedbeef; // padding + PointersBlockTargetAddress += PointerSize; + StubsBlockTargetAddress += StubSize; + } +} + } // End namespace orc. } // End namespace llvm. diff --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp index 71be8dfdc004..b7eab6b85ecf 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp @@ -106,82 +106,6 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -namespace llvm { -namespace orc { - -class CAPIDefinitionGenerator final : public DefinitionGenerator { -public: - CAPIDefinitionGenerator( - void *Ctx, - LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate) - : Ctx(Ctx), TryToGenerate(TryToGenerate) {} - - Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, - JITDylibLookupFlags JDLookupFlags, - const SymbolLookupSet &LookupSet) override { - - // Take the lookup state. - LLVMOrcLookupStateRef LSR = ::wrap(OrcV2CAPIHelper::extractLookupState(LS)); - - // Translate the lookup kind. - LLVMOrcLookupKind CLookupKind; - switch (K) { - case LookupKind::Static: - CLookupKind = LLVMOrcLookupKindStatic; - break; - case LookupKind::DLSym: - CLookupKind = LLVMOrcLookupKindDLSym; - break; - } - - // Translate the JITDylibSearchFlags. - LLVMOrcJITDylibLookupFlags CJDLookupFlags; - switch (JDLookupFlags) { - case JITDylibLookupFlags::MatchExportedSymbolsOnly: - CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly; - break; - case JITDylibLookupFlags::MatchAllSymbols: - CJDLookupFlags = LLVMOrcJITDylibLookupFlagsMatchAllSymbols; - break; - } - - // Translate the lookup set. - std::vector<LLVMOrcCLookupSetElement> CLookupSet; - CLookupSet.reserve(LookupSet.size()); - for (auto &KV : LookupSet) { - LLVMOrcSymbolLookupFlags SLF; - LLVMOrcSymbolStringPoolEntryRef Name = - ::wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(KV.first)); - switch (KV.second) { - case SymbolLookupFlags::RequiredSymbol: - SLF = LLVMOrcSymbolLookupFlagsRequiredSymbol; - break; - case SymbolLookupFlags::WeaklyReferencedSymbol: - SLF = LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol; - break; - } - CLookupSet.push_back({Name, SLF}); - } - - // Run the C TryToGenerate function. - auto Err = unwrap(TryToGenerate(::wrap(this), Ctx, &LSR, CLookupKind, - ::wrap(&JD), CJDLookupFlags, - CLookupSet.data(), CLookupSet.size())); - - // Restore the lookup state. - OrcV2CAPIHelper::resetLookupState(LS, ::unwrap(LSR)); - - return Err; - } - -private: - void *Ctx; - LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate; -}; - -} // end namespace orc -} // end namespace llvm - namespace { class OrcCAPIMaterializationUnit : public llvm::orc::MaterializationUnit { @@ -282,8 +206,134 @@ toSymbolDependenceMap(LLVMOrcCDependenceMapPairs Pairs, size_t NumPairs) { return SDM; } +static LookupKind toLookupKind(LLVMOrcLookupKind K) { + switch (K) { + case LLVMOrcLookupKindStatic: + return LookupKind::Static; + case LLVMOrcLookupKindDLSym: + return LookupKind::DLSym; + } + llvm_unreachable("unrecognized LLVMOrcLookupKind value"); +} + +static LLVMOrcLookupKind fromLookupKind(LookupKind K) { + switch (K) { + case LookupKind::Static: + return LLVMOrcLookupKindStatic; + case LookupKind::DLSym: + return LLVMOrcLookupKindDLSym; + } + llvm_unreachable("unrecognized LookupKind value"); +} + +static JITDylibLookupFlags +toJITDylibLookupFlags(LLVMOrcJITDylibLookupFlags LF) { + switch (LF) { + case LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly: + return JITDylibLookupFlags::MatchExportedSymbolsOnly; + case LLVMOrcJITDylibLookupFlagsMatchAllSymbols: + return JITDylibLookupFlags::MatchAllSymbols; + } + llvm_unreachable("unrecognized LLVMOrcJITDylibLookupFlags value"); +} + +static LLVMOrcJITDylibLookupFlags +fromJITDylibLookupFlags(JITDylibLookupFlags LF) { + switch (LF) { + case JITDylibLookupFlags::MatchExportedSymbolsOnly: + return LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly; + case JITDylibLookupFlags::MatchAllSymbols: + return LLVMOrcJITDylibLookupFlagsMatchAllSymbols; + } + llvm_unreachable("unrecognized JITDylibLookupFlags value"); +} + +static SymbolLookupFlags toSymbolLookupFlags(LLVMOrcSymbolLookupFlags SLF) { + switch (SLF) { + case LLVMOrcSymbolLookupFlagsRequiredSymbol: + return SymbolLookupFlags::RequiredSymbol; + case LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol: + return SymbolLookupFlags::WeaklyReferencedSymbol; + } + llvm_unreachable("unrecognized LLVMOrcSymbolLookupFlags value"); +} + +static LLVMOrcSymbolLookupFlags fromSymbolLookupFlags(SymbolLookupFlags SLF) { + switch (SLF) { + case SymbolLookupFlags::RequiredSymbol: + return LLVMOrcSymbolLookupFlagsRequiredSymbol; + case SymbolLookupFlags::WeaklyReferencedSymbol: + return LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol; + } + llvm_unreachable("unrecognized SymbolLookupFlags value"); +} + +static LLVMJITEvaluatedSymbol +fromJITEvaluatedSymbol(const JITEvaluatedSymbol &S) { + return {S.getAddress(), fromJITSymbolFlags(S.getFlags())}; +} + } // end anonymous namespace +namespace llvm { +namespace orc { + +class CAPIDefinitionGenerator final : public DefinitionGenerator { +public: + CAPIDefinitionGenerator( + LLVMOrcDisposeCAPIDefinitionGeneratorFunction Dispose, void *Ctx, + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate) + : Dispose(Dispose), Ctx(Ctx), TryToGenerate(TryToGenerate) {} + + ~CAPIDefinitionGenerator() { + if (Dispose) + Dispose(Ctx); + } + + Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, + JITDylibLookupFlags JDLookupFlags, + const SymbolLookupSet &LookupSet) override { + + // Take the lookup state. + LLVMOrcLookupStateRef LSR = ::wrap(OrcV2CAPIHelper::extractLookupState(LS)); + + // Translate the lookup kind. + LLVMOrcLookupKind CLookupKind = fromLookupKind(K); + + // Translate the JITDylibLookupFlags. + LLVMOrcJITDylibLookupFlags CJDLookupFlags = + fromJITDylibLookupFlags(JDLookupFlags); + + // Translate the lookup set. + std::vector<LLVMOrcCLookupSetElement> CLookupSet; + CLookupSet.reserve(LookupSet.size()); + for (auto &KV : LookupSet) { + LLVMOrcSymbolStringPoolEntryRef Name = + ::wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(KV.first)); + LLVMOrcSymbolLookupFlags SLF = fromSymbolLookupFlags(KV.second); + CLookupSet.push_back({Name, SLF}); + } + + // Run the C TryToGenerate function. + auto Err = unwrap(TryToGenerate(::wrap(this), Ctx, &LSR, CLookupKind, + ::wrap(&JD), CJDLookupFlags, + CLookupSet.data(), CLookupSet.size())); + + // Restore the lookup state. + OrcV2CAPIHelper::resetLookupState(LS, ::unwrap(LSR)); + + return Err; + } + +private: + LLVMOrcDisposeCAPIDefinitionGeneratorFunction Dispose; + void *Ctx; + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction TryToGenerate; +}; + +} // end namespace orc +} // end namespace llvm + void LLVMOrcExecutionSessionSetErrorReporter( LLVMOrcExecutionSessionRef ES, LLVMOrcErrorReporterFunction ReportError, void *Ctx) { @@ -307,6 +357,42 @@ LLVMOrcExecutionSessionIntern(LLVMOrcExecutionSessionRef ES, const char *Name) { OrcV2CAPIHelper::moveFromSymbolStringPtr(unwrap(ES)->intern(Name))); } +void LLVMOrcExecutionSessionLookup( + LLVMOrcExecutionSessionRef ES, LLVMOrcLookupKind K, + LLVMOrcCJITDylibSearchOrder SearchOrder, size_t SearchOrderSize, + LLVMOrcCLookupSet Symbols, size_t SymbolsSize, + LLVMOrcExecutionSessionLookupHandleResultFunction HandleResult, void *Ctx) { + assert(ES && "ES cannot be null"); + assert(SearchOrder && "SearchOrder cannot be null"); + assert(Symbols && "Symbols cannot be null"); + assert(HandleResult && "HandleResult cannot be null"); + + JITDylibSearchOrder SO; + for (size_t I = 0; I != SearchOrderSize; ++I) + SO.push_back({unwrap(SearchOrder[I].JD), + toJITDylibLookupFlags(SearchOrder[I].JDLookupFlags)}); + + SymbolLookupSet SLS; + for (size_t I = 0; I != SymbolsSize; ++I) + SLS.add(OrcV2CAPIHelper::moveToSymbolStringPtr(unwrap(Symbols[I].Name)), + toSymbolLookupFlags(Symbols[I].LookupFlags)); + + unwrap(ES)->lookup( + toLookupKind(K), SO, std::move(SLS), SymbolState::Ready, + [HandleResult, Ctx](Expected<SymbolMap> Result) { + if (Result) { + SmallVector<LLVMOrcCSymbolMapPair> CResult; + for (auto &KV : *Result) + CResult.push_back(LLVMOrcCSymbolMapPair{ + wrap(OrcV2CAPIHelper::getRawPoolEntryPtr(KV.first)), + fromJITEvaluatedSymbol(KV.second)}); + HandleResult(LLVMErrorSuccess, CResult.data(), CResult.size(), Ctx); + } else + HandleResult(wrap(Result.takeError()), nullptr, 0, Ctx); + }, + NoDependenciesToRegister); +} + void LLVMOrcRetainSymbolStringPoolEntry(LLVMOrcSymbolStringPoolEntryRef S) { OrcV2CAPIHelper::retainPoolEntry(unwrap(S)); } @@ -589,11 +675,19 @@ void LLVMOrcJITDylibAddGenerator(LLVMOrcJITDylibRef JD, } LLVMOrcDefinitionGeneratorRef LLVMOrcCreateCustomCAPIDefinitionGenerator( - LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F, void *Ctx) { - auto DG = std::make_unique<CAPIDefinitionGenerator>(Ctx, F); + LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction F, void *Ctx, + LLVMOrcDisposeCAPIDefinitionGeneratorFunction Dispose) { + auto DG = std::make_unique<CAPIDefinitionGenerator>(Dispose, Ctx, F); return wrap(DG.release()); } +void LLVMOrcLookupStateContinueLookup(LLVMOrcLookupStateRef S, + LLVMErrorRef Err) { + LookupState LS; + OrcV2CAPIHelper::resetLookupState(LS, ::unwrap(S)); + LS.continueLookup(unwrap(Err)); +} + LLVMErrorRef LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess( LLVMOrcDefinitionGeneratorRef *Result, char GlobalPrefix, LLVMOrcSymbolPredicate Filter, void *FilterCtx) { @@ -951,7 +1045,7 @@ LLVMErrorRef LLVMOrcLLJITLookup(LLVMOrcLLJITRef J, return wrap(Sym.takeError()); } - *Result = Sym->getAddress(); + *Result = Sym->getValue(); return LLVMErrorSuccess; } diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp index 64fc717b7b56..2bb204e688fc 100644 --- a/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.cpp @@ -43,8 +43,8 @@ const char *DispatchFnName = "__llvm_orc_SimpleRemoteEPC_dispatch_fn"; } // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames -SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() {} -SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() {} +SimpleRemoteEPCTransportClient::~SimpleRemoteEPCTransportClient() = default; +SimpleRemoteEPCTransport::~SimpleRemoteEPCTransport() = default; Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>> FDSimpleRemoteEPCTransport::Create(SimpleRemoteEPCTransportClient &C, int InFD, diff --git a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp index 0b4755fe23cf..b52d01318c0d 100644 --- a/llvm/lib/ExecutionEngine/Orc/Speculation.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Speculation.cpp @@ -85,7 +85,7 @@ void IRSpeculationLayer::emit(std::unique_ptr<MaterializationResponsibility> R, auto IRNames = QueryAnalysis(Fn); // Instrument and register if Query has result - if (IRNames.hasValue()) { + if (IRNames) { // Emit globals for each function. auto LoadValueTy = Type::getInt8Ty(MContext); @@ -126,7 +126,7 @@ void IRSpeculationLayer::emit(std::unique_ptr<MaterializationResponsibility> R, assert(Mutator.GetInsertBlock()->getParent() == &Fn && "IR builder association mismatch?"); - S.registerSymbols(internToJITSymbols(IRNames.getValue()), + S.registerSymbols(internToJITSymbols(*IRNames), &R->getTargetJITDylib()); } } diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp index b6b21bde1182..8ab0af3eab6e 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleRemoteEPCServer.cpp @@ -22,9 +22,9 @@ using namespace llvm::orc::shared; namespace llvm { namespace orc { -ExecutorBootstrapService::~ExecutorBootstrapService() {} +ExecutorBootstrapService::~ExecutorBootstrapService() = default; -SimpleRemoteEPCServer::Dispatcher::~Dispatcher() {} +SimpleRemoteEPCServer::Dispatcher::~Dispatcher() = default; #if LLVM_ENABLE_THREADS void SimpleRemoteEPCServer::ThreadDispatcher::dispatch( diff --git a/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp b/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp index 111c84ec87ed..11a99986f2ee 100644 --- a/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TaskDispatch.cpp @@ -16,7 +16,7 @@ char GenericNamedTask::ID = 0; const char *GenericNamedTask::DefaultDescription = "Generic Task"; void Task::anchor() {} -TaskDispatcher::~TaskDispatcher() {} +TaskDispatcher::~TaskDispatcher() = default; void InPlaceTaskDispatcher::dispatch(std::unique_ptr<Task> T) { T->run(); } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp index 9c8d402364c6..bc42eebf3fec 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp @@ -29,7 +29,7 @@ namespace llvm { -RTDyldMemoryManager::~RTDyldMemoryManager() {} +RTDyldMemoryManager::~RTDyldMemoryManager() = default; #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \ !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) @@ -95,18 +95,16 @@ void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr, // and projects/libunwind/src/UnwindLevel1-gcc-ext.c. const char *P = (const char *)Addr; const char *End = P + Size; - do { + while (P != End) P = processFDE(P, false); - } while(P != End); } void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr, size_t Size) { const char *P = (const char *)Addr; const char *End = P + Size; - do { + while (P != End) P = processFDE(P, true); - } while(P != End); } #else diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 3f38d26869d4..2e0cba849165 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -66,7 +66,7 @@ std::error_code RuntimeDyldError::convertToErrorCode() const { } // Empty out-of-line virtual destructor as the key function. -RuntimeDyldImpl::~RuntimeDyldImpl() {} +RuntimeDyldImpl::~RuntimeDyldImpl() = default; // Pin LoadedObjectInfo's vtables to this file. void RuntimeDyld::LoadedObjectInfo::anchor() {} @@ -1311,7 +1311,7 @@ RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr, ProcessAllSections = false; } -RuntimeDyld::~RuntimeDyld() {} +RuntimeDyld::~RuntimeDyld() = default; static std::unique_ptr<RuntimeDyldCOFF> createRuntimeDyldCOFF( diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 33db23408cf2..ae1bb5a1da4b 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MSVCErrorWorkarounds.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include <cctype> #include <memory> @@ -892,7 +893,7 @@ RuntimeDyldChecker::RuntimeDyldChecker( std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter, ErrStream)) {} -RuntimeDyldChecker::~RuntimeDyldChecker() {} +RuntimeDyldChecker::~RuntimeDyldChecker() = default; bool RuntimeDyldChecker::check(StringRef CheckExpr) const { return Impl->check(CheckExpr); diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index f92618afdff6..da1102fc9f07 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -216,7 +216,7 @@ namespace llvm { RuntimeDyldELF::RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver) : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0) {} -RuntimeDyldELF::~RuntimeDyldELF() {} +RuntimeDyldELF::~RuntimeDyldELF() = default; void RuntimeDyldELF::registerEHFrames() { for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { @@ -446,6 +446,13 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, write(isBE, TargetPtr, static_cast<uint32_t>(Result)); break; } + case ELF::R_AARCH64_PREL16: { + uint64_t Result = Value + Addend - FinalAddress; + assert(static_cast<int64_t>(Result) >= INT16_MIN && + static_cast<int64_t>(Result) <= UINT16_MAX); + write(isBE, TargetPtr, static_cast<uint16_t>(Result & 0xffffU)); + break; + } case ELF::R_AARCH64_PREL32: { uint64_t Result = Value + Addend - FinalAddress; assert(static_cast<int64_t>(Result) >= INT32_MIN && diff --git a/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp b/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp index 56b232b9dbcd..b23e33039c35 100644 --- a/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp @@ -238,7 +238,7 @@ SectionMemoryManager::~SectionMemoryManager() { } } -SectionMemoryManager::MemoryMapper::~MemoryMapper() {} +SectionMemoryManager::MemoryMapper::~MemoryMapper() = default; void SectionMemoryManager::anchor() {} |
