diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine')
20 files changed, 1374 insertions, 55 deletions
diff --git a/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp b/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp index 29a623ebe449..f1eeee3b3599 100644 --- a/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp +++ b/llvm/lib/ExecutionEngine/GDBRegistrationListener.cpp @@ -12,7 +12,6 @@ #include "llvm/Object/ObjectFile.h" #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> @@ -91,11 +90,18 @@ typedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo> /// object files that are in executable memory managed by the client of this /// class. class GDBJITRegistrationListener : public JITEventListener { + /// Lock used to serialize all jit registration events, since they + /// modify global variables. + /// + /// Only a single instance of GDBJITRegistrationListener is ever created, + /// and so the lock can be a member variable of that instance. This ensures + /// destructors are run in the correct order. + sys::Mutex JITDebugLock; + /// A map of in-memory object files that have been registered with the /// JIT interface. RegisteredObjectBufferMap ObjectBufferMap; -public: /// Instantiates the JIT service. GDBJITRegistrationListener() = default; @@ -103,6 +109,12 @@ public: /// internal resources. ~GDBJITRegistrationListener() override; +public: + static GDBJITRegistrationListener &instance() { + static GDBJITRegistrationListener Instance; + return Instance; + } + /// Creates an entry in the JIT registry for the buffer @p Object, /// which must contain an object file in executable memory with any /// debug information for the debugger. @@ -121,10 +133,6 @@ private: void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); }; -/// Lock used to serialize all jit registration events, since they -/// modify global variables. -ManagedStatic<sys::Mutex> JITDebugLock; - /// Do the registration. void NotifyDebugger(jit_code_entry* JITCodeEntry) { __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; @@ -143,7 +151,7 @@ void NotifyDebugger(jit_code_entry* JITCodeEntry) { GDBJITRegistrationListener::~GDBJITRegistrationListener() { // Free all registered object files. - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + std::lock_guard<llvm::sys::Mutex> locked(JITDebugLock); for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end(); I != E; ++I) { @@ -167,7 +175,7 @@ void GDBJITRegistrationListener::notifyObjectLoaded( const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + std::lock_guard<llvm::sys::Mutex> locked(JITDebugLock); assert(ObjectBufferMap.find(K) == ObjectBufferMap.end() && "Second attempt to perform debug registration."); jit_code_entry* JITCodeEntry = new jit_code_entry(); @@ -186,7 +194,7 @@ void GDBJITRegistrationListener::notifyObjectLoaded( } void GDBJITRegistrationListener::notifyFreeingObject(ObjectKey K) { - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + std::lock_guard<llvm::sys::Mutex> locked(JITDebugLock); RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(K); if (I != ObjectBufferMap.end()) { @@ -228,14 +236,12 @@ void GDBJITRegistrationListener::deregisterObjectInternal( JITCodeEntry = nullptr; } -llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener; - } // end namespace namespace llvm { JITEventListener* JITEventListener::createGDBRegistrationListener() { - return &*GDBRegListener; + return &GDBJITRegistrationListener::instance(); } } // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/COFF.cpp b/llvm/lib/ExecutionEngine/JITLink/COFF.cpp new file mode 100644 index 000000000000..fddc9b813fb2 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/COFF.cpp @@ -0,0 +1,137 @@ +//===-------------- COFF.cpp - JIT linker function for COFF -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// COFF jit-link function. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITLink/COFF.h" + +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cstring> + +using namespace llvm; + +#define DEBUG_TYPE "jitlink" + +namespace llvm { +namespace jitlink { + +static StringRef getMachineName(uint16_t Machine) { + switch (Machine) { + case COFF::IMAGE_FILE_MACHINE_I386: + return "i386"; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return "x86_64"; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + return "ARM"; + case COFF::IMAGE_FILE_MACHINE_ARM64: + return "ARM64"; + default: + return "unknown"; + } +} + +Expected<std::unique_ptr<LinkGraph>> +createLinkGraphFromCOFFObject(MemoryBufferRef ObjectBuffer) { + StringRef Data = ObjectBuffer.getBuffer(); + + // Check magic + auto Magic = identify_magic(ObjectBuffer.getBuffer()); + if (Magic != file_magic::coff_object) + return make_error<JITLinkError>("Invalid COFF buffer"); + + if (Data.size() < sizeof(object::coff_file_header)) + return make_error<JITLinkError>("Truncated COFF buffer"); + + uint64_t CurPtr = 0; + bool IsPE = false; + + // Check if this is a PE/COFF file. + if (Data.size() >= sizeof(object::dos_header) + sizeof(COFF::PEMagic)) { + const auto *DH = + reinterpret_cast<const object::dos_header *>(Data.data() + CurPtr); + if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') { + // Check the PE magic bytes. ("PE\0\0") + CurPtr = DH->AddressOfNewExeHeader; + if (memcmp(Data.data() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != + 0) { + return make_error<JITLinkError>("Incorrect PE magic"); + } + CurPtr += sizeof(COFF::PEMagic); + IsPE = true; + } + } + if (Data.size() < CurPtr + sizeof(object::coff_file_header)) + return make_error<JITLinkError>("Truncated COFF buffer"); + + const object::coff_file_header *COFFHeader = + reinterpret_cast<const object::coff_file_header *>(Data.data() + CurPtr); + const object::coff_bigobj_file_header *COFFBigObjHeader = nullptr; + + // Deal with bigobj file + if (!IsPE && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN && + COFFHeader->NumberOfSections == uint16_t(0xffff) && + Data.size() >= sizeof(object::coff_bigobj_file_header)) { + if (Data.size() < sizeof(object::coff_file_header)) { + return make_error<JITLinkError>("Truncated COFF buffer"); + } + COFFBigObjHeader = + reinterpret_cast<const object::coff_bigobj_file_header *>(Data.data() + + CurPtr); + + // Verify that we are dealing with bigobj. + if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion && + std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, + sizeof(COFF::BigObjMagic)) == 0) { + COFFHeader = nullptr; + CurPtr += sizeof(object::coff_bigobj_file_header); + } else + COFFBigObjHeader = nullptr; + } + + uint16_t Machine = + COFFHeader ? COFFHeader->Machine : COFFBigObjHeader->Machine; + LLVM_DEBUG({ + dbgs() << "jitLink_COFF: PE = " << (IsPE ? "yes" : "no") + << ", bigobj = " << (COFFBigObjHeader ? "yes" : "no") + << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() << "\" " + << "machine = " << getMachineName(Machine) << "\n"; + }); + + switch (Machine) { + case COFF::IMAGE_FILE_MACHINE_AMD64: + return createLinkGraphFromCOFFObject_x86_64(ObjectBuffer); + default: + return make_error<JITLinkError>( + "Unsupported target machine architecture in COFF object " + + ObjectBuffer.getBufferIdentifier() + ": " + getMachineName(Machine)); + } +} + +void link_COFF(std::unique_ptr<LinkGraph> G, + std::unique_ptr<JITLinkContext> Ctx) { + switch (G->getTargetTriple().getArch()) { + case Triple::x86_64: + link_COFF_x86_64(std::move(G), std::move(Ctx)); + return; + default: + Ctx->notifyFailed(make_error<JITLinkError>( + "Unsupported target machine architecture in COFF link graph " + + G->getName())); + return; + } +} + +} // end namespace jitlink +} // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp new file mode 100644 index 000000000000..43b9c2ba400b --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp @@ -0,0 +1,527 @@ +//=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Generic COFF LinkGraph buliding code. +// +//===----------------------------------------------------------------------===// +#include "COFFLinkGraphBuilder.h" + +#define DEBUG_TYPE "jitlink" + +static const char *CommonSectionName = "__common"; + +namespace llvm { +namespace jitlink { + +COFFLinkGraphBuilder::COFFLinkGraphBuilder( + const object::COFFObjectFile &Obj, Triple TT, + LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) + : Obj(Obj), + G(std::make_unique<LinkGraph>( + Obj.getFileName().str(), Triple(std::move(TT)), getPointerSize(Obj), + getEndianness(Obj), std::move(GetEdgeKindName))) { + LLVM_DEBUG({ + dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName() + << "\"\n"; + }); +} + +COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default; + +unsigned +COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) { + return Obj.getBytesInAddress(); +} + +support::endianness +COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) { + return Obj.isLittleEndian() ? support::little : support::big; +} + +uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj, + const object::coff_section *Sec) { + // Consider the difference between executable form and object form. + // More information is inside COFFObjectFile::getSectionSize + if (Obj.getDOSHeader()) + return std::min(Sec->VirtualSize, Sec->SizeOfRawData); + return Sec->SizeOfRawData; +} + +uint64_t +COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj, + const object::coff_section *Section) { + return Section->VirtualAddress + Obj.getImageBase(); +} + +bool COFFLinkGraphBuilder::isComdatSection( + const object::coff_section *Section) { + return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT; +} + +Section &COFFLinkGraphBuilder::getCommonSection() { + if (!CommonSection) + CommonSection = + &G->createSection(CommonSectionName, MemProt::Read | MemProt::Write); + return *CommonSection; +} + +Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() { + if (!Obj.isRelocatableObject()) + return make_error<JITLinkError>("Object is not a relocatable COFF file"); + + if (auto Err = graphifySections()) + return std::move(Err); + + if (auto Err = graphifySymbols()) + return std::move(Err); + + if (auto Err = addRelocations()) + return std::move(Err); + + return std::move(G); +} + +StringRef +COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex, + const object::coff_section *Sec, + object::COFFSymbolRef Sym) { + switch (SectionIndex) { + case COFF::IMAGE_SYM_UNDEFINED: { + if (Sym.getValue()) + return "(common)"; + else + return "(external)"; + } + case COFF::IMAGE_SYM_ABSOLUTE: + return "(absolute)"; + case COFF::IMAGE_SYM_DEBUG: { + // Used with .file symbol + return "(debug)"; + } + default: { + // Non reserved regular section numbers + if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec)) + return *SecNameOrErr; + } + } + return ""; +} + +Error COFFLinkGraphBuilder::graphifySections() { + LLVM_DEBUG(dbgs() << " Creating graph sections...\n"); + + GraphBlocks.resize(Obj.getNumberOfSections() + 1); + // For each section... + for (COFFSectionIndex SecIndex = 1; + SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); + SecIndex++) { + Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex); + if (!Sec) + return Sec.takeError(); + + StringRef SectionName; + if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec)) + SectionName = *SecNameOrErr; + + bool IsDiscardable = + (*Sec)->Characteristics & + (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO); + if (IsDiscardable) { + LLVM_DEBUG(dbgs() << " " << SecIndex << ": \"" << SectionName + << "\" is discardable: " + "No graph section will be created.\n"); + continue; + } + + // FIXME: Skip debug info sections + + LLVM_DEBUG({ + dbgs() << " " + << "Creating section for \"" << SectionName << "\"\n"; + }); + + // Get the section's memory protection flags. + MemProt Prot = MemProt::None; + if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE) + Prot |= MemProt::Exec; + if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ) + Prot |= MemProt::Read; + if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE) + Prot |= MemProt::Write; + + // Look for existing sections first. + auto *GraphSec = G->findSectionByName(SectionName); + if (!GraphSec) + GraphSec = &G->createSection(SectionName, Prot); + if (GraphSec->getMemProt() != Prot) + return make_error<JITLinkError>("MemProt should match"); + + Block *B = nullptr; + if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + B = &G->createZeroFillBlock( + *GraphSec, getSectionSize(Obj, *Sec), + orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), + (*Sec)->getAlignment(), 0); + else { + ArrayRef<uint8_t> Data; + if (auto Err = Obj.getSectionContents(*Sec, Data)) + return Err; + + B = &G->createContentBlock( + *GraphSec, + ArrayRef<char>(reinterpret_cast<const char *>(Data.data()), + Data.size()), + orc::ExecutorAddr(getSectionAddress(Obj, *Sec)), + (*Sec)->getAlignment(), 0); + } + + setGraphBlock(SecIndex, B); + } + + return Error::success(); +} + +Error COFFLinkGraphBuilder::graphifySymbols() { + LLVM_DEBUG(dbgs() << " Creating graph symbols...\n"); + + SymbolSets.resize(Obj.getNumberOfSections() + 1); + GraphSymbols.resize(Obj.getNumberOfSymbols()); + + for (COFFSymbolIndex SymIndex = 0; + SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols()); + SymIndex++) { + Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex); + if (!Sym) + return Sym.takeError(); + + StringRef SymbolName; + if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym)) + SymbolName = *SymNameOrErr; + + COFFSectionIndex SectionIndex = Sym->getSectionNumber(); + const object::coff_section *Sec = nullptr; + + if (!COFF::isReservedSectionNumber(SectionIndex)) { + auto SecOrErr = Obj.getSection(SectionIndex); + if (!SecOrErr) + return make_error<JITLinkError>( + "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) + + " (" + toString(SecOrErr.takeError()) + ")"); + Sec = *SecOrErr; + } + + // Create jitlink symbol + jitlink::Symbol *GSym = nullptr; + if (Sym->isFileRecord()) + LLVM_DEBUG({ + dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \"" + << SymbolName << "\" in " + << getCOFFSectionName(SectionIndex, Sec, *Sym) + << " (index: " << SectionIndex << ") \n"; + }); + else if (Sym->isUndefined()) { + LLVM_DEBUG({ + dbgs() << " " << SymIndex + << ": Creating external graph symbol for COFF symbol \"" + << SymbolName << "\" in " + << getCOFFSectionName(SectionIndex, Sec, *Sym) + << " (index: " << SectionIndex << ") \n"; + }); + GSym = + &G->addExternalSymbol(SymbolName, Sym->getValue(), Linkage::Strong); + } else if (Sym->isWeakExternal()) { + COFFSymbolIndex TagIndex = + Sym->getAux<object::coff_aux_weak_external>()->TagIndex; + assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics != + COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY && + "IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY is not supported."); + assert(Sym->getAux<object::coff_aux_weak_external>()->Characteristics != + COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY && + "IMAGE_WEAK_EXTERN_SEARCH_LIBRARY is not supported."); + WeakAliasRequests.push_back({SymIndex, TagIndex, SymbolName}); + } else { + Expected<jitlink::Symbol *> NewGSym = + createDefinedSymbol(SymIndex, SymbolName, *Sym, Sec); + if (!NewGSym) + return NewGSym.takeError(); + GSym = *NewGSym; + if (GSym) { + LLVM_DEBUG({ + dbgs() << " " << SymIndex + << ": Creating defined graph symbol for COFF symbol \"" + << SymbolName << "\" in " + << getCOFFSectionName(SectionIndex, Sec, *Sym) + << " (index: " << SectionIndex << ") \n"; + dbgs() << " " << *GSym << "\n"; + }); + } + } + + // Register the symbol + if (GSym) + setGraphSymbol(SectionIndex, SymIndex, *GSym); + SymIndex += Sym->getNumberOfAuxSymbols(); + } + + if (auto Err = flushWeakAliasRequests()) + return Err; + + if (auto Err = calculateImplicitSizeOfSymbols()) + return Err; + + return Error::success(); +} + +Error COFFLinkGraphBuilder::flushWeakAliasRequests() { + // Export the weak external symbols and alias it + for (auto &WeakAlias : WeakAliasRequests) { + if (auto *Target = getGraphSymbol(WeakAlias.Target)) { + Expected<object::COFFSymbolRef> AliasSymbol = + Obj.getSymbol(WeakAlias.Alias); + if (!AliasSymbol) + return AliasSymbol.takeError(); + + // FIXME: Support this when there's a way to handle this. + if (!Target->isDefined()) + return make_error<JITLinkError>("Weak external symbol with external " + "symbol as alternative not supported."); + + jitlink::Symbol *NewSymbol = &G->addDefinedSymbol( + Target->getBlock(), Target->getOffset(), WeakAlias.SymbolName, + Target->getSize(), Linkage::Weak, Scope::Default, + Target->isCallable(), false); + setGraphSymbol(AliasSymbol->getSectionNumber(), WeakAlias.Alias, + *NewSymbol); + LLVM_DEBUG({ + dbgs() << " " << WeakAlias.Alias + << ": Creating weak external symbol for COFF symbol \"" + << WeakAlias.SymbolName << "\" in section " + << AliasSymbol->getSectionNumber() << "\n"; + dbgs() << " " << *NewSymbol << "\n"; + }); + } else + return make_error<JITLinkError>("Weak symbol alias requested but actual " + "symbol not found for symbol " + + formatv("{0:d}", WeakAlias.Alias)); + } + return Error::success(); +} + +// In COFF, most of the defined symbols don't contain the size information. +// Hence, we calculate the "implicit" size of symbol by taking the delta of +// offsets of consecutive symbols within a block. We maintain a balanced tree +// set of symbols sorted by offset per each block in order to achieve +// logarithmic time complexity of sorted symbol insertion. Symbol is inserted to +// the set once it's processed in graphifySymbols. In this function, we iterate +// each collected symbol in sorted order and calculate the implicit size. +Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() { + for (COFFSectionIndex SecIndex = 1; + SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections()); + SecIndex++) { + auto &SymbolSet = SymbolSets[SecIndex]; + jitlink::Block *B = getGraphBlock(SecIndex); + orc::ExecutorAddrDiff LastOffset = B->getSize(); + orc::ExecutorAddrDiff LastDifferentOffset = B->getSize(); + orc::ExecutorAddrDiff LastSize = 0; + for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) { + orc::ExecutorAddrDiff Offset = It->first; + jitlink::Symbol *Symbol = It->second; + orc::ExecutorAddrDiff CandSize; + // Last offset can be same when aliasing happened + if (Symbol->getOffset() == LastOffset) + CandSize = LastSize; + else + CandSize = LastOffset - Offset; + + LLVM_DEBUG({ + if (Offset + Symbol->getSize() > LastDifferentOffset) + dbgs() << " Overlapping symbol range generated for the following " + "symbol:" + << "\n" + << " " << *Symbol << "\n"; + }); + (void)LastDifferentOffset; + if (LastOffset != Offset) + LastDifferentOffset = Offset; + LastSize = CandSize; + LastOffset = Offset; + if (Symbol->getSize()) { + // Non empty symbol can happen in COMDAT symbol. + // We don't consider the possibility of overlapping symbol range that + // could be introduced by disparity between inferred symbol size and + // defined symbol size because symbol size information is currently only + // used by jitlink-check where we have control to not make overlapping + // ranges. + continue; + } + + LLVM_DEBUG({ + if (!CandSize) + dbgs() << " Empty implicit symbol size generated for the following " + "symbol:" + << "\n" + << " " << *Symbol << "\n"; + }); + + Symbol->setSize(CandSize); + } + } + return Error::success(); +} + +Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol( + COFFSymbolIndex SymIndex, StringRef SymbolName, + object::COFFSymbolRef Symbol, const object::coff_section *Section) { + if (Symbol.isCommon()) { + // FIXME: correct alignment + return &G->addCommonSymbol(SymbolName, Scope::Default, getCommonSection(), + orc::ExecutorAddr(), Symbol.getValue(), + Symbol.getValue(), false); + } + if (Symbol.isAbsolute()) + return &G->addAbsoluteSymbol(SymbolName, + orc::ExecutorAddr(Symbol.getValue()), 0, + Linkage::Strong, Scope::Local, false); + + if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber())) + return make_error<JITLinkError>( + "Reserved section number used in regular symbol " + + formatv("{0:d}", SymIndex)); + + Block *B = getGraphBlock(Symbol.getSectionNumber()); + if (Symbol.isExternal()) { + // This is not a comdat sequence, export the symbol as it is + if (!isComdatSection(Section)) + return &G->addDefinedSymbol( + *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default, + Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); + else { + if (!PendingComdatExport) + return make_error<JITLinkError>("No pending COMDAT export for symbol " + + formatv("{0:d}", SymIndex)); + if (PendingComdatExport->SectionIndex != Symbol.getSectionNumber()) + return make_error<JITLinkError>( + "COMDAT export section number mismatch for symbol " + + formatv("{0:d}", SymIndex)); + return exportCOMDATSymbol(SymIndex, SymbolName, Symbol); + } + } + + if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC) { + const object::coff_aux_section_definition *Definition = + Symbol.getSectionDefinition(); + if (!Definition || !isComdatSection(Section)) { + // Handle typical static symbol + return &G->addDefinedSymbol( + *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, + Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); + } + if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + // FIXME: don't dead strip this when parent section is alive + return &G->addDefinedSymbol( + *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local, + Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false); + } + if (PendingComdatExport) + return make_error<JITLinkError>( + "COMDAT export request already exists before symbol " + + formatv("{0:d}", SymIndex)); + return createCOMDATExportRequest(SymIndex, Symbol, Definition); + } + return make_error<JITLinkError>("Unsupported storage class " + + formatv("{0:d}", Symbol.getStorageClass()) + + " in symbol " + formatv("{0:d}", SymIndex)); +} + +// COMDAT handling: +// When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section, +// the section is called a COMDAT section. It contains two symbols +// in a sequence that specifes the behavior. First symbol is the section +// symbol which contains the size and name of the section. It also contains +// selection type that specifies how duplicate of the symbol is handled. +// Second symbol is COMDAT symbol which usually defines the external name and +// data type. +// +// Since two symbols always come in a specific order, we initiate pending COMDAT +// export request when we encounter the first symbol and actually exports it +// when we process the second symbol. +// +// Process the first symbol of COMDAT sequence. +Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest( + COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, + const object::coff_aux_section_definition *Definition) { + Block *B = getGraphBlock(Symbol.getSectionNumber()); + Linkage L = Linkage::Strong; + switch (Definition->Selection) { + case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: { + L = Linkage::Strong; + break; + } + case COFF::IMAGE_COMDAT_SELECT_ANY: { + L = Linkage::Weak; + break; + } + case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: + case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: { + // FIXME: Implement size/content validation when LinkGraph is able to + // handle this. + L = Linkage::Weak; + break; + } + case COFF::IMAGE_COMDAT_SELECT_LARGEST: { + // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST when LinkGraph is able to + // handle this. + return make_error<JITLinkError>( + "IMAGE_COMDAT_SELECT_LARGEST is not supported."); + } + case COFF::IMAGE_COMDAT_SELECT_NEWEST: { + // Even link.exe doesn't support this selection properly. + return make_error<JITLinkError>( + "IMAGE_COMDAT_SELECT_NEWEST is not supported."); + } + default: { + return make_error<JITLinkError>("Invalid comdat selection type: " + + formatv("{0:d}", Definition->Selection)); + } + } + PendingComdatExport = {SymIndex, Symbol.getSectionNumber(), L}; + return &G->addAnonymousSymbol(*B, Symbol.getValue(), Definition->Length, + false, false); +} + +// Process the second symbol of COMDAT sequence. +Expected<Symbol *> +COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex, + StringRef SymbolName, + object::COFFSymbolRef Symbol) { + COFFSymbolIndex TargetIndex = PendingComdatExport->SymbolIndex; + Linkage L = PendingComdatExport->Linkage; + jitlink::Symbol *Target = getGraphSymbol(TargetIndex); + assert(Target && "COMDAT leaader is invalid."); + assert((llvm::count_if(G->defined_symbols(), + [&](const jitlink::Symbol *Sym) { + return Sym->getName() == SymbolName; + }) == 0) && + "Duplicate defined symbol"); + Target->setName(SymbolName); + Target->setLinkage(L); + Target->setCallable(Symbol.getComplexType() == + COFF::IMAGE_SYM_DTYPE_FUNCTION); + Target->setScope(Scope::Default); + LLVM_DEBUG({ + dbgs() << " " << SymIndex + << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName + << "\" in section " << Symbol.getSectionNumber() << "\n"; + dbgs() << " " << *Target << "\n"; + }); + PendingComdatExport = None; + return Target; +} + +} // namespace jitlink +} // namespace llvm
\ No newline at end of file diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h new file mode 100644 index 000000000000..4dc1b14dc4a2 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h @@ -0,0 +1,199 @@ +//===----- COFFLinkGraphBuilder.h - COFF LinkGraph builder ----*- 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 +// +//===----------------------------------------------------------------------===// +// +// Generic COFF LinkGraph building code. +// +//===----------------------------------------------------------------------===// + +#ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H +#define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ExecutionEngine/JITLink/JITLink.h" +#include "llvm/Object/COFF.h" + +#include "EHFrameSupportImpl.h" +#include "JITLinkGeneric.h" + +#define DEBUG_TYPE "jitlink" + +#include <list> + +namespace llvm { +namespace jitlink { + +class COFFLinkGraphBuilder { +public: + virtual ~COFFLinkGraphBuilder(); + Expected<std::unique_ptr<LinkGraph>> buildGraph(); + +protected: + using COFFSectionIndex = int32_t; + using COFFSymbolIndex = int32_t; + + COFFLinkGraphBuilder(const object::COFFObjectFile &Obj, Triple TT, + LinkGraph::GetEdgeKindNameFunction GetEdgeKindName); + + LinkGraph &getGraph() const { return *G; } + + const object::COFFObjectFile &getObject() const { return Obj; } + + virtual Error addRelocations() = 0; + + Error graphifySections(); + Error graphifySymbols(); + + void setGraphSymbol(COFFSectionIndex SecIndex, COFFSymbolIndex SymIndex, + Symbol &Sym) { + assert(!GraphSymbols[SymIndex] && "Duplicate symbol at index"); + GraphSymbols[SymIndex] = &Sym; + if (!COFF::isReservedSectionNumber(SecIndex)) + SymbolSets[SecIndex].insert({Sym.getOffset(), &Sym}); + } + + Symbol *getGraphSymbol(COFFSymbolIndex SymIndex) const { + if (SymIndex < 0 || + SymIndex >= static_cast<COFFSymbolIndex>(GraphSymbols.size())) + return nullptr; + return GraphSymbols[SymIndex]; + } + + void setGraphBlock(COFFSectionIndex SecIndex, Block *B) { + assert(!GraphBlocks[SecIndex] && "Duplicate section at index"); + assert(!COFF::isReservedSectionNumber(SecIndex) && "Invalid section index"); + GraphBlocks[SecIndex] = B; + } + + Block *getGraphBlock(COFFSectionIndex SecIndex) const { + if (SecIndex <= 0 || + SecIndex >= static_cast<COFFSectionIndex>(GraphSymbols.size())) + return nullptr; + return GraphBlocks[SecIndex]; + } + + object::COFFObjectFile::section_iterator_range sections() const { + return Obj.sections(); + } + + /// Traverse all matching relocation records in the given section. The handler + /// function Func should be callable with this signature: + /// Error(const object::RelocationRef&, + /// const object::SectionRef&, Section &) + /// + template <typename RelocHandlerFunction> + Error forEachRelocation(const object::SectionRef &RelSec, + RelocHandlerFunction &&Func, + bool ProcessDebugSections = false); + + /// Traverse all matching relocation records in the given section. Convenience + /// wrapper to allow passing a member function for the handler. + /// + template <typename ClassT, typename RelocHandlerMethod> + Error forEachRelocation(const object::SectionRef &RelSec, ClassT *Instance, + RelocHandlerMethod &&Method, + bool ProcessDebugSections = false) { + return forEachRelocation( + RelSec, + [Instance, Method](const auto &Rel, const auto &Target, auto &GS) { + return (Instance->*Method)(Rel, Target, GS); + }, + ProcessDebugSections); + } + +private: + // Pending comdat symbol export that is initiated by the first symbol of + // COMDAT sequence. + struct ComdatExportRequest { + COFFSymbolIndex SymbolIndex; + COFFSectionIndex SectionIndex; + jitlink::Linkage Linkage; + }; + Optional<ComdatExportRequest> PendingComdatExport; + + // This represents a pending request to create a weak external symbol with a + // name. + struct WeakAliasRequest { + COFFSymbolIndex Alias; + COFFSymbolIndex Target; + StringRef SymbolName; + }; + std::vector<WeakAliasRequest> WeakAliasRequests; + + // Per COFF section jitlink symbol set sorted by offset. + // Used for calculating implicit size of defined symbols. + using SymbolSet = std::set<std::pair<orc::ExecutorAddrDiff, Symbol *>>; + std::vector<SymbolSet> SymbolSets; + + Section &getCommonSection(); + + Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex, + StringRef SymbolName, + object::COFFSymbolRef Symbol, + const object::coff_section *Section); + Expected<Symbol *> createCOMDATExportRequest( + COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol, + const object::coff_aux_section_definition *Definition); + Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex, + StringRef SymbolName, + object::COFFSymbolRef Symbol); + Error flushWeakAliasRequests(); + Error calculateImplicitSizeOfSymbols(); + + static uint64_t getSectionAddress(const object::COFFObjectFile &Obj, + const object::coff_section *Section); + static uint64_t getSectionSize(const object::COFFObjectFile &Obj, + const object::coff_section *Section); + static bool isComdatSection(const object::coff_section *Section); + static unsigned getPointerSize(const object::COFFObjectFile &Obj); + static support::endianness getEndianness(const object::COFFObjectFile &Obj); + StringRef getCOFFSectionName(COFFSectionIndex SectionIndex, + const object::coff_section *Sec, + object::COFFSymbolRef Sym); + + const object::COFFObjectFile &Obj; + std::unique_ptr<LinkGraph> G; + + Section *CommonSection = nullptr; + std::vector<Block *> GraphBlocks; + std::vector<Symbol *> GraphSymbols; +}; + +template <typename RelocHandlerFunction> +Error COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef &RelSec, + RelocHandlerFunction &&Func, + bool ProcessDebugSections) { + + auto COFFRelSect = Obj.getCOFFSection(RelSec); + + // Target sections have names in valid COFF object files. + Expected<StringRef> Name = Obj.getSectionName(COFFRelSect); + if (!Name) + return Name.takeError(); + LLVM_DEBUG(dbgs() << " " << *Name << ":\n"); + + // Lookup the link-graph node corresponding to the target section name. + auto *BlockToFix = getGraphBlock(RelSec.getIndex() + 1); + if (!BlockToFix) + return make_error<StringError>( + "Referencing a section that wasn't added to the graph: " + *Name, + inconvertibleErrorCode()); + + // Let the callee process relocation entries one by one. + for (const auto &R : RelSec.relocations()) + if (Error Err = Func(R, RelSec, *BlockToFix)) + return Err; + + LLVM_DEBUG(dbgs() << "\n"); + return Error::success(); +} + +} // end namespace jitlink +} // end namespace llvm + +#endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H diff --git a/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp new file mode 100644 index 000000000000..3d36ad1ed767 --- /dev/null +++ b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp @@ -0,0 +1,216 @@ +//===----- COFF_x86_64.cpp - JIT linker implementation for COFF/x86_64 ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// COFF/x86_64 jit-link implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITLink/COFF_x86_64.h" +#include "COFFLinkGraphBuilder.h" +#include "EHFrameSupportImpl.h" +#include "JITLinkGeneric.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/ExecutionEngine/JITLink/x86_64.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Endian.h" + +#define DEBUG_TYPE "jitlink" + +using namespace llvm; +using namespace llvm::jitlink; + +namespace { + +class COFFJITLinker_x86_64 : public JITLinker<COFFJITLinker_x86_64> { + friend class JITLinker<COFFJITLinker_x86_64>; + +public: + COFFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, + std::unique_ptr<LinkGraph> G, + PassConfiguration PassConfig) + : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} + +private: + Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { + return x86_64::applyFixup(G, B, E, nullptr); + } +}; + +class COFFLinkGraphBuilder_x86_64 : public COFFLinkGraphBuilder { +private: + uint64_t ImageBase = 0; + enum COFFX86RelocationKind { + COFFAddr32NB, + COFFRel32, + }; + + static Expected<COFFX86RelocationKind> + getRelocationKind(const uint32_t Type) { + switch (Type) { + case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_ADDR32NB: + return COFFAddr32NB; + case COFF::RelocationTypeAMD64::IMAGE_REL_AMD64_REL32: + return COFFRel32; + } + + return make_error<JITLinkError>("Unsupported x86_64 relocation:" + + formatv("{0:d}", Type)); + } + + Error addRelocations() override { + + LLVM_DEBUG(dbgs() << "Processing relocations:\n"); + + for (const auto &RelSect : sections()) + if (Error Err = COFFLinkGraphBuilder::forEachRelocation( + RelSect, this, &COFFLinkGraphBuilder_x86_64::addSingleRelocation)) + return Err; + + return Error::success(); + } + + uint64_t getImageBase() { + if (!ImageBase) { + ImageBase = std::numeric_limits<uint64_t>::max(); + for (const auto &Block : getGraph().blocks()) { + if (Block->getAddress().getValue()) + ImageBase = std::min(ImageBase, Block->getAddress().getValue()); + } + } + return ImageBase; + } + + Error addSingleRelocation(const object::RelocationRef &Rel, + const object::SectionRef &FixupSect, + Block &BlockToFix) { + + const object::coff_relocation *COFFRel = getObject().getCOFFRelocation(Rel); + auto SymbolIt = Rel.getSymbol(); + if (SymbolIt == getObject().symbol_end()) { + return make_error<StringError>( + formatv("Invalid symbol index in relocation entry. " + "index: {0}, section: {1}", + COFFRel->SymbolTableIndex, FixupSect.getIndex()), + inconvertibleErrorCode()); + } + + object::COFFSymbolRef COFFSymbol = getObject().getCOFFSymbol(*SymbolIt); + COFFSymbolIndex SymIndex = getObject().getSymbolIndex(COFFSymbol); + + Symbol *GraphSymbol = getGraphSymbol(SymIndex); + if (!GraphSymbol) + return make_error<StringError>( + formatv("Could not find symbol at given index, did you add it to " + "JITSymbolTable? index: {0}, section: {1}", + SymIndex, FixupSect.getIndex()), + inconvertibleErrorCode()); + + Expected<COFFX86RelocationKind> RelocKind = + getRelocationKind(Rel.getType()); + if (!RelocKind) + return RelocKind.takeError(); + + int64_t Addend = 0; + orc::ExecutorAddr FixupAddress = + orc::ExecutorAddr(FixupSect.getAddress()) + Rel.getOffset(); + Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); + + Edge::Kind Kind = Edge::Invalid; + + switch (*RelocKind) { + case COFFAddr32NB: { + Kind = x86_64::Pointer32; + Offset -= getImageBase(); + break; + } + case COFFRel32: { + Kind = x86_64::BranchPCRel32; + break; + } + }; + + Edge GE(Kind, Offset, *GraphSymbol, Addend); + LLVM_DEBUG({ + dbgs() << " "; + printEdge(dbgs(), BlockToFix, GE, x86_64::getEdgeKindName(Kind)); + dbgs() << "\n"; + }); + + BlockToFix.addEdge(std::move(GE)); + return Error::success(); + } + + /// Return the string name of the given COFF x86_64 edge kind. + const char *getCOFFX86RelocationKindName(COFFX86RelocationKind R) { + switch (R) { + case COFFAddr32NB: + return "COFFAddr32NB"; + case COFFRel32: + return "COFFRel32"; + } + } + +public: + COFFLinkGraphBuilder_x86_64(const object::COFFObjectFile &Obj, const Triple T) + : COFFLinkGraphBuilder(Obj, std::move(T), x86_64::getEdgeKindName) {} +}; + +Error buildTables_COFF_x86_64(LinkGraph &G) { + LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); + + x86_64::GOTTableManager GOT; + x86_64::PLTTableManager PLT(GOT); + visitExistingEdges(G, GOT, PLT); + return Error::success(); +} +} // namespace + +namespace llvm { +namespace jitlink { + +Expected<std::unique_ptr<LinkGraph>> +createLinkGraphFromCOFFObject_x86_64(MemoryBufferRef ObjectBuffer) { + LLVM_DEBUG({ + dbgs() << "Building jitlink graph for new input " + << ObjectBuffer.getBufferIdentifier() << "...\n"; + }); + + auto COFFObj = object::ObjectFile::createCOFFObjectFile(ObjectBuffer); + if (!COFFObj) + return COFFObj.takeError(); + + return COFFLinkGraphBuilder_x86_64(**COFFObj, (*COFFObj)->makeTriple()) + .buildGraph(); +} + +void link_COFF_x86_64(std::unique_ptr<LinkGraph> G, + std::unique_ptr<JITLinkContext> Ctx) { + PassConfiguration Config; + const Triple &TT = G->getTargetTriple(); + if (Ctx->shouldAddDefaultTargetPasses(TT)) { + // 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/TLSInfoEntry build pass. + Config.PostPrunePasses.push_back(buildTables_COFF_x86_64); + + // Add GOT/Stubs optimizer pass. + Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses); + } + + if (auto Err = Ctx->modifyPassConfig(*G, Config)) + return Ctx->notifyFailed(std::move(Err)); + + COFFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); +} + +} // namespace jitlink +} // namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp index b1492cd74508..389fd14c0f29 100644 --- a/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/EHFrameSupport.cpp @@ -33,7 +33,7 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) { if (!EHFrame) { LLVM_DEBUG({ dbgs() << "EHFrameEdgeFixer: No " << EHFrameSectionName - << " section. Nothing to do\n"; + << " section in \"" << G.getName() << "\". Nothing to do.\n"; }); return Error::success(); } @@ -44,7 +44,8 @@ Error EHFrameEdgeFixer::operator()(LinkGraph &G) { "EHFrameEdgeFixer only supports 32 and 64 bit targets"); LLVM_DEBUG({ - dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << "...\n"; + dbgs() << "EHFrameEdgeFixer: Processing " << EHFrameSectionName << " in \"" + << G.getName() << "\"...\n"; }); ParseContext PC(G); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp index 98da3f155c3e..7d67e5ef343a 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_aarch64.cpp @@ -63,6 +63,10 @@ private: ELFPrel64, ELFAdrGOTPage21, ELFLd64GOTLo12, + ELFTLSDescAdrPage21, + ELFTLSDescAddLo12, + ELFTLSDescLd64Lo12, + ELFTLSDescCall, }; static Expected<ELFAArch64RelocationKind> @@ -104,6 +108,14 @@ private: return ELFAdrGOTPage21; case ELF::R_AARCH64_LD64_GOT_LO12_NC: return ELFLd64GOTLo12; + case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: + return ELFTLSDescAdrPage21; + case ELF::R_AARCH64_TLSDESC_ADD_LO12: + return ELFTLSDescAddLo12; + case ELF::R_AARCH64_TLSDESC_LD64_LO12: + return ELFTLSDescLd64Lo12; + case ELF::R_AARCH64_TLSDESC_CALL: + return ELFTLSDescCall; } return make_error<JITLinkError>( @@ -292,6 +304,21 @@ private: Kind = aarch64::GOTPageOffset12; break; } + case ELFTLSDescAdrPage21: { + Kind = aarch64::TLSDescPage21; + break; + } + case ELFTLSDescAddLo12: { + Kind = aarch64::TLSDescPageOffset12; + break; + } + case ELFTLSDescLd64Lo12: { + Kind = aarch64::TLSDescPageOffset12; + break; + } + case ELFTLSDescCall: { + return Error::success(); + } }; Edge GE(Kind, Offset, *GraphSymbol, Addend); @@ -302,6 +329,7 @@ private: }); BlockToFix.addEdge(std::move(GE)); + return Error::success(); } @@ -342,6 +370,14 @@ private: return "ELFAdrGOTPage21"; case ELFLd64GOTLo12: return "ELFLd64GOTLo12"; + case ELFTLSDescAdrPage21: + return "ELFTLSDescAdrPage21"; + case ELFTLSDescAddLo12: + return "ELFTLSDescAddLo12"; + case ELFTLSDescLd64Lo12: + return "ELFTLSDescLd64Lo12"; + case ELFTLSDescCall: + return "ELFTLSDescCall"; default: return getGenericEdgeKindName(static_cast<Edge::Kind>(R)); } @@ -354,12 +390,133 @@ public: aarch64::getEdgeKindName) {} }; +// TLS Info Builder. +class TLSInfoTableManager_ELF_aarch64 + : public TableManager<TLSInfoTableManager_ELF_aarch64> { +public: + static StringRef getSectionName() { return "$__TLSINFO"; } + + static const uint8_t TLSInfoEntryContent[16]; + + bool visitEdge(LinkGraph &G, Block *B, Edge &E) { return false; } + + Symbol &createEntry(LinkGraph &G, Symbol &Target) { + // the TLS Info entry's key value will be written by the fixTLVSectionByName + // pass, so create mutable content. + auto &TLSInfoEntry = G.createMutableContentBlock( + getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()), + orc::ExecutorAddr(), 8, 0); + TLSInfoEntry.addEdge(aarch64::Pointer64, 8, Target, 0); + return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false); + } + +private: + Section &getTLSInfoSection(LinkGraph &G) { + if (!TLSInfoTable) + TLSInfoTable = &G.createSection(getSectionName(), MemProt::Read); + return *TLSInfoTable; + } + + ArrayRef<char> getTLSInfoEntryContent() const { + return {reinterpret_cast<const char *>(TLSInfoEntryContent), + sizeof(TLSInfoEntryContent)}; + } + + Section *TLSInfoTable = nullptr; +}; + +const uint8_t TLSInfoTableManager_ELF_aarch64::TLSInfoEntryContent[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/ +}; + +// TLS Descriptor Builder. +class TLSDescTableManager_ELF_aarch64 + : public TableManager<TLSDescTableManager_ELF_aarch64> { +public: + TLSDescTableManager_ELF_aarch64( + TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager) + : TLSInfoTableManager(TLSInfoTableManager) {} + + static StringRef getSectionName() { return "$__TLSDESC"; } + + static const uint8_t TLSDescEntryContent[16]; + + bool visitEdge(LinkGraph &G, Block *B, Edge &E) { + Edge::Kind KindToSet = Edge::Invalid; + switch (E.getKind()) { + case aarch64::TLSDescPage21: { + KindToSet = aarch64::Page21; + break; + } + case aarch64::TLSDescPageOffset12: { + KindToSet = aarch64::PageOffset12; + break; + } + default: + return false; + } + assert(KindToSet != Edge::Invalid && + "Fell through switch, but no new kind to set"); + DEBUG_WITH_TYPE("jitlink", { + dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " + << B->getFixupAddress(E) << " (" << B->getAddress() << " + " + << formatv("{0:x}", E.getOffset()) << ")\n"; + }); + E.setKind(KindToSet); + E.setTarget(getEntryForTarget(G, E.getTarget())); + return true; + } + + Symbol &createEntry(LinkGraph &G, Symbol &Target) { + auto &EntryBlock = + G.createContentBlock(getTLSDescSection(G), getTLSDescBlockContent(), + orc::ExecutorAddr(), 8, 0); + EntryBlock.addEdge(aarch64::Pointer64, 0, getTLSDescResolver(G), 0); + EntryBlock.addEdge(aarch64::Pointer64, 8, + TLSInfoTableManager.getEntryForTarget(G, Target), 0); + return G.addAnonymousSymbol(EntryBlock, 0, 8, false, false); + } + +private: + Section &getTLSDescSection(LinkGraph &G) { + if (!GOTSection) + GOTSection = &G.createSection(getSectionName(), MemProt::Read); + return *GOTSection; + } + + Symbol &getTLSDescResolver(LinkGraph &G) { + if (!TLSDescResolver) + TLSDescResolver = + &G.addExternalSymbol("__tlsdesc_resolver", 8, Linkage::Strong); + return *TLSDescResolver; + } + + ArrayRef<char> getTLSDescBlockContent() { + return {reinterpret_cast<const char *>(TLSDescEntryContent), + sizeof(TLSDescEntryContent)}; + } + + Section *GOTSection = nullptr; + Symbol *TLSDescResolver = nullptr; + TLSInfoTableManager_ELF_aarch64 &TLSInfoTableManager; +}; + +const uint8_t TLSDescTableManager_ELF_aarch64::TLSDescEntryContent[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /*resolver function pointer*/ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 /*pointer to tls info*/ +}; + 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); + TLSInfoTableManager_ELF_aarch64 TLSInfo; + TLSDescTableManager_ELF_aarch64 TLSDesc(TLSInfo); + visitExistingEdges(G, GOT, PLT, TLSDesc, TLSInfo); return Error::success(); } @@ -406,7 +563,7 @@ void link_ELF_aarch64(std::unique_ptr<LinkGraph> G, else Config.PrePrunePasses.push_back(markAllSymbolsLive); - // Add an in-place GOT/Stubs build pass. + // Add an in-place GOT/TLS/Stubs build pass. Config.PostPrunePasses.push_back(buildTables_ELF_aarch64); } diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp index 197ab71f5274..c7596efe2bb8 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp @@ -494,6 +494,30 @@ private: Block &BlockToFix) { using Base = ELFLinkGraphBuilder<ELFT>; + uint32_t Type = Rel.getType(false); + // We do not implement linker relaxation, except what is required for + // alignment (see below). + if (Type == llvm::ELF::R_RISCV_RELAX) + return Error::success(); + + int64_t Addend = Rel.r_addend; + if (Type == llvm::ELF::R_RISCV_ALIGN) { + uint64_t Alignment = PowerOf2Ceil(Addend); + // FIXME: Implement support for ensuring alignment together with linker + // relaxation; 2 bytes are guaranteed by the length of compressed + // instructions, so this does not need any action from our side. + if (Alignment > 2) + return make_error<JITLinkError>( + formatv("Unsupported relocation R_RISCV_ALIGN with alignment {0} " + "larger than 2 (addend: {1})", + Alignment, Addend)); + return Error::success(); + } + + Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type); + if (!Kind) + return Kind.takeError(); + uint32_t SymbolIndex = Rel.getSymbol(false); auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); if (!ObjSymbol) @@ -508,12 +532,6 @@ private: Base::GraphSymbols.size()), inconvertibleErrorCode()); - uint32_t Type = Rel.getType(false); - Expected<riscv::EdgeKind_riscv> Kind = getRelocationKind(Type); - if (!Kind) - return Kind.takeError(); - - int64_t Addend = Rel.r_addend; auto FixupAddress = orc::ExecutorAddr(FixupSect.sh_addr) + Rel.r_offset; Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); Edge GE(*Kind, Offset, *GraphSymbol, Addend); diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 43efe0725cfe..08fdc7c9e6b1 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -9,10 +9,10 @@ #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/BinaryFormat/Magic.h" +#include "llvm/ExecutionEngine/JITLink/COFF.h" #include "llvm/ExecutionEngine/JITLink/ELF.h" #include "llvm/ExecutionEngine/JITLink/MachO.h" #include "llvm/Support/Format.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -41,8 +41,6 @@ public: } }; -static ManagedStatic<JITLinkerErrorCategory> JITLinkerErrorCategory; - } // namespace namespace llvm { @@ -53,7 +51,8 @@ char JITLinkError::ID = 0; void JITLinkError::log(raw_ostream &OS) const { OS << ErrMsg; } std::error_code JITLinkError::convertToErrorCode() const { - return std::error_code(GenericJITLinkError, *JITLinkerErrorCategory); + static JITLinkerErrorCategory TheJITLinkerErrorCategory; + return std::error_code(GenericJITLinkError, TheJITLinkerErrorCategory); } const char *getGenericEdgeKindName(Edge::Kind K) { @@ -410,6 +409,8 @@ createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) { return createLinkGraphFromMachOObject(ObjectBuffer); case file_magic::elf_relocatable: return createLinkGraphFromELFObject(ObjectBuffer); + case file_magic::coff_object: + return createLinkGraphFromCOFFObject(ObjectBuffer); default: return make_error<JITLinkError>("Unsupported file format"); }; @@ -421,6 +422,8 @@ void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) { return link_MachO(std::move(G), std::move(Ctx)); case Triple::ELF: return link_ELF(std::move(G), std::move(Ctx)); + case Triple::COFF: + return link_COFF(std::move(G), std::move(Ctx)); default: Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format")); }; diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp index dd50314d3ed7..04194318498f 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -425,7 +425,7 @@ private: else return TargetSymbolOrErr.takeError(); - Kind = aarch64::PointerToGOT; + Kind = aarch64::Delta32ToGOT; break; case MachODelta32: case MachODelta64: { diff --git a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp index 28a6f9ce90d9..9ecc71dfbb54 100644 --- a/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/aarch64.cpp @@ -48,8 +48,12 @@ const char *getEdgeKindName(Edge::Kind R) { return "TLVPage21"; case TLVPageOffset12: return "TLVPageOffset12"; - case PointerToGOT: - return "PointerToGOT"; + case TLSDescPage21: + return "TLSDescPage21"; + case TLSDescPageOffset12: + return "TLSDescPageOffset12"; + case Delta32ToGOT: + return "Delta32ToGOT"; case PairedAddend: return "PairedAddend"; case LDRLiteral19: diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index e476c549412a..e7ca636c83e9 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -839,11 +839,13 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::registerInitSections( Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges( jitlink::LinkGraph &G, JITDylib &JD) { - // TODO implement TLV support - for (auto *Sym : G.external_symbols()) + for (auto *Sym : G.external_symbols()) { if (Sym->getName() == "__tls_get_addr") { Sym->setName("___orc_rt_elfnix_tls_get_addr"); + } else if (Sym->getName() == "__tlsdesc_resolver") { + Sym->setName("___orc_rt_elfnix_tlsdesc_resolver"); } + } auto *TLSInfoEntrySection = G.findSectionByName("$__TLSINFO"); diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 6d67e6d87b56..1926ef1ecc72 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -666,8 +666,9 @@ Error LLJITBuilderState::prepareForConstruction() { // JIT linker. if (!CreateObjectLinkingLayer) { auto &TT = JTMB->getTargetTriple(); - if (TT.isOSBinFormatMachO() && - (TT.getArch() == Triple::aarch64 || TT.getArch() == Triple::x86_64)) { + if (TT.getArch() == Triple::riscv64 || + (TT.isOSBinFormatMachO() && + (TT.getArch() == Triple::aarch64 || TT.getArch() == Triple::x86_64))) { JTMB->setRelocationModel(Reloc::PIC_); JTMB->setCodeModel(CodeModel::Small); diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp index 394a555e453b..356b81b4f1c5 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectFileInterface.cpp @@ -9,6 +9,7 @@ #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" #include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h" #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" +#include "llvm/Object/COFF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" @@ -145,6 +146,55 @@ getELFObjectFileSymbolInfo(ExecutionSession &ES, return I; } +static Expected<MaterializationUnit::Interface> +getCOFFObjectFileSymbolInfo(ExecutionSession &ES, + const object::COFFObjectFile &Obj) { + MaterializationUnit::Interface I; + + for (auto &Sym : Obj.symbols()) { + Expected<uint32_t> SymFlagsOrErr = Sym.getFlags(); + if (!SymFlagsOrErr) + // TODO: Test this error. + return SymFlagsOrErr.takeError(); + + // Skip symbols not defined in this object file. + if (*SymFlagsOrErr & object::BasicSymbolRef::SF_Undefined) + continue; + + // Skip symbols that are not global. + if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) + continue; + + // Skip symbols that have type SF_File. + if (auto SymType = Sym.getType()) { + if (*SymType == object::SymbolRef::ST_File) + continue; + } else + return SymType.takeError(); + + auto Name = Sym.getName(); + if (!Name) + return Name.takeError(); + + auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym); + if (!SymFlags) + return SymFlags.takeError(); + *SymFlags |= JITSymbolFlags::Exported; + auto COFFSym = Obj.getCOFFSymbol(Sym); + + // Weak external is always a function + if (COFFSym.isWeakExternal()) { + *SymFlags |= JITSymbolFlags::Callable; + } + + I.SymbolFlags[ES.intern(*Name)] = std::move(*SymFlags); + } + + // FIXME: handle init symbols + + return I; +} + Expected<MaterializationUnit::Interface> getGenericObjectFileSymbolInfo(ExecutionSession &ES, const object::ObjectFile &Obj) { @@ -196,6 +246,8 @@ getObjectFileInterface(ExecutionSession &ES, MemoryBufferRef ObjBuffer) { return getMachOObjectFileSymbolInfo(ES, *MachOObj); else if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(Obj->get())) return getELFObjectFileSymbolInfo(ES, *ELFObj); + else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj->get())) + return getCOFFObjectFileSymbolInfo(ES, *COFFObj); return getGenericObjectFileSymbolInfo(ES, **Obj); } diff --git a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp index ef764a3f0d7f..da8aaad08cad 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp @@ -665,7 +665,7 @@ void OrcMips32_Base::writeIndirectStubsBlock( // // i.. - assert(stubAndPointerRangesOk<OrcAArch64>( + assert(stubAndPointerRangesOk<OrcMips32_Base>( StubsBlockTargetAddress, PointersBlockTargetAddress, NumStubs) && "PointersBlock is out of range"); @@ -884,7 +884,7 @@ void OrcMips64::writeIndirectStubsBlock( // // ... - assert(stubAndPointerRangesOk<OrcAArch64>( + assert(stubAndPointerRangesOk<OrcMips64>( StubsBlockTargetAddress, PointersBlockTargetAddress, NumStubs) && "PointersBlock is out of range"); diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp index fdad90cbcfb7..2cc2bddeb21a 100644 --- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcError.cpp @@ -12,7 +12,6 @@ #include "llvm/ExecutionEngine/Orc/Shared/OrcError.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" #include <type_traits> @@ -70,7 +69,10 @@ public: } }; -static ManagedStatic<OrcErrorCategory> OrcErrCat; +OrcErrorCategory &getOrcErrCat() { + static OrcErrorCategory OrcErrCat; + return OrcErrCat; +} } // namespace namespace llvm { @@ -81,7 +83,7 @@ char JITSymbolNotFound::ID = 0; std::error_code orcError(OrcErrorCode ErrCode) { typedef std::underlying_type<OrcErrorCode>::type UT; - return std::error_code(static_cast<UT>(ErrCode), *OrcErrCat); + return std::error_code(static_cast<UT>(ErrCode), getOrcErrCat()); } DuplicateDefinition::DuplicateDefinition(std::string SymbolName) @@ -105,7 +107,7 @@ JITSymbolNotFound::JITSymbolNotFound(std::string SymbolName) std::error_code JITSymbolNotFound::convertToErrorCode() const { typedef std::underlying_type<OrcErrorCode>::type UT; return std::error_code(static_cast<UT>(OrcErrorCode::JITSymbolNotFound), - *OrcErrCat); + getOrcErrCat()); } void JITSymbolNotFound::log(raw_ostream &OS) const { diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp index ffa2969536e7..8296b03398a0 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp @@ -11,7 +11,6 @@ #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/ManagedStatic.h" #include <cstdint> #include <mutex> @@ -67,9 +66,6 @@ LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { using namespace llvm; using namespace llvm::orc; -// Serialize rendezvous with the debugger as well as access to shared data. -ManagedStatic<std::mutex> JITDebugLock; - // Register debug object, return error message or null for success. static void registerJITLoaderGDBImpl(const char *ObjAddr, size_t Size) { LLVM_DEBUG({ @@ -85,7 +81,9 @@ static void registerJITLoaderGDBImpl(const char *ObjAddr, size_t Size) { E->symfile_size = Size; E->prev_entry = nullptr; - std::lock_guard<std::mutex> Lock(*JITDebugLock); + // Serialize rendezvous with the debugger as well as access to shared data. + static std::mutex JITDebugLock; + std::lock_guard<std::mutex> Lock(JITDebugLock); // Insert this entry at the head of the list. jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry; diff --git a/llvm/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp b/llvm/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp index 4a236e183c8b..bb41bac32534 100644 --- a/llvm/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp +++ b/llvm/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp @@ -24,7 +24,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Path.h" @@ -488,15 +487,14 @@ void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr, } } -// There should be only a single event listener per process, otherwise perf gets -// confused. -llvm::ManagedStatic<PerfJITEventListener> PerfListener; - } // end anonymous namespace namespace llvm { JITEventListener *JITEventListener::createPerfJITEventListener() { - return &*PerfListener; + // There should be only a single event listener per process, otherwise perf + // gets confused. + static PerfJITEventListener PerfListener; + return &PerfListener; } } // namespace llvm diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 2e0cba849165..54ab00732330 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -19,7 +19,6 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/MSVCErrorWorkarounds.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include <mutex> @@ -51,8 +50,6 @@ public: } }; -static ManagedStatic<RuntimeDyldErrorCategory> RTDyldErrorCategory; - } char RuntimeDyldError::ID = 0; @@ -62,7 +59,8 @@ void RuntimeDyldError::log(raw_ostream &OS) const { } std::error_code RuntimeDyldError::convertToErrorCode() const { - return std::error_code(GenericRTDyldError, *RTDyldErrorCategory); + static RuntimeDyldErrorCategory RTDyldErrorCategory; + return std::error_code(GenericRTDyldError, RTDyldErrorCategory); } // Empty out-of-line virtual destructor as the key function. diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index da1102fc9f07..c702584b7a33 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -479,7 +479,7 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, *TargetPtr &= 0xfff8001fU; // Immediate:15:2 goes in bits 18:5 of TBZ, TBNZ - or32le(TargetPtr, (BranchImm & 0x0FFFFFFC) << 3); + or32le(TargetPtr, (BranchImm & 0x0000FFFC) << 3); break; } case ELF::R_AARCH64_CALL26: // fallthrough |