1 | //===----- MachOLinkGraphBuilder.h - MachO LinkGraph builder ----*- C++ -*-===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Generic MachO LinkGraph building code. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H |
14 | #define LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H |
15 | |
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" |
20 | |
21 | #include "EHFrameSupportImpl.h" |
22 | #include "JITLinkGeneric.h" |
23 | |
24 | #include <list> |
25 | |
26 | namespace llvm { |
27 | namespace jitlink { |
28 | |
29 | class MachOLinkGraphBuilder { |
30 | public: |
31 | virtual ~MachOLinkGraphBuilder(); |
32 | Expected<std::unique_ptr<LinkGraph>> buildGraph(); |
33 | |
34 | protected: |
35 | |
36 | struct NormalizedSymbol { |
37 | friend class MachOLinkGraphBuilder; |
38 | |
39 | private: |
40 | NormalizedSymbol(std::optional<StringRef> Name, uint64_t Value, |
41 | uint8_t Type, uint8_t Sect, uint16_t Desc, Linkage L, |
42 | Scope S) |
43 | : Name(Name), Value(Value), Type(Type), Sect(Sect), Desc(Desc), L(L), |
44 | S(S) { |
45 | assert((!Name || !Name->empty()) && "Name must be none or non-empty" ); |
46 | } |
47 | |
48 | public: |
49 | NormalizedSymbol(const NormalizedSymbol &) = delete; |
50 | NormalizedSymbol &operator=(const NormalizedSymbol &) = delete; |
51 | NormalizedSymbol(NormalizedSymbol &&) = delete; |
52 | NormalizedSymbol &operator=(NormalizedSymbol &&) = delete; |
53 | |
54 | std::optional<StringRef> Name; |
55 | uint64_t Value = 0; |
56 | uint8_t Type = 0; |
57 | uint8_t Sect = 0; |
58 | uint16_t Desc = 0; |
59 | Linkage L = Linkage::Strong; |
60 | Scope S = Scope::Default; |
61 | Symbol *GraphSymbol = nullptr; |
62 | }; |
63 | |
64 | // Normalized section representation. Section and segment names are guaranteed |
65 | // to be null-terminated, hence the extra bytes on SegName and SectName. |
66 | class NormalizedSection { |
67 | friend class MachOLinkGraphBuilder; |
68 | |
69 | private: |
70 | NormalizedSection() = default; |
71 | |
72 | public: |
73 | char SectName[17]; |
74 | char SegName[17]; |
75 | orc::ExecutorAddr Address; |
76 | uint64_t Size = 0; |
77 | uint64_t Alignment = 0; |
78 | uint32_t Flags = 0; |
79 | const char *Data = nullptr; |
80 | Section *GraphSection = nullptr; |
81 | std::map<orc::ExecutorAddr, Symbol *> CanonicalSymbols; |
82 | }; |
83 | |
84 | using SectionParserFunction = std::function<Error(NormalizedSection &S)>; |
85 | |
86 | MachOLinkGraphBuilder(const object::MachOObjectFile &Obj, Triple TT, |
87 | SubtargetFeatures Features, |
88 | LinkGraph::GetEdgeKindNameFunction GetEdgeKindName); |
89 | |
90 | LinkGraph &getGraph() const { return *G; } |
91 | |
92 | const object::MachOObjectFile &getObject() const { return Obj; } |
93 | |
94 | void addCustomSectionParser(StringRef SectionName, |
95 | SectionParserFunction Parse); |
96 | |
97 | virtual Error addRelocations() = 0; |
98 | |
99 | /// Create a symbol. |
100 | template <typename... ArgTs> |
101 | NormalizedSymbol &createNormalizedSymbol(ArgTs &&... Args) { |
102 | NormalizedSymbol *Sym = reinterpret_cast<NormalizedSymbol *>( |
103 | Allocator.Allocate<NormalizedSymbol>()); |
104 | new (Sym) NormalizedSymbol(std::forward<ArgTs>(Args)...); |
105 | return *Sym; |
106 | } |
107 | |
108 | /// Index is zero-based (MachO section indexes are usually one-based) and |
109 | /// assumed to be in-range. Client is responsible for checking. |
110 | NormalizedSection &getSectionByIndex(unsigned Index) { |
111 | auto I = IndexToSection.find(Val: Index); |
112 | assert(I != IndexToSection.end() && "No section recorded at index" ); |
113 | return I->second; |
114 | } |
115 | |
116 | /// Try to get the section at the given index. Will return an error if the |
117 | /// given index is out of range, or if no section has been added for the given |
118 | /// index. |
119 | Expected<NormalizedSection &> findSectionByIndex(unsigned Index) { |
120 | auto I = IndexToSection.find(Val: Index); |
121 | if (I == IndexToSection.end()) |
122 | return make_error<JITLinkError>(Args: "No section recorded for index " + |
123 | formatv(Fmt: "{0:d}" , Vals&: Index)); |
124 | return I->second; |
125 | } |
126 | |
127 | /// Try to get the symbol at the given index. Will return an error if the |
128 | /// given index is out of range, or if no symbol has been added for the given |
129 | /// index. |
130 | Expected<NormalizedSymbol &> findSymbolByIndex(uint64_t Index) { |
131 | auto I = IndexToSymbol.find(Val: Index); |
132 | if (I == IndexToSymbol.end()) |
133 | return make_error<JITLinkError>(Args: "No symbol at index " + |
134 | formatv(Fmt: "{0:d}" , Vals&: Index)); |
135 | assert(I->second && "Null symbol at index" ); |
136 | return *I->second; |
137 | } |
138 | |
139 | /// Returns the symbol with the highest address not greater than the search |
140 | /// address, or null if no such symbol exists. |
141 | Symbol *getSymbolByAddress(NormalizedSection &NSec, |
142 | orc::ExecutorAddr Address) { |
143 | auto I = NSec.CanonicalSymbols.upper_bound(x: Address); |
144 | if (I == NSec.CanonicalSymbols.begin()) |
145 | return nullptr; |
146 | return std::prev(x: I)->second; |
147 | } |
148 | |
149 | /// Returns the symbol with the highest address not greater than the search |
150 | /// address, or an error if no such symbol exists. |
151 | Expected<Symbol &> findSymbolByAddress(NormalizedSection &NSec, |
152 | orc::ExecutorAddr Address) { |
153 | auto *Sym = getSymbolByAddress(NSec, Address); |
154 | if (Sym) |
155 | if (Address <= Sym->getAddress() + Sym->getSize()) |
156 | return *Sym; |
157 | return make_error<JITLinkError>(Args: "No symbol covering address " + |
158 | formatv(Fmt: "{0:x16}" , Vals&: Address)); |
159 | } |
160 | |
161 | static Linkage getLinkage(uint16_t Desc); |
162 | static Scope getScope(StringRef Name, uint8_t Type); |
163 | static bool isAltEntry(const NormalizedSymbol &NSym); |
164 | |
165 | static bool isDebugSection(const NormalizedSection &NSec); |
166 | static bool isZeroFillSection(const NormalizedSection &NSec); |
167 | |
168 | MachO::relocation_info |
169 | getRelocationInfo(const object::relocation_iterator RelItr) { |
170 | MachO::any_relocation_info ARI = |
171 | getObject().getRelocation(Rel: RelItr->getRawDataRefImpl()); |
172 | MachO::relocation_info RI; |
173 | RI.r_address = ARI.r_word0; |
174 | RI.r_symbolnum = ARI.r_word1 & 0xffffff; |
175 | RI.r_pcrel = (ARI.r_word1 >> 24) & 1; |
176 | RI.r_length = (ARI.r_word1 >> 25) & 3; |
177 | RI.r_extern = (ARI.r_word1 >> 27) & 1; |
178 | RI.r_type = (ARI.r_word1 >> 28); |
179 | return RI; |
180 | } |
181 | |
182 | private: |
183 | static unsigned getPointerSize(const object::MachOObjectFile &Obj); |
184 | static llvm::endianness getEndianness(const object::MachOObjectFile &Obj); |
185 | |
186 | void setCanonicalSymbol(NormalizedSection &NSec, Symbol &Sym) { |
187 | auto *&CanonicalSymEntry = NSec.CanonicalSymbols[Sym.getAddress()]; |
188 | // There should be no symbol at this address, or, if there is, |
189 | // it should be a zero-sized symbol from an empty section (which |
190 | // we can safely override). |
191 | assert((!CanonicalSymEntry || CanonicalSymEntry->getSize() == 0) && |
192 | "Duplicate canonical symbol at address" ); |
193 | CanonicalSymEntry = &Sym; |
194 | } |
195 | |
196 | Section &getCommonSection(); |
197 | void addSectionStartSymAndBlock(unsigned SecIndex, Section &GraphSec, |
198 | orc::ExecutorAddr Address, const char *Data, |
199 | orc::ExecutorAddrDiff Size, |
200 | uint32_t Alignment, bool IsLive); |
201 | |
202 | Error createNormalizedSections(); |
203 | Error createNormalizedSymbols(); |
204 | |
205 | /// Create graph blocks and symbols for externals, absolutes, commons and |
206 | /// all defined symbols in sections without custom parsers. |
207 | Error graphifyRegularSymbols(); |
208 | |
209 | /// Create and return a graph symbol for the given normalized symbol. |
210 | /// |
211 | /// NSym's GraphSymbol member will be updated to point at the newly created |
212 | /// symbol. |
213 | Symbol &createStandardGraphSymbol(NormalizedSymbol &Sym, Block &B, |
214 | size_t Size, bool IsText, |
215 | bool IsNoDeadStrip, bool IsCanonical); |
216 | |
217 | /// Create graph blocks and symbols for all sections. |
218 | Error graphifySectionsWithCustomParsers(); |
219 | |
220 | /// Graphify cstring section. |
221 | Error graphifyCStringSection(NormalizedSection &NSec, |
222 | std::vector<NormalizedSymbol *> NSyms); |
223 | |
224 | // Put the BumpPtrAllocator first so that we don't free any of the underlying |
225 | // memory until the Symbol/Addressable destructors have been run. |
226 | BumpPtrAllocator Allocator; |
227 | |
228 | const object::MachOObjectFile &Obj; |
229 | std::unique_ptr<LinkGraph> G; |
230 | |
231 | bool SubsectionsViaSymbols = false; |
232 | DenseMap<unsigned, NormalizedSection> IndexToSection; |
233 | Section *CommonSection = nullptr; |
234 | |
235 | DenseMap<uint32_t, NormalizedSymbol *> IndexToSymbol; |
236 | StringMap<SectionParserFunction> CustomSectionParserFunctions; |
237 | }; |
238 | |
239 | /// A pass to split up __LD,__compact_unwind sections. |
240 | class CompactUnwindSplitter { |
241 | public: |
242 | CompactUnwindSplitter(StringRef CompactUnwindSectionName) |
243 | : CompactUnwindSectionName(CompactUnwindSectionName) {} |
244 | Error operator()(LinkGraph &G); |
245 | |
246 | private: |
247 | StringRef CompactUnwindSectionName; |
248 | }; |
249 | |
250 | } // end namespace jitlink |
251 | } // end namespace llvm |
252 | |
253 | #endif // LIB_EXECUTIONENGINE_JITLINK_MACHOLINKGRAPHBUILDER_H |
254 | |