653 lines · cpp
1//=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Generic COFF LinkGraph building code.10//11//===----------------------------------------------------------------------===//12#include "COFFLinkGraphBuilder.h"13 14#include <memory>15 16#define DEBUG_TYPE "jitlink"17 18static const char *CommonSectionName = "__common";19 20namespace llvm {21namespace jitlink {22 23static Triple createTripleWithCOFFFormat(Triple T) {24 T.setObjectFormat(Triple::COFF);25 return T;26}27 28COFFLinkGraphBuilder::COFFLinkGraphBuilder(29 const object::COFFObjectFile &Obj,30 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,31 SubtargetFeatures Features,32 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName)33 : Obj(Obj),34 G(std::make_unique<LinkGraph>(Obj.getFileName().str(), std::move(SSP),35 createTripleWithCOFFFormat(std::move(TT)),36 std::move(Features),37 std::move(GetEdgeKindName))) {38 LLVM_DEBUG({39 dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj.getFileName()40 << "\"\n";41 });42}43 44COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;45 46uint64_t COFFLinkGraphBuilder::getSectionSize(const object::COFFObjectFile &Obj,47 const object::coff_section *Sec) {48 // Consider the difference between executable form and object form.49 // More information is inside COFFObjectFile::getSectionSize50 if (Obj.getDOSHeader())51 return std::min(Sec->VirtualSize, Sec->SizeOfRawData);52 return Sec->SizeOfRawData;53}54 55uint64_t56COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,57 const object::coff_section *Section) {58 return Section->VirtualAddress + Obj.getImageBase();59}60 61bool COFFLinkGraphBuilder::isComdatSection(62 const object::coff_section *Section) {63 return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;64}65 66Section &COFFLinkGraphBuilder::getCommonSection() {67 if (!CommonSection)68 CommonSection = &G->createSection(CommonSectionName,69 orc::MemProt::Read | orc::MemProt::Write);70 return *CommonSection;71}72 73Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {74 if (!Obj.isRelocatableObject())75 return make_error<JITLinkError>("Object is not a relocatable COFF file");76 77 if (auto Err = graphifySections())78 return std::move(Err);79 80 if (auto Err = graphifySymbols())81 return std::move(Err);82 83 if (auto Err = addRelocations())84 return std::move(Err);85 86 return std::move(G);87}88 89StringRef90COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex,91 const object::coff_section *Sec,92 object::COFFSymbolRef Sym) {93 switch (SectionIndex) {94 case COFF::IMAGE_SYM_UNDEFINED: {95 if (Sym.getValue())96 return "(common)";97 else98 return "(external)";99 }100 case COFF::IMAGE_SYM_ABSOLUTE:101 return "(absolute)";102 case COFF::IMAGE_SYM_DEBUG: {103 // Used with .file symbol104 return "(debug)";105 }106 default: {107 // Non reserved regular section numbers108 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))109 return *SecNameOrErr;110 }111 }112 return "";113}114 115Error COFFLinkGraphBuilder::graphifySections() {116 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");117 118 GraphBlocks.resize(Obj.getNumberOfSections() + 1);119 // For each section...120 for (COFFSectionIndex SecIndex = 1;121 SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());122 SecIndex++) {123 Expected<const object::coff_section *> Sec = Obj.getSection(SecIndex);124 if (!Sec)125 return Sec.takeError();126 127 StringRef SectionName;128 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))129 SectionName = *SecNameOrErr;130 131 // FIXME: Skip debug info sections132 if (SectionName == ".voltbl") {133 LLVM_DEBUG({134 dbgs() << " "135 << "Skipping section \"" << SectionName << "\"\n";136 });137 continue;138 }139 140 LLVM_DEBUG({141 dbgs() << " "142 << "Creating section for \"" << SectionName << "\"\n";143 });144 145 // Get the section's memory protection flags.146 orc::MemProt Prot = orc::MemProt::Read;147 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE)148 Prot |= orc::MemProt::Exec;149 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_READ)150 Prot |= orc::MemProt::Read;151 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_MEM_WRITE)152 Prot |= orc::MemProt::Write;153 154 // Look for existing sections first.155 auto *GraphSec = G->findSectionByName(SectionName);156 if (!GraphSec) {157 GraphSec = &G->createSection(SectionName, Prot);158 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_LNK_REMOVE)159 GraphSec->setMemLifetime(orc::MemLifetime::NoAlloc);160 }161 if (GraphSec->getMemProt() != Prot)162 return make_error<JITLinkError>("MemProt should match");163 164 Block *B = nullptr;165 if ((*Sec)->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)166 B = &G->createZeroFillBlock(167 *GraphSec, getSectionSize(Obj, *Sec),168 orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),169 (*Sec)->getAlignment(), 0);170 else {171 ArrayRef<uint8_t> Data;172 if (auto Err = Obj.getSectionContents(*Sec, Data))173 return Err;174 175 auto CharData = ArrayRef<char>(176 reinterpret_cast<const char *>(Data.data()), Data.size());177 178 if (SectionName == getDirectiveSectionName())179 if (auto Err = handleDirectiveSection(180 StringRef(CharData.data(), CharData.size())))181 return Err;182 183 B = &G->createContentBlock(184 *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),185 (*Sec)->getAlignment(), 0);186 }187 188 setGraphBlock(SecIndex, B);189 }190 191 return Error::success();192}193 194Error COFFLinkGraphBuilder::graphifySymbols() {195 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");196 197 SymbolSets.resize(Obj.getNumberOfSections() + 1);198 PendingComdatExports.resize(Obj.getNumberOfSections() + 1);199 GraphSymbols.resize(Obj.getNumberOfSymbols());200 201 for (COFFSymbolIndex SymIndex = 0;202 SymIndex < static_cast<COFFSymbolIndex>(Obj.getNumberOfSymbols());203 SymIndex++) {204 Expected<object::COFFSymbolRef> Sym = Obj.getSymbol(SymIndex);205 if (!Sym)206 return Sym.takeError();207 208 StringRef SymbolName;209 if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))210 SymbolName = *SymNameOrErr;211 212 COFFSectionIndex SectionIndex = Sym->getSectionNumber();213 const object::coff_section *Sec = nullptr;214 215 if (!COFF::isReservedSectionNumber(SectionIndex)) {216 auto SecOrErr = Obj.getSection(SectionIndex);217 if (!SecOrErr)218 return make_error<JITLinkError>(219 "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex) +220 " (" + toString(SecOrErr.takeError()) + ")");221 Sec = *SecOrErr;222 }223 auto InternedSymbolName = G->intern(std::move(SymbolName));224 225 // Create jitlink symbol226 jitlink::Symbol *GSym = nullptr;227 if (Sym->isFileRecord())228 LLVM_DEBUG({229 dbgs() << " " << SymIndex << ": Skipping FileRecord symbol \""230 << InternedSymbolName << "\" in "231 << getCOFFSectionName(SectionIndex, Sec, *Sym)232 << " (index: " << SectionIndex << ") \n";233 });234 else if (Sym->isUndefined()) {235 GSym = createExternalSymbol(SymIndex, InternedSymbolName, *Sym, Sec);236 } else if (Sym->isWeakExternal()) {237 auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();238 COFFSymbolIndex TagIndex = WeakExternal->TagIndex;239 uint32_t Characteristics = WeakExternal->Characteristics;240 WeakExternalRequests.push_back(241 {SymIndex, TagIndex, Characteristics, SymbolName});242 } else {243 Expected<jitlink::Symbol *> NewGSym =244 createDefinedSymbol(SymIndex, InternedSymbolName, *Sym, Sec);245 if (!NewGSym)246 return NewGSym.takeError();247 GSym = *NewGSym;248 if (GSym) {249 LLVM_DEBUG({250 dbgs() << " " << SymIndex251 << ": Creating defined graph symbol for COFF symbol \""252 << InternedSymbolName << "\" in "253 << getCOFFSectionName(SectionIndex, Sec, *Sym)254 << " (index: " << SectionIndex << ") \n";255 dbgs() << " " << *GSym << "\n";256 });257 }258 }259 260 // Register the symbol261 if (GSym)262 setGraphSymbol(SectionIndex, SymIndex, *GSym);263 SymIndex += Sym->getNumberOfAuxSymbols();264 }265 266 if (auto Err = flushWeakAliasRequests())267 return Err;268 269 if (auto Err = handleAlternateNames())270 return Err;271 272 if (auto Err = calculateImplicitSizeOfSymbols())273 return Err;274 275 return Error::success();276}277 278Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) {279 auto Parsed = DirectiveParser.parse(Str);280 if (!Parsed)281 return Parsed.takeError();282 for (auto *Arg : *Parsed) {283 StringRef S = Arg->getValue();284 switch (Arg->getOption().getID()) {285 case COFF_OPT_alternatename: {286 StringRef From, To;287 std::tie(From, To) = S.split('=');288 if (From.empty() || To.empty())289 return make_error<JITLinkError>(290 "Invalid COFF /alternatename directive");291 AlternateNames[G->intern(From)] = G->intern(To);292 break;293 }294 case COFF_OPT_incl: {295 auto Symbol = &G->addExternalSymbol(S, 0, false);296 Symbol->setLive(true);297 ExternalSymbols[Symbol->getName()] = Symbol;298 break;299 }300 case COFF_OPT_export:301 break;302 default: {303 LLVM_DEBUG({304 dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n";305 });306 break;307 }308 }309 }310 return Error::success();311}312 313Error COFFLinkGraphBuilder::flushWeakAliasRequests() {314 // Export the weak external symbols and alias it315 for (auto &WeakExternal : WeakExternalRequests) {316 if (auto *Target = getGraphSymbol(WeakExternal.Target)) {317 Expected<object::COFFSymbolRef> AliasSymbol =318 Obj.getSymbol(WeakExternal.Alias);319 if (!AliasSymbol)320 return AliasSymbol.takeError();321 322 // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and323 // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.324 Scope S =325 WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS326 ? Scope::Default327 : Scope::Local;328 329 auto NewSymbol = createAliasSymbol(G->intern(WeakExternal.SymbolName),330 Linkage::Weak, S, *Target);331 if (!NewSymbol)332 return NewSymbol.takeError();333 setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,334 **NewSymbol);335 LLVM_DEBUG({336 dbgs() << " " << WeakExternal.Alias337 << ": Creating weak external symbol for COFF symbol \""338 << WeakExternal.SymbolName << "\" in section "339 << AliasSymbol->getSectionNumber() << "\n";340 dbgs() << " " << **NewSymbol << "\n";341 });342 } else343 return make_error<JITLinkError>("Weak symbol alias requested but actual "344 "symbol not found for symbol " +345 formatv("{0:d}", WeakExternal.Alias));346 }347 return Error::success();348}349 350Error COFFLinkGraphBuilder::handleAlternateNames() {351 for (auto &KeyValue : AlternateNames) {352 auto DefinedSymbolName = KeyValue.second;353 auto ExternalSymbolsName = KeyValue.first;354 if (DefinedSymbols.count(DefinedSymbolName) &&355 ExternalSymbols.count(ExternalSymbolsName)) {356 auto *Target = DefinedSymbols[DefinedSymbolName];357 auto *Alias = ExternalSymbols[ExternalSymbolsName];358 G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(),359 Target->getSize(), Linkage::Weak, Scope::Local, false);360 }361 }362 return Error::success();363}364 365Symbol *COFFLinkGraphBuilder::createExternalSymbol(366 COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName,367 object::COFFSymbolRef Symbol, const object::coff_section *Section) {368 llvm::jitlink::Symbol *Sym = nullptr;369 if (auto It = ExternalSymbols.find(SymbolName); It == ExternalSymbols.end()) {370 Sym = &G->addExternalSymbol(*SymbolName, Symbol.getValue(), false);371 ExternalSymbols[Sym->getName()] = Sym;372 } else {373 Sym = It->second;374 }375 376 LLVM_DEBUG({377 dbgs() << " " << SymIndex378 << ": Creating external graph symbol for COFF symbol \""379 << Sym->getName() << "\" in "380 << getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol)381 << " (index: " << Symbol.getSectionNumber() << ") \n";382 });383 return Sym;384}385 386Expected<Symbol *>387COFFLinkGraphBuilder::createAliasSymbol(orc::SymbolStringPtr SymbolName,388 Linkage L, Scope S, Symbol &Target) {389 if (!Target.isDefined()) {390 // FIXME: Support this when there's a way to handle this.391 return make_error<JITLinkError>("Weak external symbol with external "392 "symbol as alternative not supported.");393 }394 return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName,395 Target.getSize(), L, S, Target.isCallable(),396 false);397}398 399// In COFF, most of the defined symbols don't contain the size information.400// Hence, we calculate the "implicit" size of symbol by taking the delta of401// offsets of consecutive symbols within a block. We maintain a balanced tree402// set of symbols sorted by offset per each block in order to achieve403// logarithmic time complexity of sorted symbol insertion. Symbol is inserted to404// the set once it's processed in graphifySymbols. In this function, we iterate405// each collected symbol in sorted order and calculate the implicit size.406Error COFFLinkGraphBuilder::calculateImplicitSizeOfSymbols() {407 for (COFFSectionIndex SecIndex = 1;408 SecIndex <= static_cast<COFFSectionIndex>(Obj.getNumberOfSections());409 SecIndex++) {410 auto &SymbolSet = SymbolSets[SecIndex];411 if (SymbolSet.empty())412 continue;413 jitlink::Block *B = getGraphBlock(SecIndex);414 orc::ExecutorAddrDiff LastOffset = B->getSize();415 orc::ExecutorAddrDiff LastDifferentOffset = B->getSize();416 orc::ExecutorAddrDiff LastSize = 0;417 for (auto It = SymbolSet.rbegin(); It != SymbolSet.rend(); It++) {418 orc::ExecutorAddrDiff Offset = It->first;419 jitlink::Symbol *Symbol = It->second;420 orc::ExecutorAddrDiff CandSize;421 // Last offset can be same when aliasing happened422 if (Symbol->getOffset() == LastOffset)423 CandSize = LastSize;424 else425 CandSize = LastOffset - Offset;426 427 LLVM_DEBUG({428 if (Offset + Symbol->getSize() > LastDifferentOffset)429 dbgs() << " Overlapping symbol range generated for the following "430 "symbol:"431 << "\n"432 << " " << *Symbol << "\n";433 });434 (void)LastDifferentOffset;435 if (LastOffset != Offset)436 LastDifferentOffset = Offset;437 LastSize = CandSize;438 LastOffset = Offset;439 if (Symbol->getSize()) {440 // Non empty symbol can happen in COMDAT symbol.441 // We don't consider the possibility of overlapping symbol range that442 // could be introduced by disparity between inferred symbol size and443 // defined symbol size because symbol size information is currently only444 // used by jitlink-check where we have control to not make overlapping445 // ranges.446 continue;447 }448 449 LLVM_DEBUG({450 if (!CandSize)451 dbgs() << " Empty implicit symbol size generated for the following "452 "symbol:"453 << "\n"454 << " " << *Symbol << "\n";455 });456 457 Symbol->setSize(CandSize);458 }459 }460 return Error::success();461}462 463Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(464 COFFSymbolIndex SymIndex, orc::SymbolStringPtr SymbolName,465 object::COFFSymbolRef Symbol, const object::coff_section *Section) {466 467 if (Symbol.isCommon()) {468 // FIXME: correct alignment469 return &G->addDefinedSymbol(470 G->createZeroFillBlock(getCommonSection(), Symbol.getValue(),471 orc::ExecutorAddr(), Symbol.getValue(), 0),472 0, SymbolName, Symbol.getValue(), Linkage::Weak, Scope::Default,473 false, false);474 }475 476 if (Symbol.isAbsolute())477 return &G->addAbsoluteSymbol(SymbolName,478 orc::ExecutorAddr(Symbol.getValue()), 0,479 Linkage::Strong, Scope::Local, false);480 481 if (llvm::COFF::isReservedSectionNumber(Symbol.getSectionNumber()))482 return make_error<JITLinkError>(483 "Reserved section number used in regular symbol " +484 formatv("{0:d}", SymIndex));485 486 Block *B = getGraphBlock(Symbol.getSectionNumber());487 if (!B) {488 LLVM_DEBUG({489 dbgs() << " " << SymIndex490 << ": Skipping graph symbol since section was not created for "491 "COFF symbol \""492 << SymbolName << "\" in section " << Symbol.getSectionNumber()493 << "\n";494 });495 return nullptr;496 }497 498 if (Symbol.isExternal()) {499 // This is not a comdat sequence, export the symbol as it is500 if (!isComdatSection(Section)) {501 auto GSym = &G->addDefinedSymbol(502 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,503 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);504 DefinedSymbols[SymbolName] = GSym;505 return GSym;506 } else {507 if (!PendingComdatExports[Symbol.getSectionNumber()])508 return make_error<JITLinkError>("No pending COMDAT export for symbol " +509 formatv("{0:d}", SymIndex));510 511 return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);512 }513 }514 515 if (Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC ||516 Symbol.getStorageClass() == COFF::IMAGE_SYM_CLASS_LABEL) {517 const object::coff_aux_section_definition *Definition =518 Symbol.getSectionDefinition();519 if (!Definition || !isComdatSection(Section)) {520 // Handle typical static symbol521 return &G->addDefinedSymbol(522 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,523 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);524 }525 if (Definition->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {526 auto Target = Definition->getNumber(Symbol.isBigObj());527 auto GSym = &G->addDefinedSymbol(528 *B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Local,529 Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);530 getGraphBlock(Target)->addEdge(Edge::KeepAlive, 0, *GSym, 0);531 return GSym;532 }533 if (PendingComdatExports[Symbol.getSectionNumber()])534 return make_error<JITLinkError>(535 "COMDAT export request already exists before symbol " +536 formatv("{0:d}", SymIndex));537 return createCOMDATExportRequest(SymIndex, Symbol, Definition);538 }539 return make_error<JITLinkError>("Unsupported storage class " +540 formatv("{0:d}", Symbol.getStorageClass()) +541 " in symbol " + formatv("{0:d}", SymIndex));542}543 544// COMDAT handling:545// When IMAGE_SCN_LNK_COMDAT flag is set in the flags of a section,546// the section is called a COMDAT section. It contains two symbols547// in a sequence that specifes the behavior. First symbol is the section548// symbol which contains the size and name of the section. It also contains549// selection type that specifies how duplicate of the symbol is handled.550// Second symbol is COMDAT symbol which usually defines the external name and551// data type.552//553// Since two symbols always come in a specific order, we initiate pending COMDAT554// export request when we encounter the first symbol and actually exports it555// when we process the second symbol.556//557// Process the first symbol of COMDAT sequence.558Expected<Symbol *> COFFLinkGraphBuilder::createCOMDATExportRequest(559 COFFSymbolIndex SymIndex, object::COFFSymbolRef Symbol,560 const object::coff_aux_section_definition *Definition) {561 Linkage L = Linkage::Strong;562 switch (Definition->Selection) {563 case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: {564 L = Linkage::Strong;565 break;566 }567 case COFF::IMAGE_COMDAT_SELECT_ANY: {568 L = Linkage::Weak;569 break;570 }571 case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:572 case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: {573 // FIXME: Implement size/content validation when LinkGraph is able to574 // handle this.575 L = Linkage::Weak;576 break;577 }578 case COFF::IMAGE_COMDAT_SELECT_LARGEST: {579 // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is580 // able to handle this.581 LLVM_DEBUG({582 dbgs() << " " << SymIndex583 << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"584 " in section "585 << Symbol.getSectionNumber() << " (size: " << Definition->Length586 << ")\n";587 });588 L = Linkage::Weak;589 break;590 }591 case COFF::IMAGE_COMDAT_SELECT_NEWEST: {592 // Even link.exe doesn't support this selection properly.593 return make_error<JITLinkError>(594 "IMAGE_COMDAT_SELECT_NEWEST is not supported.");595 }596 default: {597 return make_error<JITLinkError>("Invalid comdat selection type: " +598 formatv("{0:d}", Definition->Selection));599 }600 }601 PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L,602 Definition->Length};603 return nullptr;604}605 606// Process the second symbol of COMDAT sequence.607Expected<Symbol *>608COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,609 orc::SymbolStringPtr SymbolName,610 object::COFFSymbolRef Symbol) {611 Block *B = getGraphBlock(Symbol.getSectionNumber());612 auto &PendingComdatExport = PendingComdatExports[Symbol.getSectionNumber()];613 // NOTE: ComdatDef->Length is the size of "section" not size of symbol.614 // We use zero symbol size to not reach out of bound of block when symbol615 // offset is non-zero.616 auto GSym = &G->addDefinedSymbol(617 *B, Symbol.getValue(), SymbolName, 0, PendingComdatExport->Linkage,618 Scope::Default, Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION,619 false);620 LLVM_DEBUG({621 dbgs() << " " << SymIndex622 << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName623 << "\" in section " << Symbol.getSectionNumber() << "\n";624 dbgs() << " " << *GSym << "\n";625 });626 setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex,627 *GSym);628 DefinedSymbols[SymbolName] = GSym;629 PendingComdatExport = std::nullopt;630 return GSym;631}632 633Symbol *GetImageBaseSymbol::operator()(LinkGraph &G) {634 if (ImageBase)635 return *ImageBase;636 637 auto IBN = G.intern(ImageBaseName);638 ImageBase = G.findExternalSymbolByName(IBN);639 if (*ImageBase)640 return *ImageBase;641 ImageBase = G.findAbsoluteSymbolByName(IBN);642 if (*ImageBase)643 return *ImageBase;644 ImageBase = G.findDefinedSymbolByName(IBN);645 if (*ImageBase)646 return *ImageBase;647 648 return nullptr;649}650 651} // namespace jitlink652} // namespace llvm653