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