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/ADT/StringMap.h"
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/Object/COFF.h"
21 #include "COFFDirectiveParser.h"
22 #include "EHFrameSupportImpl.h"
23 #include "JITLinkGeneric.h"
25 #define DEBUG_TYPE "jitlink"
32 class COFFLinkGraphBuilder
{
34 virtual ~COFFLinkGraphBuilder();
35 Expected
<std::unique_ptr
<LinkGraph
>> buildGraph();
38 using COFFSectionIndex
= int32_t;
39 using COFFSymbolIndex
= int32_t;
41 COFFLinkGraphBuilder(const object::COFFObjectFile
&Obj
, 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
, StringRef SymbolName
,
139 object::COFFSymbolRef Symbol
,
140 const object::coff_section
*Section
);
141 Expected
<Symbol
*> createAliasSymbol(StringRef SymbolName
, Linkage L
, Scope S
,
143 Expected
<Symbol
*> createDefinedSymbol(COFFSymbolIndex SymIndex
,
144 StringRef SymbolName
,
145 object::COFFSymbolRef Symbol
,
146 const object::coff_section
*Section
);
147 Expected
<Symbol
*> createCOMDATExportRequest(
148 COFFSymbolIndex SymIndex
, object::COFFSymbolRef Symbol
,
149 const object::coff_aux_section_definition
*Definition
);
150 Expected
<Symbol
*> exportCOMDATSymbol(COFFSymbolIndex SymIndex
,
151 StringRef SymbolName
,
152 object::COFFSymbolRef Symbol
);
154 Error
handleDirectiveSection(StringRef Str
);
155 Error
flushWeakAliasRequests();
156 Error
handleAlternateNames();
157 Error
calculateImplicitSizeOfSymbols();
159 static uint64_t getSectionAddress(const object::COFFObjectFile
&Obj
,
160 const object::coff_section
*Section
);
161 static uint64_t getSectionSize(const object::COFFObjectFile
&Obj
,
162 const object::coff_section
*Section
);
163 static bool isComdatSection(const object::coff_section
*Section
);
164 static unsigned getPointerSize(const object::COFFObjectFile
&Obj
);
165 static support::endianness
getEndianness(const object::COFFObjectFile
&Obj
);
166 static StringRef
getDLLImportStubPrefix() { return "__imp_"; }
167 static StringRef
getDirectiveSectionName() { return ".drectve"; }
168 StringRef
getCOFFSectionName(COFFSectionIndex SectionIndex
,
169 const object::coff_section
*Sec
,
170 object::COFFSymbolRef Sym
);
172 const object::COFFObjectFile
&Obj
;
173 std::unique_ptr
<LinkGraph
> G
;
174 COFFDirectiveParser DirectiveParser
;
176 Section
*CommonSection
= nullptr;
177 std::vector
<Block
*> GraphBlocks
;
178 std::vector
<Symbol
*> GraphSymbols
;
180 DenseMap
<StringRef
, StringRef
> AlternateNames
;
181 DenseMap
<StringRef
, Symbol
*> ExternalSymbols
;
182 DenseMap
<StringRef
, Symbol
*> DefinedSymbols
;
185 template <typename RelocHandlerFunction
>
186 Error
COFFLinkGraphBuilder::forEachRelocation(const object::SectionRef
&RelSec
,
187 RelocHandlerFunction
&&Func
,
188 bool ProcessDebugSections
) {
190 auto COFFRelSect
= Obj
.getCOFFSection(RelSec
);
192 // Target sections have names in valid COFF object files.
193 Expected
<StringRef
> Name
= Obj
.getSectionName(COFFRelSect
);
195 return Name
.takeError();
197 // Skip the unhandled metadata sections.
198 if (*Name
== ".voltbl")
199 return Error::success();
200 LLVM_DEBUG(dbgs() << " " << *Name
<< ":\n");
202 // Lookup the link-graph node corresponding to the target section name.
203 auto *BlockToFix
= getGraphBlock(RelSec
.getIndex() + 1);
205 return make_error
<StringError
>(
206 "Referencing a section that wasn't added to the graph: " + *Name
,
207 inconvertibleErrorCode());
209 // Let the callee process relocation entries one by one.
210 for (const auto &R
: RelSec
.relocations())
211 if (Error Err
= Func(R
, RelSec
, *BlockToFix
))
214 LLVM_DEBUG(dbgs() << "\n");
215 return Error::success();
218 } // end namespace jitlink
219 } // end namespace llvm
221 #endif // LIB_EXECUTIONENGINE_JITLINK_COFFLINKGRAPHBUILDER_H