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