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() ? llvm::endianness::little
49 : llvm::endianness::big
;
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
;
62 COFFLinkGraphBuilder::getSectionAddress(const object::COFFObjectFile
&Obj
,
63 const object::coff_section
*Section
) {
64 return Section
->VirtualAddress
+ Obj
.getImageBase();
67 bool COFFLinkGraphBuilder::isComdatSection(
68 const object::coff_section
*Section
) {
69 return Section
->Characteristics
& COFF::IMAGE_SCN_LNK_COMDAT
;
72 Section
&COFFLinkGraphBuilder::getCommonSection() {
74 CommonSection
= &G
->createSection(CommonSectionName
,
75 orc::MemProt::Read
| orc::MemProt::Write
);
76 return *CommonSection
;
79 Expected
<std::unique_ptr
<LinkGraph
>> COFFLinkGraphBuilder::buildGraph() {
80 if (!Obj
.isRelocatableObject())
81 return make_error
<JITLinkError
>("Object is not a relocatable COFF file");
83 if (auto Err
= graphifySections())
84 return std::move(Err
);
86 if (auto Err
= graphifySymbols())
87 return std::move(Err
);
89 if (auto Err
= addRelocations())
90 return std::move(Err
);
96 COFFLinkGraphBuilder::getCOFFSectionName(COFFSectionIndex SectionIndex
,
97 const object::coff_section
*Sec
,
98 object::COFFSymbolRef Sym
) {
99 switch (SectionIndex
) {
100 case COFF::IMAGE_SYM_UNDEFINED
: {
106 case COFF::IMAGE_SYM_ABSOLUTE
:
108 case COFF::IMAGE_SYM_DEBUG
: {
109 // Used with .file symbol
113 // Non reserved regular section numbers
114 if (Expected
<StringRef
> SecNameOrErr
= Obj
.getSectionName(Sec
))
115 return *SecNameOrErr
;
121 Error
COFFLinkGraphBuilder::graphifySections() {
122 LLVM_DEBUG(dbgs() << " Creating graph sections...\n");
124 GraphBlocks
.resize(Obj
.getNumberOfSections() + 1);
125 // For each section...
126 for (COFFSectionIndex SecIndex
= 1;
127 SecIndex
<= static_cast<COFFSectionIndex
>(Obj
.getNumberOfSections());
129 Expected
<const object::coff_section
*> Sec
= Obj
.getSection(SecIndex
);
131 return Sec
.takeError();
133 StringRef SectionName
;
134 if (Expected
<StringRef
> SecNameOrErr
= Obj
.getSectionName(*Sec
))
135 SectionName
= *SecNameOrErr
;
137 // FIXME: Skip debug info sections
138 if (SectionName
== ".voltbl") {
141 << "Skipping section \"" << SectionName
<< "\"\n";
148 << "Creating section for \"" << SectionName
<< "\"\n";
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
;
160 // Look for existing sections first.
161 auto *GraphSec
= G
->findSectionByName(SectionName
);
163 GraphSec
= &G
->createSection(SectionName
, Prot
);
164 if ((*Sec
)->Characteristics
& COFF::IMAGE_SCN_LNK_REMOVE
)
165 GraphSec
->setMemLifetime(orc::MemLifetime::NoAlloc
);
167 if (GraphSec
->getMemProt() != Prot
)
168 return make_error
<JITLinkError
>("MemProt should match");
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);
177 ArrayRef
<uint8_t> Data
;
178 if (auto Err
= Obj
.getSectionContents(*Sec
, Data
))
181 auto CharData
= ArrayRef
<char>(
182 reinterpret_cast<const char *>(Data
.data()), Data
.size());
184 if (SectionName
== getDirectiveSectionName())
185 if (auto Err
= handleDirectiveSection(
186 StringRef(CharData
.data(), CharData
.size())))
189 B
= &G
->createContentBlock(
190 *GraphSec
, CharData
, orc::ExecutorAddr(getSectionAddress(Obj
, *Sec
)),
191 (*Sec
)->getAlignment(), 0);
194 setGraphBlock(SecIndex
, B
);
197 return Error::success();
200 Error
COFFLinkGraphBuilder::graphifySymbols() {
201 LLVM_DEBUG(dbgs() << " Creating graph symbols...\n");
203 SymbolSets
.resize(Obj
.getNumberOfSections() + 1);
204 PendingComdatExports
.resize(Obj
.getNumberOfSections() + 1);
205 GraphSymbols
.resize(Obj
.getNumberOfSymbols());
207 for (COFFSymbolIndex SymIndex
= 0;
208 SymIndex
< static_cast<COFFSymbolIndex
>(Obj
.getNumberOfSymbols());
210 Expected
<object::COFFSymbolRef
> Sym
= Obj
.getSymbol(SymIndex
);
212 return Sym
.takeError();
214 StringRef SymbolName
;
215 if (Expected
<StringRef
> SymNameOrErr
= Obj
.getSymbolName(*Sym
))
216 SymbolName
= *SymNameOrErr
;
218 COFFSectionIndex SectionIndex
= Sym
->getSectionNumber();
219 const object::coff_section
*Sec
= nullptr;
221 if (!COFF::isReservedSectionNumber(SectionIndex
)) {
222 auto SecOrErr
= Obj
.getSection(SectionIndex
);
224 return make_error
<JITLinkError
>(
225 "Invalid COFF section number:" + formatv("{0:d}: ", SectionIndex
) +
226 " (" + toString(SecOrErr
.takeError()) + ")");
230 // Create jitlink symbol
231 jitlink::Symbol
*GSym
= nullptr;
232 if (Sym
->isFileRecord())
234 dbgs() << " " << SymIndex
<< ": Skipping FileRecord symbol \""
235 << SymbolName
<< "\" in "
236 << getCOFFSectionName(SectionIndex
, Sec
, *Sym
)
237 << " (index: " << SectionIndex
<< ") \n";
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
});
248 Expected
<jitlink::Symbol
*> NewGSym
=
249 createDefinedSymbol(SymIndex
, SymbolName
, *Sym
, Sec
);
251 return NewGSym
.takeError();
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";
265 // Register the symbol
267 setGraphSymbol(SectionIndex
, SymIndex
, *GSym
);
268 SymIndex
+= Sym
->getNumberOfAuxSymbols();
271 if (auto Err
= flushWeakAliasRequests())
274 if (auto Err
= handleAlternateNames())
277 if (auto Err
= calculateImplicitSizeOfSymbols())
280 return Error::success();
283 Error
COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str
) {
284 auto Parsed
= DirectiveParser
.parse(Str
);
286 return Parsed
.takeError();
287 for (auto *Arg
: *Parsed
) {
288 StringRef S
= Arg
->getValue();
289 switch (Arg
->getOption().getID()) {
290 case COFF_OPT_alternatename
: {
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
;
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);
306 case COFF_OPT_export
:
310 dbgs() << "Unknown coff directive: " << Arg
->getSpelling() << "\n";
316 return Error::success();
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
);
326 return AliasSymbol
.takeError();
328 // FIXME: IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and
329 // IMAGE_WEAK_EXTERN_SEARCH_LIBRARY are handled in the same way.
331 WeakExternal
.Characteristics
== COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS
336 createAliasSymbol(WeakExternal
.SymbolName
, Linkage::Weak
, S
, *Target
);
338 return NewSymbol
.takeError();
339 setGraphSymbol(AliasSymbol
->getSectionNumber(), WeakExternal
.Alias
,
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";
349 return make_error
<JITLinkError
>("Weak symbol alias requested but actual "
350 "symbol not found for symbol " +
351 formatv("{0:d}", WeakExternal
.Alias
));
353 return Error::success();
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);
365 return Error::success();
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);
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";
382 return ExternalSymbols
[SymbolName
];
385 Expected
<Symbol
*> COFFLinkGraphBuilder::createAliasSymbol(StringRef SymbolName
,
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.");
393 return &G
->addDefinedSymbol(Target
.getBlock(), Target
.getOffset(), SymbolName
,
394 Target
.getSize(), L
, S
, Target
.isCallable(),
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());
409 auto &SymbolSet
= SymbolSets
[SecIndex
];
410 if (SymbolSet
.empty())
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
)
424 CandSize
= LastOffset
- Offset
;
427 if (Offset
+ Symbol
->getSize() > LastDifferentOffset
)
428 dbgs() << " Overlapping symbol range generated for the following "
431 << " " << *Symbol
<< "\n";
433 (void)LastDifferentOffset
;
434 if (LastOffset
!= Offset
)
435 LastDifferentOffset
= 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
450 dbgs() << " Empty implicit symbol size generated for the following "
453 << " " << *Symbol
<< "\n";
456 Symbol
->setSize(CandSize
);
459 return Error::success();
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
,
473 if (Symbol
.isAbsolute())
474 return &G
->addAbsoluteSymbol(SymbolName
,
475 orc::ExecutorAddr(Symbol
.getValue()), 0,
476 Linkage::Strong
, Scope::Local
, false);
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
));
483 Block
*B
= getGraphBlock(Symbol
.getSectionNumber());
486 dbgs() << " " << SymIndex
487 << ": Skipping graph symbol since section was not created for "
489 << SymbolName
<< "\" in section " << Symbol
.getSectionNumber()
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
;
504 if (!PendingComdatExports
[Symbol
.getSectionNumber()])
505 return make_error
<JITLinkError
>("No pending COMDAT export for symbol " +
506 formatv("{0:d}", SymIndex
));
508 return exportCOMDATSymbol(SymIndex
, SymbolName
, Symbol
);
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);
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);
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
);
536 return make_error
<JITLinkError
>("Unsupported storage class " +
537 formatv("{0:d}", Symbol
.getStorageClass()) +
538 " in symbol " + formatv("{0:d}", SymIndex
));
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
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.
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
: {
564 case COFF::IMAGE_COMDAT_SELECT_ANY
: {
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
575 case COFF::IMAGE_COMDAT_SELECT_LARGEST
: {
576 // FIXME: Support IMAGE_COMDAT_SELECT_LARGEST properly when LinkGraph is
577 // able to handle this.
579 dbgs() << " " << SymIndex
580 << ": Partially supported IMAGE_COMDAT_SELECT_LARGEST was used"
582 << Symbol
.getSectionNumber() << " (size: " << Definition
->Length
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.");
594 return make_error
<JITLinkError
>("Invalid comdat selection type: " +
595 formatv("{0:d}", Definition
->Selection
));
598 PendingComdatExports
[Symbol
.getSectionNumber()] = {SymIndex
, L
,
603 // Process the second symbol of COMDAT sequence.
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
,
618 dbgs() << " " << SymIndex
619 << ": Exporting COMDAT graph symbol for COFF symbol \"" << SymbolName
620 << "\" in section " << Symbol
.getSectionNumber() << "\n";
621 dbgs() << " " << *GSym
<< "\n";
623 setGraphSymbol(Symbol
.getSectionNumber(), PendingComdatExport
->SymbolIndex
,
625 DefinedSymbols
[SymbolName
] = GSym
;
626 PendingComdatExport
= std::nullopt
;
630 } // namespace jitlink