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