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