1 //===----- COFFLinkGraphBuilder.h - COFF LinkGraph builder ----*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
13 #ifndef LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
14 #define LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/Object/COFF.h"
20 #include "COFFDirectiveParser.h"
21 #include "EHFrameSupportImpl.h"
22 #include "JITLinkGeneric.h"
24 #define DEBUG_TYPE "jitlink"
31 class COFFLinkGraphBuilder
{
33 virtual ~COFFLinkGraphBuilder();
34 Expected
<std::unique_ptr
<LinkGraph
>> buildGraph();
37 using COFFSectionIndex
= int32_t;
38 using COFFSymbolIndex
= int32_t;
40 COFFLinkGraphBuilder(const object::COFFObjectFile
&Obj
, Triple TT
,
41 SubtargetFeatures Features
,
42 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName
);
44 LinkGraph
&getGraph() const { return *G
; }
46 const object::COFFObjectFile
&getObject() const { return Obj
; }
48 virtual Error
addRelocations() = 0;
50 Error
graphifySections();
51 Error
graphifySymbols();
53 void setGraphSymbol(COFFSectionIndex SecIndex
, COFFSymbolIndex SymIndex
,
55 assert(!GraphSymbols
[SymIndex
] && "Duplicate symbol at index");
56 GraphSymbols
[SymIndex
] = &Sym
;
57 if (!COFF::isReservedSectionNumber(SecIndex
))
58 SymbolSets
[SecIndex
].insert({Sym
.getOffset(), &Sym
});
61 Symbol
*getGraphSymbol(COFFSymbolIndex SymIndex
) const {
63 SymIndex
>= static_cast<COFFSymbolIndex
>(GraphSymbols
.size()))
65 return GraphSymbols
[SymIndex
];
68 void setGraphBlock(COFFSectionIndex SecIndex
, Block
*B
) {
69 assert(!GraphBlocks
[SecIndex
] && "Duplicate section at index");
70 assert(!COFF::isReservedSectionNumber(SecIndex
) && "Invalid section index");
71 GraphBlocks
[SecIndex
] = B
;
74 Block
*getGraphBlock(COFFSectionIndex SecIndex
) const {
76 SecIndex
>= static_cast<COFFSectionIndex
>(GraphSymbols
.size()))
78 return GraphBlocks
[SecIndex
];
81 object::COFFObjectFile::section_iterator_range
sections() const {
82 return Obj
.sections();
85 /// Traverse all matching relocation records in the given section. The handler
86 /// function Func should be callable with this signature:
87 /// Error(const object::RelocationRef&,
88 /// const object::SectionRef&, Section &)
90 template <typename RelocHandlerFunction
>
91 Error
forEachRelocation(const object::SectionRef
&RelSec
,
92 RelocHandlerFunction
&&Func
,
93 bool ProcessDebugSections
= false);
95 /// Traverse all matching relocation records in the given section. Convenience
96 /// wrapper to allow passing a member function for the handler.
98 template <typename ClassT
, typename RelocHandlerMethod
>
99 Error
forEachRelocation(const object::SectionRef
&RelSec
, ClassT
*Instance
,
100 RelocHandlerMethod
&&Method
,
101 bool ProcessDebugSections
= false) {
102 return forEachRelocation(
104 [Instance
, Method
](const auto &Rel
, const auto &Target
, auto &GS
) {
105 return (Instance
->*Method
)(Rel
, Target
, GS
);
107 ProcessDebugSections
);
111 // Pending comdat symbol export that is initiated by the first symbol of
113 struct ComdatExportRequest
{
114 COFFSymbolIndex SymbolIndex
;
115 jitlink::Linkage Linkage
;
116 orc::ExecutorAddrDiff Size
;
118 std::vector
<std::optional
<ComdatExportRequest
>> PendingComdatExports
;
120 // This represents a pending request to create a weak external symbol with a
122 struct WeakExternalRequest
{
123 COFFSymbolIndex Alias
;
124 COFFSymbolIndex Target
;
125 uint32_t Characteristics
;
126 StringRef SymbolName
;
128 std::vector
<WeakExternalRequest
> WeakExternalRequests
;
130 // Per COFF section jitlink symbol set sorted by offset.
131 // Used for calculating implicit size of defined symbols.
132 using SymbolSet
= std::set
<std::pair
<orc::ExecutorAddrDiff
, Symbol
*>>;
133 std::vector
<SymbolSet
> SymbolSets
;
135 Section
&getCommonSection();
137 Symbol
*createExternalSymbol(COFFSymbolIndex SymIndex
, StringRef SymbolName
,
138 object::COFFSymbolRef Symbol
,
139 const object::coff_section
*Section
);
140 Expected
<Symbol
*> createAliasSymbol(StringRef SymbolName
, Linkage L
, Scope S
,
142 Expected
<Symbol
*> createDefinedSymbol(COFFSymbolIndex SymIndex
,
143 StringRef SymbolName
,
144 object::COFFSymbolRef Symbol
,
145 const object::coff_section
*Section
);
146 Expected
<Symbol
*> createCOMDATExportRequest(
147 COFFSymbolIndex SymIndex
, object::COFFSymbolRef Symbol
,
148 const object::coff_aux_section_definition
*Definition
);
149 Expected
<Symbol
*> exportCOMDATSymbol(COFFSymbolIndex SymIndex
,
150 StringRef SymbolName
,
151 object::COFFSymbolRef Symbol
);
153 Error
handleDirectiveSection(StringRef Str
);
154 Error
flushWeakAliasRequests();
155 Error
handleAlternateNames();
156 Error
calculateImplicitSizeOfSymbols();
158 static uint64_t getSectionAddress(const object::COFFObjectFile
&Obj
,
159 const object::coff_section
*Section
);
160 static uint64_t getSectionSize(const object::COFFObjectFile
&Obj
,
161 const object::coff_section
*Section
);
162 static bool isComdatSection(const object::coff_section
*Section
);
163 static unsigned getPointerSize(const object::COFFObjectFile
&Obj
);
164 static llvm::endianness
getEndianness(const object::COFFObjectFile
&Obj
);
165 static StringRef
getDLLImportStubPrefix() { return "__imp_"; }
166 static StringRef
getDirectiveSectionName() { return ".drectve"; }
167 StringRef
getCOFFSectionName(COFFSectionIndex SectionIndex
,
168 const object::coff_section
*Sec
,
169 object::COFFSymbolRef Sym
);
171 const object::COFFObjectFile
&Obj
;
172 std::unique_ptr
<LinkGraph
> G
;
173 COFFDirectiveParser DirectiveParser
;
175 Section
*CommonSection
= nullptr;
176 std::vector
<Block
*> GraphBlocks
;
177 std::vector
<Symbol
*> GraphSymbols
;
179 DenseMap
<StringRef
, StringRef
> AlternateNames
;
180 DenseMap
<StringRef
, Symbol
*> ExternalSymbols
;
181 DenseMap
<StringRef
, Symbol
*> DefinedSymbols
;
184 template <typename RelocHandlerFunction
>
185 Error
COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef
&RelSec
,
186 RelocHandlerFunction
&&Func
,
187 bool ProcessDebugSections
) {
189 auto COFFRelSect
= Obj
.getCOFFSection(RelSec
);
191 // Target sections have names in valid COFF object files.
192 Expected
<StringRef
> Name
= Obj
.getSectionName(COFFRelSect
);
194 return Name
.takeError();
196 // Skip the unhandled metadata sections.
197 if (*Name
== ".voltbl")
198 return Error::success();
199 LLVM_DEBUG(dbgs() << " " << *Name
<< ":\n");
201 // Lookup the link-graph node corresponding to the target section name.
202 auto *BlockToFix
= getGraphBlock(RelSec
.getIndex() + 1);
204 return make_error
<StringError
>(
205 "Referencing a section that wasn't added to the graph: " + *Name
,
206 inconvertibleErrorCode());
208 // Let the callee process relocation entries one by one.
209 for (const auto &R
: RelSec
.relocations())
210 if (Error Err
= Func(R
, RelSec
, *BlockToFix
))
213 LLVM_DEBUG(dbgs() << "\n");
214 return Error::success();
217 } // end namespace jitlink
218 } // end namespace llvm
220 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H