1 //===----- MachOLinkGraphBuilder.h - MachO 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 MachO LinkGraph building code.
11 //===----------------------------------------------------------------------===//
13 #ifndef LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
14 #define LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "EHFrameSupportImpl.h"
19 #include "JITLinkGeneric.h"
20 #include "llvm/Object/MachO.h"
27 class MachOLinkGraphBuilder
{
29 virtual ~MachOLinkGraphBuilder();
30 Expected
<std::unique_ptr
<LinkGraph
>> buildGraph();
33 class MachOEHFrameBinaryParser
: public EHFrameBinaryParser
{
35 MachOEHFrameBinaryParser(MachOLinkGraphBuilder
&Builder
,
36 JITTargetAddress EHFrameAddress
,
37 StringRef EHFrameContent
, Section
&EHFrameSection
,
38 uint64_t CIEAlignment
, uint64_t FDEAlignment
,
39 Edge::Kind FDEToCIERelocKind
,
40 Edge::Kind FDEToTargetRelocKind
)
41 : EHFrameBinaryParser(EHFrameAddress
, EHFrameContent
,
42 Builder
.getGraph().getPointerSize(),
43 Builder
.getGraph().getEndianness()),
44 Builder(Builder
), EHFrameSection(EHFrameSection
),
45 CIEAlignment(CIEAlignment
), FDEAlignment(FDEAlignment
),
46 FDEToCIERelocKind(FDEToCIERelocKind
),
47 FDEToTargetRelocKind(FDEToTargetRelocKind
) {}
49 Symbol
*getSymbolAtAddress(JITTargetAddress Address
) override
{
50 if (auto *Sym
= Builder
.getSymbolByAddress(Address
))
51 if (Sym
->getAddress() == Address
)
56 Symbol
&createCIERecord(JITTargetAddress RecordAddr
,
57 StringRef RecordContent
) override
{
58 auto &G
= Builder
.getGraph();
59 auto &B
= G
.createContentBlock(EHFrameSection
, RecordContent
, RecordAddr
,
62 G
.addAnonymousSymbol(B
, 0, RecordContent
.size(), false, false);
63 Builder
.setCanonicalSymbol(CIESymbol
);
67 Expected
<Symbol
&> createFDERecord(JITTargetAddress RecordAddr
,
68 StringRef RecordContent
, Symbol
&CIE
,
69 size_t CIEOffset
, Symbol
&Func
,
70 size_t FuncOffset
, Symbol
*LSDA
,
71 size_t LSDAOffset
) override
{
72 auto &G
= Builder
.getGraph();
73 auto &B
= G
.createContentBlock(EHFrameSection
, RecordContent
, RecordAddr
,
76 // Add edges to CIE, Func, and (conditionally) LSDA.
77 B
.addEdge(FDEToCIERelocKind
, CIEOffset
, CIE
, 0);
78 B
.addEdge(FDEToTargetRelocKind
, FuncOffset
, Func
, 0);
81 B
.addEdge(FDEToTargetRelocKind
, LSDAOffset
, *LSDA
, 0);
84 G
.addAnonymousSymbol(B
, 0, RecordContent
.size(), false, false);
86 // Add a keep-alive relocation from the function to the FDE to ensure it
87 // is not dead stripped.
88 Func
.getBlock().addEdge(Edge::KeepAlive
, 0, FDESymbol
, 0);
94 MachOLinkGraphBuilder
&Builder
;
95 Section
&EHFrameSection
;
96 uint64_t CIEAlignment
;
97 uint64_t FDEAlignment
;
98 Edge::Kind FDEToCIERelocKind
;
99 Edge::Kind FDEToTargetRelocKind
;
102 struct NormalizedSymbol
{
103 friend class MachOLinkGraphBuilder
;
106 NormalizedSymbol(Optional
<StringRef
> Name
, uint64_t Value
, uint8_t Type
,
107 uint8_t Sect
, uint16_t Desc
, Linkage L
, Scope S
)
108 : Name(Name
), Value(Value
), Type(Type
), Sect(Sect
), Desc(Desc
), L(L
),
110 assert((!Name
|| !Name
->empty()) && "Name must be none or non-empty");
114 NormalizedSymbol(const NormalizedSymbol
&) = delete;
115 NormalizedSymbol
&operator=(const NormalizedSymbol
&) = delete;
116 NormalizedSymbol(NormalizedSymbol
&&) = delete;
117 NormalizedSymbol
&operator=(NormalizedSymbol
&&) = delete;
119 Optional
<StringRef
> Name
;
124 Linkage L
= Linkage::Strong
;
125 Scope S
= Scope::Default
;
126 Symbol
*GraphSymbol
= nullptr;
129 class NormalizedSection
{
130 friend class MachOLinkGraphBuilder
;
133 NormalizedSection() = default;
136 Section
*GraphSection
= nullptr;
137 uint64_t Address
= 0;
139 uint64_t Alignment
= 0;
141 const char *Data
= nullptr;
144 using SectionParserFunction
= std::function
<Error(NormalizedSection
&S
)>;
146 MachOLinkGraphBuilder(const object::MachOObjectFile
&Obj
);
148 LinkGraph
&getGraph() const { return *G
; }
150 const object::MachOObjectFile
&getObject() const { return Obj
; }
152 void addCustomSectionParser(StringRef SectionName
,
153 SectionParserFunction Parse
);
155 virtual Error
addRelocations() = 0;
158 template <typename
... ArgTs
>
159 NormalizedSymbol
&createNormalizedSymbol(ArgTs
&&... Args
) {
160 NormalizedSymbol
*Sym
= reinterpret_cast<NormalizedSymbol
*>(
161 Allocator
.Allocate
<NormalizedSymbol
>());
162 new (Sym
) NormalizedSymbol(std::forward
<ArgTs
>(Args
)...);
166 /// Index is zero-based (MachO section indexes are usually one-based) and
167 /// assumed to be in-range. Client is responsible for checking.
168 NormalizedSection
&getSectionByIndex(unsigned Index
) {
169 auto I
= IndexToSection
.find(Index
);
170 assert(I
!= IndexToSection
.end() && "No section recorded at index");
174 /// Try to get the section at the given index. Will return an error if the
175 /// given index is out of range, or if no section has been added for the given
177 Expected
<NormalizedSection
&> findSectionByIndex(unsigned Index
) {
178 auto I
= IndexToSection
.find(Index
);
179 if (I
== IndexToSection
.end())
180 return make_error
<JITLinkError
>("No section recorded for index " +
181 formatv("{0:u}", Index
));
185 /// Try to get the symbol at the given index. Will return an error if the
186 /// given index is out of range, or if no symbol has been added for the given
188 Expected
<NormalizedSymbol
&> findSymbolByIndex(uint64_t Index
) {
189 if (Index
>= IndexToSymbol
.size())
190 return make_error
<JITLinkError
>("Symbol index out of range");
191 auto *Sym
= IndexToSymbol
[Index
];
193 return make_error
<JITLinkError
>("No symbol at index " +
194 formatv("{0:u}", Index
));
198 /// Returns the symbol with the highest address not greater than the search
199 /// address, or null if no such symbol exists.
200 Symbol
*getSymbolByAddress(JITTargetAddress Address
) {
201 auto I
= AddrToCanonicalSymbol
.upper_bound(Address
);
202 if (I
== AddrToCanonicalSymbol
.begin())
204 return std::prev(I
)->second
;
207 /// Returns the symbol with the highest address not greater than the search
208 /// address, or an error if no such symbol exists.
209 Expected
<Symbol
&> findSymbolByAddress(JITTargetAddress Address
) {
210 auto *Sym
= getSymbolByAddress(Address
);
212 if (Address
< Sym
->getAddress() + Sym
->getSize())
214 return make_error
<JITLinkError
>("No symbol covering address " +
215 formatv("{0:x16}", Address
));
218 static Linkage
getLinkage(uint16_t Desc
);
219 static Scope
getScope(StringRef Name
, uint8_t Type
);
220 static bool isAltEntry(const NormalizedSymbol
&NSym
);
223 static unsigned getPointerSize(const object::MachOObjectFile
&Obj
);
224 static support::endianness
getEndianness(const object::MachOObjectFile
&Obj
);
226 void setCanonicalSymbol(Symbol
&Sym
) {
227 auto *&CanonicalSymEntry
= AddrToCanonicalSymbol
[Sym
.getAddress()];
228 // There should be no symbol at this address, or, if there is,
229 // it should be a zero-sized symbol from an empty section (which
230 // we can safely override).
231 assert((!CanonicalSymEntry
|| CanonicalSymEntry
->getSize() == 0) &&
232 "Duplicate canonical symbol at address");
233 CanonicalSymEntry
= &Sym
;
236 Section
&getCommonSection();
237 void addSectionStartSymAndBlock(Section
&GraphSec
, uint64_t Address
,
238 const char *Data
, uint64_t Size
,
239 uint32_t Alignment
, bool IsLive
);
241 Error
createNormalizedSections();
242 Error
createNormalizedSymbols();
244 /// Create graph blocks and symbols for externals, absolutes, commons and
245 /// all defined symbols in sections without custom parsers.
246 Error
graphifyRegularSymbols();
248 /// Create graph blocks and symbols for all sections.
249 Error
graphifySectionsWithCustomParsers();
251 // Put the BumpPtrAllocator first so that we don't free any of the underlying
252 // memory until the Symbol/Addressable destructors have been run.
253 BumpPtrAllocator Allocator
;
255 const object::MachOObjectFile
&Obj
;
256 std::unique_ptr
<LinkGraph
> G
;
258 DenseMap
<unsigned, NormalizedSection
> IndexToSection
;
259 Section
*CommonSection
= nullptr;
261 DenseMap
<uint32_t, NormalizedSymbol
*> IndexToSymbol
;
262 std::map
<JITTargetAddress
, Symbol
*> AddrToCanonicalSymbol
;
263 StringMap
<SectionParserFunction
> CustomSectionParserFunctions
;
266 } // end namespace jitlink
267 } // end namespace llvm
269 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H