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