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/ADT/DenseMap.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
19 #include "llvm/Object/MachO.h"
21 #include "EHFrameSupportImpl.h"
22 #include "JITLinkGeneric.h"
29 class MachOLinkGraphBuilder
{
31 virtual ~MachOLinkGraphBuilder();
32 Expected
<std::unique_ptr
<LinkGraph
>> buildGraph();
36 struct NormalizedSymbol
{
37 friend class MachOLinkGraphBuilder
;
40 NormalizedSymbol(Optional
<StringRef
> Name
, uint64_t Value
, uint8_t Type
,
41 uint8_t Sect
, uint16_t Desc
, Linkage L
, Scope S
)
42 : Name(Name
), Value(Value
), Type(Type
), Sect(Sect
), Desc(Desc
), L(L
),
44 assert((!Name
|| !Name
->empty()) && "Name must be none or non-empty");
48 NormalizedSymbol(const NormalizedSymbol
&) = delete;
49 NormalizedSymbol
&operator=(const NormalizedSymbol
&) = delete;
50 NormalizedSymbol(NormalizedSymbol
&&) = delete;
51 NormalizedSymbol
&operator=(NormalizedSymbol
&&) = delete;
53 Optional
<StringRef
> Name
;
58 Linkage L
= Linkage::Strong
;
59 Scope S
= Scope::Default
;
60 Symbol
*GraphSymbol
= nullptr;
63 // Normalized section representation. Section and segment names are guaranteed
64 // to be null-terminated, hence the extra bytes on SegName and SectName.
65 class NormalizedSection
{
66 friend class MachOLinkGraphBuilder
;
69 NormalizedSection() = default;
76 uint64_t Alignment
= 0;
78 const char *Data
= nullptr;
79 Section
*GraphSection
= nullptr;
82 using SectionParserFunction
= std::function
<Error(NormalizedSection
&S
)>;
84 MachOLinkGraphBuilder(const object::MachOObjectFile
&Obj
, Triple TT
,
85 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName
);
87 LinkGraph
&getGraph() const { return *G
; }
89 const object::MachOObjectFile
&getObject() const { return Obj
; }
91 void addCustomSectionParser(StringRef SectionName
,
92 SectionParserFunction Parse
);
94 virtual Error
addRelocations() = 0;
97 template <typename
... ArgTs
>
98 NormalizedSymbol
&createNormalizedSymbol(ArgTs
&&... Args
) {
99 NormalizedSymbol
*Sym
= reinterpret_cast<NormalizedSymbol
*>(
100 Allocator
.Allocate
<NormalizedSymbol
>());
101 new (Sym
) NormalizedSymbol(std::forward
<ArgTs
>(Args
)...);
105 /// Index is zero-based (MachO section indexes are usually one-based) and
106 /// assumed to be in-range. Client is responsible for checking.
107 NormalizedSection
&getSectionByIndex(unsigned Index
) {
108 auto I
= IndexToSection
.find(Index
);
109 assert(I
!= IndexToSection
.end() && "No section recorded at index");
113 /// Try to get the section at the given index. Will return an error if the
114 /// given index is out of range, or if no section has been added for the given
116 Expected
<NormalizedSection
&> findSectionByIndex(unsigned Index
) {
117 auto I
= IndexToSection
.find(Index
);
118 if (I
== IndexToSection
.end())
119 return make_error
<JITLinkError
>("No section recorded for index " +
120 formatv("{0:d}", Index
));
124 /// Try to get the symbol at the given index. Will return an error if the
125 /// given index is out of range, or if no symbol has been added for the given
127 Expected
<NormalizedSymbol
&> findSymbolByIndex(uint64_t Index
) {
128 if (Index
>= IndexToSymbol
.size())
129 return make_error
<JITLinkError
>("Symbol index out of range");
130 auto *Sym
= IndexToSymbol
[Index
];
132 return make_error
<JITLinkError
>("No symbol at index " +
133 formatv("{0:d}", Index
));
137 /// Returns the symbol with the highest address not greater than the search
138 /// address, or null if no such symbol exists.
139 Symbol
*getSymbolByAddress(JITTargetAddress Address
) {
140 auto I
= AddrToCanonicalSymbol
.upper_bound(Address
);
141 if (I
== AddrToCanonicalSymbol
.begin())
143 return std::prev(I
)->second
;
146 /// Returns the symbol with the highest address not greater than the search
147 /// address, or an error if no such symbol exists.
148 Expected
<Symbol
&> findSymbolByAddress(JITTargetAddress Address
) {
149 auto *Sym
= getSymbolByAddress(Address
);
151 if (Address
< Sym
->getAddress() + Sym
->getSize())
153 return make_error
<JITLinkError
>("No symbol covering address " +
154 formatv("{0:x16}", Address
));
157 static Linkage
getLinkage(uint16_t Desc
);
158 static Scope
getScope(StringRef Name
, uint8_t Type
);
159 static bool isAltEntry(const NormalizedSymbol
&NSym
);
161 static bool isDebugSection(const NormalizedSection
&NSec
);
162 static bool isZeroFillSection(const NormalizedSection
&NSec
);
164 MachO::relocation_info
165 getRelocationInfo(const object::relocation_iterator RelItr
) {
166 MachO::any_relocation_info ARI
=
167 getObject().getRelocation(RelItr
->getRawDataRefImpl());
168 MachO::relocation_info RI
;
169 RI
.r_address
= ARI
.r_word0
;
170 RI
.r_symbolnum
= ARI
.r_word1
& 0xffffff;
171 RI
.r_pcrel
= (ARI
.r_word1
>> 24) & 1;
172 RI
.r_length
= (ARI
.r_word1
>> 25) & 3;
173 RI
.r_extern
= (ARI
.r_word1
>> 27) & 1;
174 RI
.r_type
= (ARI
.r_word1
>> 28);
179 static unsigned getPointerSize(const object::MachOObjectFile
&Obj
);
180 static support::endianness
getEndianness(const object::MachOObjectFile
&Obj
);
182 void setCanonicalSymbol(Symbol
&Sym
) {
183 auto *&CanonicalSymEntry
= AddrToCanonicalSymbol
[Sym
.getAddress()];
184 // There should be no symbol at this address, or, if there is,
185 // it should be a zero-sized symbol from an empty section (which
186 // we can safely override).
187 assert((!CanonicalSymEntry
|| CanonicalSymEntry
->getSize() == 0) &&
188 "Duplicate canonical symbol at address");
189 CanonicalSymEntry
= &Sym
;
192 Section
&getCommonSection();
193 void addSectionStartSymAndBlock(Section
&GraphSec
, uint64_t Address
,
194 const char *Data
, uint64_t Size
,
195 uint32_t Alignment
, bool IsLive
);
197 Error
createNormalizedSections();
198 Error
createNormalizedSymbols();
200 /// Create graph blocks and symbols for externals, absolutes, commons and
201 /// all defined symbols in sections without custom parsers.
202 Error
graphifyRegularSymbols();
204 /// Create and return a graph symbol for the given normalized symbol.
206 /// NSym's GraphSymbol member will be updated to point at the newly created
208 Symbol
&createStandardGraphSymbol(NormalizedSymbol
&Sym
, Block
&B
,
209 size_t Size
, bool IsText
,
210 bool IsNoDeadStrip
, bool IsCanonical
);
212 /// Create graph blocks and symbols for all sections.
213 Error
graphifySectionsWithCustomParsers();
215 /// Graphify cstring section.
216 Error
graphifyCStringSection(NormalizedSection
&NSec
,
217 std::vector
<NormalizedSymbol
*> NSyms
);
219 // Put the BumpPtrAllocator first so that we don't free any of the underlying
220 // memory until the Symbol/Addressable destructors have been run.
221 BumpPtrAllocator Allocator
;
223 const object::MachOObjectFile
&Obj
;
224 std::unique_ptr
<LinkGraph
> G
;
226 DenseMap
<unsigned, NormalizedSection
> IndexToSection
;
227 Section
*CommonSection
= nullptr;
229 DenseMap
<uint32_t, NormalizedSymbol
*> IndexToSymbol
;
230 std::map
<JITTargetAddress
, Symbol
*> AddrToCanonicalSymbol
;
231 StringMap
<SectionParserFunction
> CustomSectionParserFunctions
;
234 } // end namespace jitlink
235 } // end namespace llvm
237 #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H