[AMDGPU] Test codegen'ing True16 additions.
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / COFFLinkGraphBuilder.cpp
blob30286ea8811f7ca1df9927f1bc7fdbe91159a544
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.
11 //===----------------------------------------------------------------------===//
12 #include "COFFLinkGraphBuilder.h"
14 #define DEBUG_TYPE "jitlink"
16 static const char *CommonSectionName = "__common";
18 namespace llvm {
19 namespace jitlink {
21 static Triple createTripleWithCOFFFormat(Triple T) {
22 T.setObjectFormat(Triple::COFF);
23 return T;
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 });
39 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
41 unsigned
42 COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile &Obj) {
43 return Obj.getBytesInAddress();
46 support::endianness
47 COFFLinkGraphBuilder::getEndianness(const object::COFFObjectFile &Obj) {
48 return Obj.isLittleEndian() ? support::little : support::big;
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;
60 uint64_t
61 COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile &Obj,
62 const object::coff_section *Section) {
63 return Section->VirtualAddress + Obj.getImageBase();
66 bool COFFLinkGraphBuilder::isComdatSection(
67 const object::coff_section *Section) {
68 return Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT;
71 Section &COFFLinkGraphBuilder::getCommonSection() {
72 if (!CommonSection)
73 CommonSection = &G->createSection(CommonSectionName,
74 orc::MemProt::Read | orc::MemProt::Write);
75 return *CommonSection;
78 Expected<std::unique_ptr<LinkGraph>> COFFLinkGraphBuilder::buildGraph() {
79 if (!Obj.isRelocatableObject())
80 return make_error<JITLinkError>("Object is not a relocatable COFF file");
82 if (auto Err = graphifySections())
83 return std::move(Err);
85 if (auto Err = graphifySymbols())
86 return std::move(Err);
88 if (auto Err = addRelocations())
89 return std::move(Err);
91 return std::move(G);
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)";
105 case COFF::IMAGE_SYM_ABSOLUTE:
106 return "(absolute)";
107 case COFF::IMAGE_SYM_DEBUG: {
108 // Used with .file symbol
109 return "(debug)";
111 default: {
112 // Non reserved regular section numbers
113 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(Sec))
114 return *SecNameOrErr;
117 return "";
120 Error COFFLinkGraphBuilder::graphifySections() {
121 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
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();
132 StringRef SectionName;
133 if (Expected<StringRef> SecNameOrErr = Obj.getSectionName(*Sec))
134 SectionName = *SecNameOrErr;
136 // FIXME: Skip debug info sections
137 if (SectionName == ".voltbl") {
138 LLVM_DEBUG({
139 dbgs() << " "
140 << "Skipping section \"" << SectionName << "\"\n";
142 continue;
145 LLVM_DEBUG({
146 dbgs() << " "
147 << "Creating section for \"" << SectionName << "\"\n";
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;
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);
166 if (GraphSec->getMemProt() != Prot)
167 return make_error<JITLinkError>("MemProt should match");
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;
180 auto CharData = ArrayRef<char>(
181 reinterpret_cast<const char *>(Data.data()), Data.size());
183 if (SectionName == getDirectiveSectionName())
184 if (auto Err = handleDirectiveSection(
185 StringRef(CharData.data(), CharData.size())))
186 return Err;
188 B = &G->createContentBlock(
189 *GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
190 (*Sec)->getAlignment(), 0);
193 setGraphBlock(SecIndex, B);
196 return Error::success();
199 Error COFFLinkGraphBuilder::graphifySymbols() {
200 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
202 SymbolSets.resize(Obj.getNumberOfSections() + 1);
203 PendingComdatExports.resize(Obj.getNumberOfSections() + 1);
204 GraphSymbols.resize(Obj.getNumberOfSymbols());
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();
213 StringRef SymbolName;
214 if (Expected<StringRef> SymNameOrErr = Obj.getSymbolName(*Sym))
215 SymbolName = *SymNameOrErr;
217 COFFSectionIndex SectionIndex = Sym->getSectionNumber();
218 const object::coff_section *Sec = nullptr;
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;
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";
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";
264 // Register the symbol
265 if (GSym)
266 setGraphSymbol(SectionIndex, SymIndex, *GSym);
267 SymIndex += Sym->getNumberOfAuxSymbols();
270 if (auto Err = flushWeakAliasRequests())
271 return Err;
273 if (auto Err = handleAlternateNames())
274 return Err;
276 if (auto Err = calculateImplicitSizeOfSymbols())
277 return Err;
279 return Error::success();
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;
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;
305 case COFF_OPT_export:
306 break;
307 default: {
308 LLVM_DEBUG({
309 dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n";
311 break;
315 return Error::success();
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();
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;
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";
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));
352 return Error::success();
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);
364 return Error::success();
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);
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";
381 return ExternalSymbols[SymbolName];
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.");
392 return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName,
393 Target.getSize(), L, S, Target.isCallable(),
394 false);
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;
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";
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;
447 LLVM_DEBUG({
448 if (!CandSize)
449 dbgs() << " Empty implicit symbol size generated for the following "
450 "symbol:"
451 << "\n"
452 << " " << *Symbol << "\n";
455 Symbol->setSize(CandSize);
458 return Error::success();
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);
472 if (Symbol.isAbsolute())
473 return &G->addAbsoluteSymbol(SymbolName,
474 orc::ExecutorAddr(Symbol.getValue()), 0,
475 Linkage::Strong, Scope::Local, false);
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));
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";
491 return nullptr;
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));
507 return exportCOMDATSymbol(SymIndex, SymbolName, Symbol);
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);
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;
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);
535 return make_error<JITLinkError>("Unsupported storage class " +
536 formatv("{0:d}", Symbol.getStorageClass()) +
537 " in symbol " + formatv("{0:d}", SymIndex));
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.
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.
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;
563 case COFF::IMAGE_COMDAT_SELECT_ANY: {
564 L = Linkage::Weak;
565 break;
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;
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";
584 L = Linkage::Weak;
585 break;
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.");
592 default: {
593 return make_error<JITLinkError>("Invalid comdat selection type: " +
594 formatv("{0:d}", Definition->Selection));
597 PendingComdatExports[Symbol.getSectionNumber()] = {SymIndex, L,
598 Definition->Length};
599 return nullptr;
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->Length 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";
622 setGraphSymbol(Symbol.getSectionNumber(), PendingComdatExport->SymbolIndex,
623 *GSym);
624 DefinedSymbols[SymbolName] = GSym;
625 PendingComdatExport = std::nullopt;
626 return GSym;
629 } // namespace jitlink
630 } // namespace llvm