1 //=--------- COFFLinkGraphBuilder.cpp - COFF LinkGraph builder ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // Generic COFF LinkGraph building code.
11 //===----------------------------------------------------------------------===//
12 #include "COFFLinkGraphBuilder.h"
14 #define DEBUG_TYPE "jitlink"
16 static const char *CommonSectionName
= "__common";
21 static Triple
createTripleWithCOFFFormat(Triple T
) {
22 T
.setObjectFormat(Triple::COFF
);
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
))) {
34 dbgs() << "Created COFFLinkGraphBuilder for \"" << Obj
.getFileName()
39 COFFLinkGraphBuilder::~COFFLinkGraphBuilder() = default;
42 COFFLinkGraphBuilder::getPointerSize(const object::COFFObjectFile
&Obj
) {
43 return Obj
.getBytesInAddress();
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
;
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() {
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
);
95 COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex
,
96 const object::coff_section
*Sec
,
97 object::COFFSymbolRef Sym
) {
98 switch (SectionIndex
) {
99 case COFF::IMAGE_SYM_UNDEFINED
: {
105 case COFF::IMAGE_SYM_ABSOLUTE
:
107 case COFF::IMAGE_SYM_DEBUG
: {
108 // Used with .file symbol
112 // Non reserved regular section numbers
113 if (Expected
<StringRef
> SecNameOrErr
= Obj
.getSectionName(Sec
))
114 return *SecNameOrErr
;
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());
128 Expected
<const object::coff_section
*> Sec
= Obj
.getSection(SecIndex
);
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") {
140 << "Skipping section \"" << SectionName
<< "\"\n";
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
);
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");
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);
176 ArrayRef
<uint8_t> Data
;
177 if (auto Err
= Obj
.getSectionContents(*Sec
, Data
))
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())))
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());
209 Expected
<object::COFFSymbolRef
> Sym
= Obj
.getSymbol(SymIndex
);
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
);
223 return make_error
<JITLinkError
>(
224 "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex
) +
225 " (" + toString(SecOrErr
.takeError()) + ")");
229 // Create jitlink symbol
230 jitlink::Symbol
*GSym
= nullptr;
231 if (Sym
->isFileRecord())
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
});
247 Expected
<jitlink::Symbol
*> NewGSym
=
248 createDefinedSymbol(SymIndex
, SymbolName
, *Sym
, Sec
);
250 return NewGSym
.takeError();
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
266 setGraphSymbol(SectionIndex
, SymIndex
, *GSym
);
267 SymIndex
+= Sym
->getNumberOfAuxSymbols();
270 if (auto Err
= flushWeakAliasRequests())
273 if (auto Err
= handleAlternateNames())
276 if (auto Err
= calculateImplicitSizeOfSymbols())
279 return Error::success();
282 Error
COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str
) {
283 auto Parsed
= DirectiveParser
.parse(Str
);
285 return Parsed
.takeError();
286 for (auto *Arg
: *Parsed
) {
287 StringRef S
= Arg
->getValue();
288 switch (Arg
->getOption().getID()) {
289 case COFF_OPT_alternatename
: {
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
;
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);
305 case COFF_OPT_export
:
309 dbgs() << "Unknown coff directive: " << Arg
->getSpelling() << "\n";
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
);
325 return AliasSymbol
.takeError();
327 // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
328 // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
330 WeakExternal
.Characteristics
== COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
335 createAliasSymbol(WeakExternal
.SymbolName
, Linkage::Weak
, S
, *Target
);
337 return NewSymbol
.takeError();
338 setGraphSymbol(AliasSymbol
->getSectionNumber(), WeakExternal
.Alias
,
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";
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);
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
,
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(),
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());
408 auto &SymbolSet
= SymbolSets
[SecIndex
];
409 if (SymbolSet
.empty())
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
)
423 CandSize
= LastOffset
- Offset
;
426 if (Offset
+ Symbol
->getSize() > LastDifferentOffset
)
427 dbgs() << " Overlapping symbol range generated for the following "
430 << " " << *Symbol
<< "\n";
432 (void)LastDifferentOffset
;
433 if (LastOffset
!= Offset
)
434 LastDifferentOffset
= 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
449 dbgs() << " Empty implicit symbol size generated for the following "
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
,
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());
485 dbgs() << " " << SymIndex
486 << ": Skipping graph symbol since section was not created for "
488 << SymbolName
<< "\" in section " << Symbol
.getSectionNumber()
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
;
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);
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
));
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
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
: {
563 case COFF::IMAGE_COMDAT_SELECT_ANY
: {
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
574 case COFF::IMAGE_COMDAT_SELECT_LARGEST
: {
575 // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
576 // able to handle this.
578 dbgs() << " " << SymIndex
579 << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
581 << Symbol
.getSectionNumber() << " (size: " << Definition
->Length
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.");
593 return make_error
<JITLinkError
>("Invalid comdat selection type: " +
594 formatv("{0:d}", Definition
->Selection
));
597 PendingComdatExports
[Symbol
.getSectionNumber()] = {SymIndex
, L
,
602 // Process the second symbol of COMDAT sequence.
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
,
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
,
624 DefinedSymbols
[SymbolName
] = GSym
;
625 PendingComdatExport
= std::nullopt
;
629 } // namespace jitlink