xref: /llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp (revision 9c5001e45491ae8b1b2967d2fa48f445799c88ae)
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-exception
6 //
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 
18 static const char *CommonSectionName = "__common";
19 
20 namespace llvm {
21 namespace jitlink {
22 
23 static Triple createTripleWithCOFFFormat(Triple T) {
24   T.setObjectFormat(Triple::COFF);
25   return T;
26 }
27 
28 COFFLinkGraphBuilder::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 
44 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
45 
46 uint64_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::getSectionSize
50   if (Obj.getDOSHeader())
51     return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
52   return Sec->SizeOfRawData;
53 }
54 
55 uint64_t
56 COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,
57                                         const object::coff_section *Section) {
58   return Section->VirtualAddress + Obj.getImageBase();
59 }
60 
61 bool COFFLinkGraphBuilder::isComdatSection(
62     const object::coff_section *Section) {
63   return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;
64 }
65 
66 Section &COFFLinkGraphBuilder::getCommonSection() {
67   if (!CommonSection)
68     CommonSection = &G->createSection(CommonSectionName,
69                                       orc::MemProt::Read | orc::MemProt::Write);
70   return *CommonSection;
71 }
72 
73 Expected<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 
89 StringRef
90 COFFLinkGraphBuilder::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     else
98       return "(external)";
99   }
100   case COFF::IMAGE_SYM_ABSOLUTE:
101     return "(absolute)";
102   case COFF::IMAGE_SYM_DEBUG: {
103     // Used with .file symbol
104     return "(debug)";
105   }
106   default: {
107     // Non reserved regular section numbers
108     if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))
109       return *SecNameOrErr;
110   }
111   }
112   return "";
113 }
114 
115 Error 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 sections
132     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 
194 Error 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 symbol
226     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() << "    " << SymIndex
251                  << ": 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 symbol
261     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 
278 Error 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 
313 Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
314   // Export the weak external symbols and alias it
315   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 and
323       // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
324       Scope S =
325           WeakExternal.Characteristics == COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
326               ? Scope::Default
327               : 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.Alias
337                << ": Creating weak external symbol for COFF symbol \""
338                << WeakExternal.SymbolName << "\" in section "
339                << AliasSymbol->getSectionNumber() << "\n";
340         dbgs() << "      " << **NewSymbol << "\n";
341       });
342     } else
343       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 
350 Error 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 
365 Symbol *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 (!ExternalSymbols.count(SymbolName)) {
370     Sym = &G->addExternalSymbol(*SymbolName, Symbol.getValue(), false);
371     ExternalSymbols[Sym->getName()] = Sym;
372   } else {
373     Sym = ExternalSymbols[SymbolName];
374   }
375 
376   LLVM_DEBUG({
377     dbgs() << "    " << SymIndex
378            << ": 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 
386 Expected<Symbol *>
387 COFFLinkGraphBuilder::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 of
401 // offsets of consecutive symbols within a block. We maintain a balanced tree
402 // set of symbols sorted by offset per each block in order to achieve
403 // logarithmic time complexity of sorted symbol insertion. Symbol is inserted to
404 // the set once it's processed in graphifySymbols. In this function, we iterate
405 // each collected symbol in sorted order and calculate the implicit size.
406 Error 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 happened
422       if (Symbol->getOffset() == LastOffset)
423         CandSize = LastSize;
424       else
425         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 that
442         // could be introduced by disparity between inferred symbol size and
443         // defined symbol size because symbol size information is currently only
444         // used by jitlink-check where we have control to not make overlapping
445         // 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 
463 Expected<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 alignment
469     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() << "    " << SymIndex
490              << ": 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 is
500     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 symbol
521       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 symbols
547 // in a sequence that specifes the behavior. First symbol is the section
548 // symbol which contains the size and name of the section. It also contains
549 // selection type that specifies how duplicate of the symbol is handled.
550 // Second symbol is COMDAT symbol which usually defines the external name and
551 // data type.
552 //
553 // Since two symbols always come in a specific order, we initiate pending COMDAT
554 // export request when we encounter the first symbol and actually exports it
555 // when we process the second symbol.
556 //
557 // Process the first symbol of COMDAT sequence.
558 Expected<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 to
574     // 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 is
580     // able to handle this.
581     LLVM_DEBUG({
582       dbgs() << "    " << SymIndex
583              << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
584                 " in section "
585              << Symbol.getSectionNumber() << " (size: " << Definition->Length
586              << ")\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.
607 Expected<Symbol *>
608 COFFLinkGraphBuilder::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 symbol
615   // 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() << "    " << SymIndex
622            << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
623            << "\" 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 
633 Symbol *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 jitlink
652 } // namespace llvm
653