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