Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
35271 views
//===------- ELFLinkGraphBuilder.h - ELF LinkGraph builder ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Generic ELF LinkGraph building code.9//10//===----------------------------------------------------------------------===//1112#ifndef LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H13#define LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H1415#include "llvm/ExecutionEngine/JITLink/JITLink.h"16#include "llvm/Object/ELF.h"17#include "llvm/Support/Debug.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/FormatVariadic.h"2021#define DEBUG_TYPE "jitlink"2223namespace llvm {24namespace jitlink {2526/// Common link-graph building code shared between all ELFFiles.27class ELFLinkGraphBuilderBase {28public:29ELFLinkGraphBuilderBase(std::unique_ptr<LinkGraph> G) : G(std::move(G)) {}30virtual ~ELFLinkGraphBuilderBase();3132protected:33static bool isDwarfSection(StringRef SectionName) {34return llvm::is_contained(DwarfSectionNames, SectionName);35}3637Section &getCommonSection() {38if (!CommonSection)39CommonSection = &G->createSection(40CommonSectionName, orc::MemProt::Read | orc::MemProt::Write);41return *CommonSection;42}4344std::unique_ptr<LinkGraph> G;4546private:47static StringRef CommonSectionName;48static ArrayRef<const char *> DwarfSectionNames;4950Section *CommonSection = nullptr;51};5253/// LinkGraph building code that's specific to the given ELFT, but common54/// across all architectures.55template <typename ELFT>56class ELFLinkGraphBuilder : public ELFLinkGraphBuilderBase {57using ELFFile = object::ELFFile<ELFT>;5859public:60ELFLinkGraphBuilder(const object::ELFFile<ELFT> &Obj, Triple TT,61SubtargetFeatures Features, StringRef FileName,62LinkGraph::GetEdgeKindNameFunction GetEdgeKindName);6364/// Debug sections are included in the graph by default. Use65/// setProcessDebugSections(false) to ignore them if debug info is not66/// needed.67ELFLinkGraphBuilder &setProcessDebugSections(bool ProcessDebugSections) {68this->ProcessDebugSections = ProcessDebugSections;69return *this;70}7172/// Attempt to construct and return the LinkGraph.73Expected<std::unique_ptr<LinkGraph>> buildGraph();7475/// Call to derived class to handle relocations. These require76/// architecture specific knowledge to map to JITLink edge kinds.77virtual Error addRelocations() = 0;7879protected:80using ELFSectionIndex = unsigned;81using ELFSymbolIndex = unsigned;8283bool isRelocatable() const {84return Obj.getHeader().e_type == llvm::ELF::ET_REL;85}8687void setGraphBlock(ELFSectionIndex SecIndex, Block *B) {88assert(!GraphBlocks.count(SecIndex) && "Duplicate section at index");89GraphBlocks[SecIndex] = B;90}9192Block *getGraphBlock(ELFSectionIndex SecIndex) {93return GraphBlocks.lookup(SecIndex);94}9596void setGraphSymbol(ELFSymbolIndex SymIndex, Symbol &Sym) {97assert(!GraphSymbols.count(SymIndex) && "Duplicate symbol at index");98GraphSymbols[SymIndex] = &Sym;99}100101Symbol *getGraphSymbol(ELFSymbolIndex SymIndex) {102return GraphSymbols.lookup(SymIndex);103}104105Expected<std::pair<Linkage, Scope>>106getSymbolLinkageAndScope(const typename ELFT::Sym &Sym, StringRef Name);107108/// Set the target flags on the given Symbol.109virtual TargetFlagsType makeTargetFlags(const typename ELFT::Sym &Sym) {110return TargetFlagsType{};111}112113/// Get the physical offset of the symbol on the target platform.114virtual orc::ExecutorAddrDiff getRawOffset(const typename ELFT::Sym &Sym,115TargetFlagsType Flags) {116return Sym.getValue();117}118119Error prepare();120Error graphifySections();121Error graphifySymbols();122123/// Override in derived classes to suppress certain sections in the link124/// graph.125virtual bool excludeSection(const typename ELFT::Shdr &Sect) const {126return false;127}128129/// Traverse all matching ELFT::Rela relocation records in the given section.130/// The handler function Func should be callable with this signature:131/// Error(const typename ELFT::Rela &,132/// const typename ELFT::Shdr &, Section &)133///134template <typename RelocHandlerMethod>135Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,136RelocHandlerMethod &&Func);137138/// Traverse all matching ELFT::Rel relocation records in the given section.139/// The handler function Func should be callable with this signature:140/// Error(const typename ELFT::Rel &,141/// const typename ELFT::Shdr &, Section &)142///143template <typename RelocHandlerMethod>144Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,145RelocHandlerMethod &&Func);146147/// Traverse all matching rela relocation records in the given section.148/// Convenience wrapper to allow passing a member function for the handler.149///150template <typename ClassT, typename RelocHandlerMethod>151Error forEachRelaRelocation(const typename ELFT::Shdr &RelSect,152ClassT *Instance, RelocHandlerMethod &&Method) {153return forEachRelaRelocation(154RelSect,155[Instance, Method](const auto &Rel, const auto &Target, auto &GS) {156return (Instance->*Method)(Rel, Target, GS);157});158}159160/// Traverse all matching rel relocation records in the given section.161/// Convenience wrapper to allow passing a member function for the handler.162///163template <typename ClassT, typename RelocHandlerMethod>164Error forEachRelRelocation(const typename ELFT::Shdr &RelSect,165ClassT *Instance, RelocHandlerMethod &&Method) {166return forEachRelRelocation(167RelSect,168[Instance, Method](const auto &Rel, const auto &Target, auto &GS) {169return (Instance->*Method)(Rel, Target, GS);170});171}172173const ELFFile &Obj;174175typename ELFFile::Elf_Shdr_Range Sections;176const typename ELFFile::Elf_Shdr *SymTabSec = nullptr;177StringRef SectionStringTab;178bool ProcessDebugSections = true;179180// Maps ELF section indexes to LinkGraph Blocks.181// Only SHF_ALLOC sections will have graph blocks.182DenseMap<ELFSectionIndex, Block *> GraphBlocks;183DenseMap<ELFSymbolIndex, Symbol *> GraphSymbols;184DenseMap<const typename ELFFile::Elf_Shdr *,185ArrayRef<typename ELFFile::Elf_Word>>186ShndxTables;187};188189template <typename ELFT>190ELFLinkGraphBuilder<ELFT>::ELFLinkGraphBuilder(191const ELFFile &Obj, Triple TT, SubtargetFeatures Features,192StringRef FileName, LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)193: ELFLinkGraphBuilderBase(std::make_unique<LinkGraph>(194FileName.str(), Triple(std::move(TT)), std::move(Features),195ELFT::Is64Bits ? 8 : 4, llvm::endianness(ELFT::Endianness),196std::move(GetEdgeKindName))),197Obj(Obj) {198LLVM_DEBUG(199{ dbgs() << "Created ELFLinkGraphBuilder for \"" << FileName << "\""; });200}201202template <typename ELFT>203Expected<std::unique_ptr<LinkGraph>> ELFLinkGraphBuilder<ELFT>::buildGraph() {204if (!isRelocatable())205return make_error<JITLinkError>("Object is not a relocatable ELF file");206207if (auto Err = prepare())208return std::move(Err);209210if (auto Err = graphifySections())211return std::move(Err);212213if (auto Err = graphifySymbols())214return std::move(Err);215216if (auto Err = addRelocations())217return std::move(Err);218219return std::move(G);220}221222template <typename ELFT>223Expected<std::pair<Linkage, Scope>>224ELFLinkGraphBuilder<ELFT>::getSymbolLinkageAndScope(225const typename ELFT::Sym &Sym, StringRef Name) {226Linkage L = Linkage::Strong;227Scope S = Scope::Default;228229switch (Sym.getBinding()) {230case ELF::STB_LOCAL:231S = Scope::Local;232break;233case ELF::STB_GLOBAL:234// Nothing to do here.235break;236case ELF::STB_WEAK:237case ELF::STB_GNU_UNIQUE:238L = Linkage::Weak;239break;240default:241return make_error<StringError>(242"Unrecognized symbol binding " +243Twine(static_cast<int>(Sym.getBinding())) + " for " + Name,244inconvertibleErrorCode());245}246247switch (Sym.getVisibility()) {248case ELF::STV_DEFAULT:249case ELF::STV_PROTECTED:250// FIXME: Make STV_DEFAULT symbols pre-emptible? This probably needs251// Orc support.252// Otherwise nothing to do here.253break;254case ELF::STV_HIDDEN:255// Default scope -> Hidden scope. No effect on local scope.256if (S == Scope::Default)257S = Scope::Hidden;258break;259case ELF::STV_INTERNAL:260return make_error<StringError>(261"Unrecognized symbol visibility " +262Twine(static_cast<int>(Sym.getVisibility())) + " for " + Name,263inconvertibleErrorCode());264}265266return std::make_pair(L, S);267}268269template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::prepare() {270LLVM_DEBUG(dbgs() << " Preparing to build...\n");271272// Get the sections array.273if (auto SectionsOrErr = Obj.sections())274Sections = *SectionsOrErr;275else276return SectionsOrErr.takeError();277278// Get the section string table.279if (auto SectionStringTabOrErr = Obj.getSectionStringTable(Sections))280SectionStringTab = *SectionStringTabOrErr;281else282return SectionStringTabOrErr.takeError();283284// Get the SHT_SYMTAB section.285for (auto &Sec : Sections) {286if (Sec.sh_type == ELF::SHT_SYMTAB) {287if (!SymTabSec)288SymTabSec = &Sec;289else290return make_error<JITLinkError>("Multiple SHT_SYMTAB sections in " +291G->getName());292}293294// Extended table.295if (Sec.sh_type == ELF::SHT_SYMTAB_SHNDX) {296uint32_t SymtabNdx = Sec.sh_link;297if (SymtabNdx >= Sections.size())298return make_error<JITLinkError>("sh_link is out of bound");299300auto ShndxTable = Obj.getSHNDXTable(Sec);301if (!ShndxTable)302return ShndxTable.takeError();303304ShndxTables.insert({&Sections[SymtabNdx], *ShndxTable});305}306}307308return Error::success();309}310311template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySections() {312LLVM_DEBUG(dbgs() << " Creating graph sections...\n");313314// For each section...315for (ELFSectionIndex SecIndex = 0; SecIndex != Sections.size(); ++SecIndex) {316317auto &Sec = Sections[SecIndex];318319// Start by getting the section name.320auto Name = Obj.getSectionName(Sec, SectionStringTab);321if (!Name)322return Name.takeError();323if (excludeSection(Sec)) {324LLVM_DEBUG({325dbgs() << " " << SecIndex << ": Skipping section \"" << *Name326<< "\" explicitly\n";327});328continue;329}330331// Skip null sections.332if (Sec.sh_type == ELF::SHT_NULL) {333LLVM_DEBUG({334dbgs() << " " << SecIndex << ": has type SHT_NULL. Skipping.\n";335});336continue;337}338339// If the name indicates that it's a debug section then skip it: We don't340// support those yet.341if (!ProcessDebugSections && isDwarfSection(*Name)) {342LLVM_DEBUG({343dbgs() << " " << SecIndex << ": \"" << *Name344<< "\" is a debug section: "345"No graph section will be created.\n";346});347continue;348}349350LLVM_DEBUG({351dbgs() << " " << SecIndex << ": Creating section for \"" << *Name352<< "\"\n";353});354355// Get the section's memory protection flags.356orc::MemProt Prot = orc::MemProt::Read;357if (Sec.sh_flags & ELF::SHF_EXECINSTR)358Prot |= orc::MemProt::Exec;359if (Sec.sh_flags & ELF::SHF_WRITE)360Prot |= orc::MemProt::Write;361362// Look for existing sections first.363auto *GraphSec = G->findSectionByName(*Name);364if (!GraphSec) {365GraphSec = &G->createSection(*Name, Prot);366// Non-SHF_ALLOC sections get NoAlloc memory lifetimes.367if (!(Sec.sh_flags & ELF::SHF_ALLOC)) {368GraphSec->setMemLifetime(orc::MemLifetime::NoAlloc);369LLVM_DEBUG({370dbgs() << " " << SecIndex << ": \"" << *Name371<< "\" is not a SHF_ALLOC section. Using NoAlloc lifetime.\n";372});373}374}375376if (GraphSec->getMemProt() != Prot) {377std::string ErrMsg;378raw_string_ostream(ErrMsg)379<< "In " << G->getName() << ", section " << *Name380<< " is present more than once with different permissions: "381<< GraphSec->getMemProt() << " vs " << Prot;382return make_error<JITLinkError>(std::move(ErrMsg));383}384385Block *B = nullptr;386if (Sec.sh_type != ELF::SHT_NOBITS) {387auto Data = Obj.template getSectionContentsAsArray<char>(Sec);388if (!Data)389return Data.takeError();390391B = &G->createContentBlock(*GraphSec, *Data,392orc::ExecutorAddr(Sec.sh_addr),393Sec.sh_addralign, 0);394} else395B = &G->createZeroFillBlock(*GraphSec, Sec.sh_size,396orc::ExecutorAddr(Sec.sh_addr),397Sec.sh_addralign, 0);398399if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {400// Add live symbol to avoid dead-stripping for .ARM.exidx sections401G->addAnonymousSymbol(*B, orc::ExecutorAddrDiff(),402orc::ExecutorAddrDiff(), false, true);403}404405setGraphBlock(SecIndex, B);406}407408return Error::success();409}410411template <typename ELFT> Error ELFLinkGraphBuilder<ELFT>::graphifySymbols() {412LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");413414// No SYMTAB -- Bail out early.415if (!SymTabSec)416return Error::success();417418// Get the section content as a Symbols array.419auto Symbols = Obj.symbols(SymTabSec);420if (!Symbols)421return Symbols.takeError();422423// Get the string table for this section.424auto StringTab = Obj.getStringTableForSymtab(*SymTabSec, Sections);425if (!StringTab)426return StringTab.takeError();427428LLVM_DEBUG({429StringRef SymTabName;430431if (auto SymTabNameOrErr = Obj.getSectionName(*SymTabSec, SectionStringTab))432SymTabName = *SymTabNameOrErr;433else {434dbgs() << "Could not get ELF SHT_SYMTAB section name for logging: "435<< toString(SymTabNameOrErr.takeError()) << "\n";436SymTabName = "<SHT_SYMTAB section with invalid name>";437}438439dbgs() << " Adding symbols from symtab section \"" << SymTabName440<< "\"\n";441});442443for (ELFSymbolIndex SymIndex = 0; SymIndex != Symbols->size(); ++SymIndex) {444auto &Sym = (*Symbols)[SymIndex];445446// Check symbol type.447switch (Sym.getType()) {448case ELF::STT_FILE:449LLVM_DEBUG({450if (auto Name = Sym.getName(*StringTab))451dbgs() << " " << SymIndex << ": Skipping STT_FILE symbol \""452<< *Name << "\"\n";453else {454dbgs() << "Could not get STT_FILE symbol name: "455<< toString(Name.takeError()) << "\n";456dbgs() << " " << SymIndex457<< ": Skipping STT_FILE symbol with invalid name\n";458}459});460continue;461break;462}463464// Get the symbol name.465auto Name = Sym.getName(*StringTab);466if (!Name)467return Name.takeError();468469// Handle common symbols specially.470if (Sym.isCommon()) {471Symbol &GSym = G->addDefinedSymbol(472G->createZeroFillBlock(getCommonSection(), Sym.st_size,473orc::ExecutorAddr(), Sym.getValue(), 0),4740, *Name, Sym.st_size, Linkage::Strong, Scope::Default, false, false);475setGraphSymbol(SymIndex, GSym);476continue;477}478479if (Sym.isDefined() &&480(Sym.getType() == ELF::STT_NOTYPE || Sym.getType() == ELF::STT_FUNC ||481Sym.getType() == ELF::STT_OBJECT ||482Sym.getType() == ELF::STT_SECTION || Sym.getType() == ELF::STT_TLS)) {483484// Map Visibility and Binding to Scope and Linkage:485Linkage L;486Scope S;487if (auto LSOrErr = getSymbolLinkageAndScope(Sym, *Name))488std::tie(L, S) = *LSOrErr;489else490return LSOrErr.takeError();491492// Handle extended tables.493unsigned Shndx = Sym.st_shndx;494if (Shndx == ELF::SHN_XINDEX) {495auto ShndxTable = ShndxTables.find(SymTabSec);496if (ShndxTable == ShndxTables.end())497continue;498auto NdxOrErr = object::getExtendedSymbolTableIndex<ELFT>(499Sym, SymIndex, ShndxTable->second);500if (!NdxOrErr)501return NdxOrErr.takeError();502Shndx = *NdxOrErr;503}504if (auto *B = getGraphBlock(Shndx)) {505LLVM_DEBUG({506dbgs() << " " << SymIndex507<< ": Creating defined graph symbol for ELF symbol \"" << *Name508<< "\"\n";509});510511TargetFlagsType Flags = makeTargetFlags(Sym);512orc::ExecutorAddrDiff Offset = getRawOffset(Sym, Flags);513514if (Offset + Sym.st_size > B->getSize()) {515std::string ErrMsg;516raw_string_ostream ErrStream(ErrMsg);517ErrStream << "In " << G->getName() << ", symbol ";518if (!Name->empty())519ErrStream << *Name;520else521ErrStream << "<anon>";522ErrStream << " (" << (B->getAddress() + Offset) << " -- "523<< (B->getAddress() + Offset + Sym.st_size) << ") extends "524<< formatv("{0:x}", Offset + Sym.st_size - B->getSize())525<< " bytes past the end of its containing block ("526<< B->getRange() << ")";527return make_error<JITLinkError>(std::move(ErrMsg));528}529530// In RISCV, temporary symbols (Used to generate dwarf, eh_frame531// sections...) will appear in object code's symbol table, and LLVM does532// not use names on these temporary symbols (RISCV gnu toolchain uses533// names on these temporary symbols). If the symbol is unnamed, add an534// anonymous symbol.535auto &GSym =536Name->empty()537? G->addAnonymousSymbol(*B, Offset, Sym.st_size,538false, false)539: G->addDefinedSymbol(*B, Offset, *Name, Sym.st_size, L,540S, Sym.getType() == ELF::STT_FUNC,541false);542543GSym.setTargetFlags(Flags);544setGraphSymbol(SymIndex, GSym);545}546} else if (Sym.isUndefined() && Sym.isExternal()) {547LLVM_DEBUG({548dbgs() << " " << SymIndex549<< ": Creating external graph symbol for ELF symbol \"" << *Name550<< "\"\n";551});552553if (Sym.getBinding() != ELF::STB_GLOBAL &&554Sym.getBinding() != ELF::STB_WEAK)555return make_error<StringError>(556"Invalid symbol binding " +557Twine(static_cast<int>(Sym.getBinding())) +558" for external symbol " + *Name,559inconvertibleErrorCode());560561// If L is Linkage::Weak that means this is a weakly referenced symbol.562auto &GSym = G->addExternalSymbol(*Name, Sym.st_size,563Sym.getBinding() == ELF::STB_WEAK);564setGraphSymbol(SymIndex, GSym);565} else if (Sym.isUndefined() && Sym.st_value == 0 && Sym.st_size == 0 &&566Sym.getType() == ELF::STT_NOTYPE &&567Sym.getBinding() == ELF::STB_LOCAL && Name->empty()) {568// Some relocations (e.g., R_RISCV_ALIGN) don't have a target symbol and569// use this kind of null symbol as a placeholder.570LLVM_DEBUG({571dbgs() << " " << SymIndex << ": Creating null graph symbol\n";572});573574auto SymName =575G->allocateContent("__jitlink_ELF_SYM_UND_" + Twine(SymIndex));576auto SymNameRef = StringRef(SymName.data(), SymName.size());577auto &GSym = G->addAbsoluteSymbol(SymNameRef, orc::ExecutorAddr(0), 0,578Linkage::Strong, Scope::Local, false);579setGraphSymbol(SymIndex, GSym);580} else {581LLVM_DEBUG({582dbgs() << " " << SymIndex583<< ": Not creating graph symbol for ELF symbol \"" << *Name584<< "\" with unrecognized type\n";585});586}587}588589return Error::success();590}591592template <typename ELFT>593template <typename RelocHandlerFunction>594Error ELFLinkGraphBuilder<ELFT>::forEachRelaRelocation(595const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func) {596// Only look into sections that store relocation entries.597if (RelSect.sh_type != ELF::SHT_RELA)598return Error::success();599600// sh_info contains the section header index of the target (FixupSection),601// which is the section to which all relocations in RelSect apply.602auto FixupSection = Obj.getSection(RelSect.sh_info);603if (!FixupSection)604return FixupSection.takeError();605606// Target sections have names in valid ELF object files.607Expected<StringRef> Name = Obj.getSectionName(**FixupSection);608if (!Name)609return Name.takeError();610LLVM_DEBUG(dbgs() << " " << *Name << ":\n");611612// Consider skipping these relocations.613if (!ProcessDebugSections && isDwarfSection(*Name)) {614LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");615return Error::success();616}617if (excludeSection(**FixupSection)) {618LLVM_DEBUG(dbgs() << " skipped (fixup section excluded explicitly)\n\n");619return Error::success();620}621622// Lookup the link-graph node corresponding to the target section name.623auto *BlockToFix = getGraphBlock(RelSect.sh_info);624if (!BlockToFix)625return make_error<StringError>(626"Refencing a section that wasn't added to the graph: " + *Name,627inconvertibleErrorCode());628629auto RelEntries = Obj.relas(RelSect);630if (!RelEntries)631return RelEntries.takeError();632633// Let the callee process relocation entries one by one.634for (const typename ELFT::Rela &R : *RelEntries)635if (Error Err = Func(R, **FixupSection, *BlockToFix))636return Err;637638LLVM_DEBUG(dbgs() << "\n");639return Error::success();640}641642template <typename ELFT>643template <typename RelocHandlerFunction>644Error ELFLinkGraphBuilder<ELFT>::forEachRelRelocation(645const typename ELFT::Shdr &RelSect, RelocHandlerFunction &&Func) {646// Only look into sections that store relocation entries.647if (RelSect.sh_type != ELF::SHT_REL)648return Error::success();649650// sh_info contains the section header index of the target (FixupSection),651// which is the section to which all relocations in RelSect apply.652auto FixupSection = Obj.getSection(RelSect.sh_info);653if (!FixupSection)654return FixupSection.takeError();655656// Target sections have names in valid ELF object files.657Expected<StringRef> Name = Obj.getSectionName(**FixupSection);658if (!Name)659return Name.takeError();660LLVM_DEBUG(dbgs() << " " << *Name << ":\n");661662// Consider skipping these relocations.663if (!ProcessDebugSections && isDwarfSection(*Name)) {664LLVM_DEBUG(dbgs() << " skipped (dwarf section)\n\n");665return Error::success();666}667if (excludeSection(**FixupSection)) {668LLVM_DEBUG(dbgs() << " skipped (fixup section excluded explicitly)\n\n");669return Error::success();670}671672// Lookup the link-graph node corresponding to the target section name.673auto *BlockToFix = getGraphBlock(RelSect.sh_info);674if (!BlockToFix)675return make_error<StringError>(676"Refencing a section that wasn't added to the graph: " + *Name,677inconvertibleErrorCode());678679auto RelEntries = Obj.rels(RelSect);680if (!RelEntries)681return RelEntries.takeError();682683// Let the callee process relocation entries one by one.684for (const typename ELFT::Rel &R : *RelEntries)685if (Error Err = Func(R, **FixupSection, *BlockToFix))686return Err;687688LLVM_DEBUG(dbgs() << "\n");689return Error::success();690}691692} // end namespace jitlink693} // end namespace llvm694695#undef DEBUG_TYPE696697#endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H698699700