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
,
41 std::shared_ptr
<orc::SymbolStringPool
> SSP
, Triple TT
,
42 SubtargetFeatures Features
,
43 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName
);
45 LinkGraph
&getGraph() const { return *G
; }
47 const object::COFFObjectFile
&getObject() const { return Obj
; }
49 virtual Error
addRelocations() = 0;
51 Error
graphifySections();
52 Error
graphifySymbols();
54 void setGraphSymbol(COFFSectionIndex SecIndex
, COFFSymbolIndex SymIndex
,
56 assert(!GraphSymbols
[SymIndex
] && "Duplicate symbol at index");
57 GraphSymbols
[SymIndex
] = &Sym
;
58 if (!COFF::isReservedSectionNumber(SecIndex
))
59 SymbolSets
[SecIndex
].insert({Sym
.getOffset(), &Sym
});
62 Symbol
*getGraphSymbol(COFFSymbolIndex SymIndex
) const {
64 SymIndex
>= static_cast<COFFSymbolIndex
>(GraphSymbols
.size()))
66 return GraphSymbols
[SymIndex
];
69 void setGraphBlock(COFFSectionIndex SecIndex
, Block
*B
) {
70 assert(!GraphBlocks
[SecIndex
] && "Duplicate section at index");
71 assert(!COFF::isReservedSectionNumber(SecIndex
) && "Invalid section index");
72 GraphBlocks
[SecIndex
] = B
;
75 Block
*getGraphBlock(COFFSectionIndex SecIndex
) const {
77 SecIndex
>= static_cast<COFFSectionIndex
>(GraphSymbols
.size()))
79 return GraphBlocks
[SecIndex
];
82 object::COFFObjectFile::section_iterator_range
sections() const {
83 return Obj
.sections();
86 /// Traverse all matching relocation records in the given section. The handler
87 /// function Func should be callable with this signature:
88 /// Error(const object::RelocationRef&,
89 /// const object::SectionRef&, Section &)
91 template <typename RelocHandlerFunction
>
92 Error
forEachRelocation(const object::SectionRef
&RelSec
,
93 RelocHandlerFunction
&&Func
,
94 bool ProcessDebugSections
= false);
96 /// Traverse all matching relocation records in the given section. Convenience
97 /// wrapper to allow passing a member function for the handler.
99 template <typename ClassT
, typename RelocHandlerMethod
>
100 Error
forEachRelocation(const object::SectionRef
&RelSec
, ClassT
*Instance
,
101 RelocHandlerMethod
&&Method
,
102 bool ProcessDebugSections
= false) {
103 return forEachRelocation(
105 [Instance
, Method
](const auto &Rel
, const auto &Target
, auto &GS
) {
106 return (Instance
->*Method
)(Rel
, Target
, GS
);
108 ProcessDebugSections
);
112 // Pending comdat symbol export that is initiated by the first symbol of
114 struct ComdatExportRequest
{
115 COFFSymbolIndex SymbolIndex
;
116 jitlink::Linkage Linkage
;
117 orc::ExecutorAddrDiff Size
;
119 std::vector
<std::optional
<ComdatExportRequest
>> PendingComdatExports
;
121 // This represents a pending request to create a weak external symbol with a
123 struct WeakExternalRequest
{
124 COFFSymbolIndex Alias
;
125 COFFSymbolIndex Target
;
126 uint32_t Characteristics
;
127 StringRef SymbolName
;
129 std::vector
<WeakExternalRequest
> WeakExternalRequests
;
131 // Per COFF section jitlink symbol set sorted by offset.
132 // Used for calculating implicit size of defined symbols.
133 using SymbolSet
= std::set
<std::pair
<orc::ExecutorAddrDiff
, Symbol
*>>;
134 std::vector
<SymbolSet
> SymbolSets
;
136 Section
&getCommonSection();
138 Symbol
*createExternalSymbol(COFFSymbolIndex SymIndex
,
139 orc::SymbolStringPtr SymbolName
,
140 object::COFFSymbolRef Symbol
,
141 const object::coff_section
*Section
);
142 Expected
<Symbol
*> createAliasSymbol(orc::SymbolStringPtr SymbolName
,
143 Linkage L
, Scope S
, Symbol
&Target
);
144 Expected
<Symbol
*> createDefinedSymbol(COFFSymbolIndex SymIndex
,
145 orc::SymbolStringPtr SymbolName
,
146 object::COFFSymbolRef Symbol
,
147 const object::coff_section
*Section
);
148 Expected
<Symbol
*> createCOMDATExportRequest(
149 COFFSymbolIndex SymIndex
, object::COFFSymbolRef Symbol
,
150 const object::coff_aux_section_definition
*Definition
);
151 Expected
<Symbol
*> exportCOMDATSymbol(COFFSymbolIndex SymIndex
,
152 orc::SymbolStringPtr SymbolName
,
153 object::COFFSymbolRef Symbol
);
155 Error
handleDirectiveSection(StringRef Str
);
156 Error
flushWeakAliasRequests();
157 Error
handleAlternateNames();
158 Error
calculateImplicitSizeOfSymbols();
160 static uint64_t getSectionAddress(const object::COFFObjectFile
&Obj
,
161 const object::coff_section
*Section
);
162 static uint64_t getSectionSize(const object::COFFObjectFile
&Obj
,
163 const object::coff_section
*Section
);
164 static bool isComdatSection(const object::coff_section
*Section
);
165 static unsigned getPointerSize(const object::COFFObjectFile
&Obj
);
166 static llvm::endianness
getEndianness(const object::COFFObjectFile
&Obj
);
167 static StringRef
getDLLImportStubPrefix() { return "__imp_"; }
168 static StringRef
getDirectiveSectionName() { return ".drectve"; }
169 StringRef
getCOFFSectionName(COFFSectionIndex SectionIndex
,
170 const object::coff_section
*Sec
,
171 object::COFFSymbolRef Sym
);
173 const object::COFFObjectFile
&Obj
;
174 std::unique_ptr
<LinkGraph
> G
;
175 COFFDirectiveParser DirectiveParser
;
177 Section
*CommonSection
= nullptr;
178 std::vector
<Block
*> GraphBlocks
;
179 std::vector
<Symbol
*> GraphSymbols
;
181 DenseMap
<orc::SymbolStringPtr
, orc::SymbolStringPtr
> AlternateNames
;
182 DenseMap
<orc::SymbolStringPtr
, Symbol
*> ExternalSymbols
;
183 DenseMap
<orc::SymbolStringPtr
, Symbol
*> DefinedSymbols
;
186 template <typename RelocHandlerFunction
>
187 Error
COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef
&RelSec
,
188 RelocHandlerFunction
&&Func
,
189 bool ProcessDebugSections
) {
191 auto COFFRelSect
= Obj
.getCOFFSection(RelSec
);
193 // Target sections have names in valid COFF object files.
194 Expected
<StringRef
> Name
= Obj
.getSectionName(COFFRelSect
);
196 return Name
.takeError();
198 // Skip the unhandled metadata sections.
199 if (*Name
== ".voltbl")
200 return Error::success();
201 LLVM_DEBUG(dbgs() << " " << *Name
<< ":\n");
203 // Lookup the link-graph node corresponding to the target section name.
204 auto *BlockToFix
= getGraphBlock(RelSec
.getIndex() + 1);
206 return make_error
<StringError
>(
207 "Referencing a section that wasn't added to the graph: " + *Name
,
208 inconvertibleErrorCode());
210 // Let the callee process relocation entries one by one.
211 for (const auto &R
: RelSec
.relocations())
212 if (Error Err
= Func(R
, RelSec
, *BlockToFix
))
215 LLVM_DEBUG(dbgs() << "\n");
216 return Error::success();
219 } // end namespace jitlink
220 } // end namespace llvm
222 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H