Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp
35271 views
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
633