clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name MachO_x86_64.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/ExecutionEngine/JITLink -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/ExecutionEngine/JITLink -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/ExecutionEngine/JITLink -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/lib/ExecutionEngine/JITLink -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" |
14 | #include "llvm/ExecutionEngine/JITLink/x86_64.h" |
15 | |
16 | #include "MachOLinkGraphBuilder.h" |
17 | #include "PerGraphGOTAndPLTStubsBuilder.h" |
18 | |
19 | #define DEBUG_TYPE "jitlink" |
20 | |
21 | using namespace llvm; |
22 | using namespace llvm::jitlink; |
23 | |
24 | namespace { |
25 | |
26 | class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder { |
27 | public: |
28 | MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj) |
29 | : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin"), |
30 | x86_64::getEdgeKindName) {} |
31 | |
32 | private: |
33 | enum MachONormalizedRelocationType : unsigned { |
34 | MachOBranch32, |
35 | MachOPointer32, |
36 | MachOPointer64, |
37 | MachOPointer64Anon, |
38 | MachOPCRel32, |
39 | MachOPCRel32Minus1, |
40 | MachOPCRel32Minus2, |
41 | MachOPCRel32Minus4, |
42 | MachOPCRel32Anon, |
43 | MachOPCRel32Minus1Anon, |
44 | MachOPCRel32Minus2Anon, |
45 | MachOPCRel32Minus4Anon, |
46 | MachOPCRel32GOTLoad, |
47 | MachOPCRel32GOT, |
48 | MachOPCRel32TLV, |
49 | MachOSubtractor32, |
50 | MachOSubtractor64, |
51 | }; |
52 | |
53 | static Expected<MachONormalizedRelocationType> |
54 | getRelocKind(const MachO::relocation_info &RI) { |
55 | switch (RI.r_type) { |
56 | case MachO::X86_64_RELOC_UNSIGNED: |
57 | if (!RI.r_pcrel) { |
58 | if (RI.r_length == 3) |
59 | return RI.r_extern ? MachOPointer64 : MachOPointer64Anon; |
60 | else if (RI.r_extern && RI.r_length == 2) |
61 | return MachOPointer32; |
62 | } |
63 | break; |
64 | case MachO::X86_64_RELOC_SIGNED: |
65 | if (RI.r_pcrel && RI.r_length == 2) |
66 | return RI.r_extern ? MachOPCRel32 : MachOPCRel32Anon; |
67 | break; |
68 | case MachO::X86_64_RELOC_BRANCH: |
69 | if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) |
70 | return MachOBranch32; |
71 | break; |
72 | case MachO::X86_64_RELOC_GOT_LOAD: |
73 | if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) |
74 | return MachOPCRel32GOTLoad; |
75 | break; |
76 | case MachO::X86_64_RELOC_GOT: |
77 | if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) |
78 | return MachOPCRel32GOT; |
79 | break; |
80 | case MachO::X86_64_RELOC_SUBTRACTOR: |
81 | if (!RI.r_pcrel && RI.r_extern) { |
82 | if (RI.r_length == 2) |
83 | return MachOSubtractor32; |
84 | else if (RI.r_length == 3) |
85 | return MachOSubtractor64; |
86 | } |
87 | break; |
88 | case MachO::X86_64_RELOC_SIGNED_1: |
89 | if (RI.r_pcrel && RI.r_length == 2) |
90 | return RI.r_extern ? MachOPCRel32Minus1 : MachOPCRel32Minus1Anon; |
91 | break; |
92 | case MachO::X86_64_RELOC_SIGNED_2: |
93 | if (RI.r_pcrel && RI.r_length == 2) |
94 | return RI.r_extern ? MachOPCRel32Minus2 : MachOPCRel32Minus2Anon; |
95 | break; |
96 | case MachO::X86_64_RELOC_SIGNED_4: |
97 | if (RI.r_pcrel && RI.r_length == 2) |
98 | return RI.r_extern ? MachOPCRel32Minus4 : MachOPCRel32Minus4Anon; |
99 | break; |
100 | case MachO::X86_64_RELOC_TLV: |
101 | if (RI.r_pcrel && RI.r_extern && RI.r_length == 2) |
102 | return MachOPCRel32TLV; |
103 | break; |
104 | } |
105 | |
106 | return make_error<JITLinkError>( |
107 | "Unsupported x86-64 relocation: address=" + |
108 | formatv("{0:x8}", RI.r_address) + |
109 | ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) + |
110 | ", kind=" + formatv("{0:x1}", RI.r_type) + |
111 | ", pc_rel=" + (RI.r_pcrel ? "true" : "false") + |
112 | ", extern=" + (RI.r_extern ? "true" : "false") + |
113 | ", length=" + formatv("{0:d}", RI.r_length)); |
114 | } |
115 | |
116 | using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>; |
117 | |
118 | |
119 | |
120 | Expected<PairRelocInfo> parsePairRelocation( |
121 | Block &BlockToFix, MachONormalizedRelocationType SubtractorKind, |
122 | const MachO::relocation_info &SubRI, JITTargetAddress FixupAddress, |
123 | const char *FixupContent, object::relocation_iterator &UnsignedRelItr, |
124 | object::relocation_iterator &RelEnd) { |
125 | using namespace support; |
126 | |
127 | assert(((SubtractorKind == MachOSubtractor32 && SubRI.r_length == 2) || |
128 | (SubtractorKind == MachOSubtractor64 && SubRI.r_length == 3)) && |
129 | "Subtractor kind should match length"); |
130 | assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern"); |
131 | assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel"); |
132 | |
133 | if (UnsignedRelItr == RelEnd) |
134 | return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired " |
135 | "UNSIGNED relocation"); |
136 | |
137 | auto UnsignedRI = getRelocationInfo(UnsignedRelItr); |
138 | |
139 | if (SubRI.r_address != UnsignedRI.r_address) |
140 | return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED " |
141 | "point to different addresses"); |
142 | |
143 | if (SubRI.r_length != UnsignedRI.r_length) |
144 | return make_error<JITLinkError>("length of x86_64 SUBTRACTOR and paired " |
145 | "UNSIGNED reloc must match"); |
146 | |
147 | Symbol *FromSymbol; |
148 | if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum)) |
149 | FromSymbol = FromSymbolOrErr->GraphSymbol; |
150 | else |
151 | return FromSymbolOrErr.takeError(); |
152 | |
153 | |
154 | uint64_t FixupValue = 0; |
155 | if (SubRI.r_length == 3) |
156 | FixupValue = *(const little64_t *)FixupContent; |
157 | else |
158 | FixupValue = *(const little32_t *)FixupContent; |
159 | |
160 | |
161 | |
162 | Symbol *ToSymbol = nullptr; |
163 | if (UnsignedRI.r_extern) { |
164 | |
165 | if (auto ToSymbolOrErr = findSymbolByIndex(UnsignedRI.r_symbolnum)) |
166 | ToSymbol = ToSymbolOrErr->GraphSymbol; |
167 | else |
168 | return ToSymbolOrErr.takeError(); |
169 | } else { |
170 | auto ToSymbolSec = findSectionByIndex(UnsignedRI.r_symbolnum - 1); |
171 | if (!ToSymbolSec) |
172 | return ToSymbolSec.takeError(); |
173 | ToSymbol = getSymbolByAddress(ToSymbolSec->Address); |
174 | assert(ToSymbol && "No symbol for section"); |
175 | FixupValue -= ToSymbol->getAddress(); |
176 | } |
177 | |
178 | Edge::Kind DeltaKind; |
179 | Symbol *TargetSymbol; |
180 | uint64_t Addend; |
181 | if (&BlockToFix == &FromSymbol->getAddressable()) { |
182 | TargetSymbol = ToSymbol; |
183 | DeltaKind = (SubRI.r_length == 3) ? x86_64::Delta64 : x86_64::Delta32; |
184 | Addend = FixupValue + (FixupAddress - FromSymbol->getAddress()); |
185 | |
186 | } else if (&BlockToFix == &ToSymbol->getAddressable()) { |
187 | TargetSymbol = FromSymbol; |
188 | DeltaKind = |
189 | (SubRI.r_length == 3) ? x86_64::NegDelta64 : x86_64::NegDelta32; |
190 | Addend = FixupValue - (FixupAddress - ToSymbol->getAddress()); |
191 | } else { |
192 | |
193 | return make_error<JITLinkError>("SUBTRACTOR relocation must fix up " |
194 | "either 'A' or 'B' (or a symbol in one " |
195 | "of their alt-entry chains)"); |
196 | } |
197 | |
198 | return PairRelocInfo(DeltaKind, TargetSymbol, Addend); |
199 | } |
200 | |
201 | Error addRelocations() override { |
202 | using namespace support; |
203 | auto &Obj = getObject(); |
204 | |
205 | LLVM_DEBUG(dbgs() << "Processing relocations:\n"); |
206 | |
207 | for (auto &S : Obj.sections()) { |
208 | |
209 | JITTargetAddress SectionAddress = S.getAddress(); |
210 | |
211 | |
212 | if (S.isVirtual()) { |
213 | if (S.relocation_begin() != S.relocation_end()) |
214 | return make_error<JITLinkError>("Virtual section contains " |
215 | "relocations"); |
216 | continue; |
217 | } |
218 | |
219 | |
220 | { |
221 | auto &NSec = |
222 | getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); |
223 | if (!NSec.GraphSection) { |
224 | LLVM_DEBUG({ |
225 | dbgs() << " Skipping relocations for MachO section " |
226 | << NSec.SegName << "/" << NSec.SectName |
227 | << " which has no associated graph section\n"; |
228 | }); |
229 | continue; |
230 | } |
231 | } |
232 | |
233 | |
234 | for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end(); |
235 | RelItr != RelEnd; ++RelItr) { |
236 | |
237 | MachO::relocation_info RI = getRelocationInfo(RelItr); |
238 | |
239 | |
240 | JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address; |
241 | |
242 | LLVM_DEBUG({ |
243 | auto &NSec = |
244 | getSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl())); |
245 | dbgs() << " " << NSec.SectName << " + " |
246 | << formatv("{0:x8}", RI.r_address) << ":\n"; |
247 | }); |
248 | |
249 | |
250 | Block *BlockToFix = nullptr; |
251 | { |
252 | auto SymbolToFixOrErr = findSymbolByAddress(FixupAddress); |
253 | if (!SymbolToFixOrErr) |
254 | return SymbolToFixOrErr.takeError(); |
255 | BlockToFix = &SymbolToFixOrErr->getBlock(); |
256 | } |
257 | |
258 | if (FixupAddress + static_cast<JITTargetAddress>(1ULL << RI.r_length) > |
259 | BlockToFix->getAddress() + BlockToFix->getContent().size()) |
260 | return make_error<JITLinkError>( |
261 | "Relocation extends past end of fixup block"); |
262 | |
263 | |
264 | const char *FixupContent = BlockToFix->getContent().data() + |
265 | (FixupAddress - BlockToFix->getAddress()); |
266 | |
267 | size_t FixupOffset = FixupAddress - BlockToFix->getAddress(); |
268 | |
269 | |
270 | Symbol *TargetSymbol = nullptr; |
271 | uint64_t Addend = 0; |
272 | |
273 | |
274 | auto MachORelocKind = getRelocKind(RI); |
275 | if (!MachORelocKind) |
276 | return MachORelocKind.takeError(); |
277 | |
278 | Edge::Kind Kind = Edge::Invalid; |
279 | |
280 | switch (*MachORelocKind) { |
281 | case MachOBranch32: |
282 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
283 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
284 | else |
285 | return TargetSymbolOrErr.takeError(); |
286 | Addend = *(const little32_t *)FixupContent; |
287 | Kind = x86_64::BranchPCRel32; |
288 | break; |
289 | case MachOPCRel32: |
290 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
291 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
292 | else |
293 | return TargetSymbolOrErr.takeError(); |
294 | Addend = *(const little32_t *)FixupContent - 4; |
295 | Kind = x86_64::Delta32; |
296 | break; |
297 | case MachOPCRel32GOTLoad: |
298 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
299 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
300 | else |
301 | return TargetSymbolOrErr.takeError(); |
302 | Addend = *(const little32_t *)FixupContent; |
303 | Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable; |
304 | if (FixupOffset < 3) |
305 | return make_error<JITLinkError>("GOTLD at invalid offset " + |
306 | formatv("{0}", FixupOffset)); |
307 | break; |
308 | case MachOPCRel32GOT: |
309 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
310 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
311 | else |
312 | return TargetSymbolOrErr.takeError(); |
313 | Addend = *(const little32_t *)FixupContent - 4; |
314 | Kind = x86_64::RequestGOTAndTransformToDelta32; |
315 | break; |
316 | case MachOPCRel32TLV: |
317 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
318 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
319 | else |
320 | return TargetSymbolOrErr.takeError(); |
321 | Addend = *(const little32_t *)FixupContent; |
322 | Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable; |
323 | if (FixupOffset < 3) |
324 | return make_error<JITLinkError>("TLV at invalid offset " + |
325 | formatv("{0}", FixupOffset)); |
326 | break; |
327 | case MachOPointer32: |
328 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
329 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
330 | else |
331 | return TargetSymbolOrErr.takeError(); |
332 | Addend = *(const ulittle32_t *)FixupContent; |
333 | Kind = x86_64::Pointer32; |
334 | break; |
335 | case MachOPointer64: |
336 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
337 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
338 | else |
339 | return TargetSymbolOrErr.takeError(); |
340 | Addend = *(const ulittle64_t *)FixupContent; |
341 | Kind = x86_64::Pointer64; |
342 | break; |
343 | case MachOPointer64Anon: { |
344 | JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent; |
345 | if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) |
346 | TargetSymbol = &*TargetSymbolOrErr; |
347 | else |
348 | return TargetSymbolOrErr.takeError(); |
349 | Addend = TargetAddress - TargetSymbol->getAddress(); |
350 | Kind = x86_64::Pointer64; |
351 | break; |
352 | } |
353 | case MachOPCRel32Minus1: |
354 | case MachOPCRel32Minus2: |
355 | case MachOPCRel32Minus4: |
356 | if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum)) |
357 | TargetSymbol = TargetSymbolOrErr->GraphSymbol; |
358 | else |
359 | return TargetSymbolOrErr.takeError(); |
360 | Addend = *(const little32_t *)FixupContent - 4; |
361 | Kind = x86_64::Delta32; |
362 | break; |
363 | case MachOPCRel32Anon: { |
364 | JITTargetAddress TargetAddress = |
365 | FixupAddress + 4 + *(const little32_t *)FixupContent; |
366 | if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) |
367 | TargetSymbol = &*TargetSymbolOrErr; |
368 | else |
369 | return TargetSymbolOrErr.takeError(); |
370 | Addend = TargetAddress - TargetSymbol->getAddress() - 4; |
371 | Kind = x86_64::Delta32; |
372 | break; |
373 | } |
374 | case MachOPCRel32Minus1Anon: |
375 | case MachOPCRel32Minus2Anon: |
376 | case MachOPCRel32Minus4Anon: { |
377 | JITTargetAddress Delta = |
378 | 4 + static_cast<JITTargetAddress>( |
379 | 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon)); |
380 | JITTargetAddress TargetAddress = |
381 | FixupAddress + Delta + *(const little32_t *)FixupContent; |
382 | if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress)) |
383 | TargetSymbol = &*TargetSymbolOrErr; |
384 | else |
385 | return TargetSymbolOrErr.takeError(); |
386 | Addend = TargetAddress - TargetSymbol->getAddress() - Delta; |
387 | Kind = x86_64::Delta32; |
388 | break; |
389 | } |
390 | case MachOSubtractor32: |
391 | case MachOSubtractor64: { |
392 | |
393 | |
394 | |
395 | |
396 | |
397 | auto PairInfo = |
398 | parsePairRelocation(*BlockToFix, *MachORelocKind, RI, |
399 | FixupAddress, FixupContent, ++RelItr, RelEnd); |
400 | if (!PairInfo) |
401 | return PairInfo.takeError(); |
402 | std::tie(Kind, TargetSymbol, Addend) = *PairInfo; |
403 | assert(TargetSymbol && "No target symbol from parsePairRelocation?"); |
404 | break; |
405 | } |
406 | } |
407 | |
408 | LLVM_DEBUG({ |
409 | dbgs() << " "; |
410 | Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol, |
411 | Addend); |
412 | printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind)); |
413 | dbgs() << "\n"; |
414 | }); |
415 | BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(), |
416 | *TargetSymbol, Addend); |
417 | } |
418 | } |
419 | return Error::success(); |
420 | } |
421 | }; |
422 | |
423 | class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64 |
424 | : public PerGraphGOTAndPLTStubsBuilder< |
425 | PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> { |
426 | public: |
427 | |
428 | using PerGraphGOTAndPLTStubsBuilder< |
429 | PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>:: |
430 | PerGraphGOTAndPLTStubsBuilder; |
431 | |
432 | bool isGOTEdgeToFix(Edge &E) const { |
433 | return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 || |
434 | E.getKind() == |
435 | x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable; |
436 | } |
437 | |
438 | Symbol &createGOTEntry(Symbol &Target) { |
439 | return x86_64::createAnonymousPointer(G, getGOTSection(), &Target); |
440 | } |
441 | |
442 | void fixGOTEdge(Edge &E, Symbol &GOTEntry) { |
443 | |
444 | switch (E.getKind()) { |
445 | case x86_64::RequestGOTAndTransformToDelta32: |
446 | E.setKind(x86_64::Delta32); |
447 | break; |
448 | case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable: |
449 | E.setKind(x86_64::PCRel32GOTLoadREXRelaxable); |
450 | break; |
451 | default: |
452 | llvm_unreachable("Not a GOT transform edge"); |
453 | } |
454 | |
455 | E.setTarget(GOTEntry); |
456 | } |
457 | |
458 | bool isExternalBranchEdge(Edge &E) { |
459 | return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal(); |
460 | } |
461 | |
462 | Symbol &createPLTStub(Symbol &Target) { |
463 | return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(), |
464 | getGOTEntry(Target)); |
465 | } |
466 | |
467 | void fixPLTEdge(Edge &E, Symbol &Stub) { |
468 | assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?"); |
469 | assert(E.getAddend() == 0 && |
470 | "BranchPCRel32 edge has unexpected addend value"); |
471 | |
472 | |
473 | |
474 | |
475 | E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable); |
476 | E.setTarget(Stub); |
477 | } |
478 | |
479 | private: |
480 | Section &getGOTSection() { |
481 | if (!GOTSection) |
482 | GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ); |
483 | return *GOTSection; |
484 | } |
485 | |
486 | Section &getStubsSection() { |
487 | if (!StubsSection) { |
488 | auto StubsProt = static_cast<sys::Memory::ProtectionFlags>( |
489 | sys::Memory::MF_READ | sys::Memory::MF_EXEC); |
490 | StubsSection = &G.createSection("$__STUBS", StubsProt); |
491 | } |
492 | return *StubsSection; |
493 | } |
494 | |
495 | Section *GOTSection = nullptr; |
496 | Section *StubsSection = nullptr; |
497 | }; |
498 | |
499 | } |
500 | |
501 | namespace llvm { |
502 | namespace jitlink { |
503 | |
504 | class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { |
505 | friend class JITLinker<MachOJITLinker_x86_64>; |
506 | |
507 | public: |
508 | MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx, |
509 | std::unique_ptr<LinkGraph> G, |
510 | PassConfiguration PassConfig) |
511 | : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} |
512 | |
513 | private: |
514 | Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { |
515 | return x86_64::applyFixup(G, B, E, nullptr); |
| 1 | Passing null pointer value via 4th parameter 'GOTSymbol' | |
|
| |
516 | } |
517 | }; |
518 | |
519 | Expected<std::unique_ptr<LinkGraph>> |
520 | createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) { |
521 | auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer); |
522 | if (!MachOObj) |
523 | return MachOObj.takeError(); |
524 | return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph(); |
525 | } |
526 | |
527 | void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, |
528 | std::unique_ptr<JITLinkContext> Ctx) { |
529 | |
530 | PassConfiguration Config; |
531 | |
532 | if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { |
533 | |
534 | Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64()); |
535 | Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64()); |
536 | |
537 | |
538 | if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) |
539 | Config.PrePrunePasses.push_back(std::move(MarkLive)); |
540 | else |
541 | Config.PrePrunePasses.push_back(markAllSymbolsLive); |
542 | |
543 | |
544 | Config.PostPrunePasses.push_back( |
545 | PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass); |
546 | |
547 | |
548 | Config.PreFixupPasses.push_back(x86_64::optimize_x86_64_GOTAndStubs); |
549 | } |
550 | |
551 | if (auto Err = Ctx->modifyPassConfig(*G, Config)) |
552 | return Ctx->notifyFailed(std::move(Err)); |
553 | |
554 | |
555 | MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config)); |
556 | } |
557 | |
558 | LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() { |
559 | return EHFrameSplitter("__TEXT,__eh_frame"); |
560 | } |
561 | |
562 | LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() { |
563 | return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize, |
564 | x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32); |
565 | } |
566 | |
567 | } |
568 | } |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #ifndef LLVM_EXECUTIONENGINE_JITLINK_X86_64_H |
14 | #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H |
15 | |
16 | #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
17 | |
18 | #include <limits> |
19 | |
20 | namespace llvm { |
21 | namespace jitlink { |
22 | namespace x86_64 { |
23 | |
24 | |
25 | enum EdgeKind_x86_64 : Edge::Kind { |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | Pointer64 = Edge::FirstRelocation, |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | Pointer32, |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | Pointer32Signed, |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | Delta64, |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | |
74 | |
75 | Delta32, |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | NegDelta64, |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | NegDelta32, |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | Delta64FromGOT, |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | |
126 | BranchPCRel32, |
127 | |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | BranchPCRel32ToPtrJumpStub, |
156 | |
157 | |
158 | |
159 | |
160 | |
161 | |
162 | |
163 | |
164 | |
165 | |
166 | |
167 | |
168 | |
169 | |
170 | |
171 | BranchPCRel32ToPtrJumpStubBypassable, |
172 | |
173 | |
174 | |
175 | |
176 | |
177 | |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | |
187 | |
188 | |
189 | |
190 | |
191 | RequestGOTAndTransformToDelta32, |
192 | |
193 | |
194 | |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | RequestGOTAndTransformToDelta64, |
212 | |
213 | |
214 | |
215 | |
216 | |
217 | |
218 | |
219 | |
220 | |
221 | |
222 | |
223 | |
224 | |
225 | |
226 | |
227 | |
228 | |
229 | |
230 | |
231 | |
232 | RequestGOTAndTransformToDelta64FromGOT, |
233 | |
234 | |
235 | |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | |
244 | |
245 | |
246 | PCRel32GOTLoadRelaxable, |
247 | |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | PCRel32GOTLoadREXRelaxable, |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | |
275 | |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | |
282 | RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable, |
283 | |
284 | |
285 | |
286 | |
287 | |
288 | |
289 | |
290 | |
291 | |
292 | |
293 | |
294 | |
295 | |
296 | |
297 | |
298 | |
299 | |
300 | |
301 | |
302 | |
303 | RequestGOTAndTransformToPCRel32GOTLoadRelaxable, |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | |
313 | |
314 | |
315 | |
316 | |
317 | |
318 | |
319 | |
320 | |
321 | |
322 | |
323 | |
324 | |
325 | PCRel32TLVPLoadREXRelaxable, |
326 | |
327 | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 | |
342 | RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable |
343 | }; |
344 | |
345 | |
346 | |
347 | const char *getEdgeKindName(Edge::Kind K); |
348 | |
349 | |
350 | |
351 | |
352 | |
353 | |
354 | |
355 | Error optimize_x86_64_GOTAndStubs(LinkGraph &G); |
356 | |
357 | |
358 | inline bool isInRangeForImmU32(uint64_t Value) { |
359 | return Value <= std::numeric_limits<uint32_t>::max(); |
360 | } |
361 | |
362 | |
363 | inline bool isInRangeForImmS32(int64_t Value) { |
364 | return (Value >= std::numeric_limits<int32_t>::min() && |
365 | Value <= std::numeric_limits<int32_t>::max()); |
366 | } |
367 | |
368 | |
369 | inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E, |
370 | const Symbol *GOTSymbol) { |
371 | using namespace support; |
372 | |
373 | char *BlockWorkingMem = B.getAlreadyMutableContent().data(); |
374 | char *FixupPtr = BlockWorkingMem + E.getOffset(); |
375 | JITTargetAddress FixupAddress = B.getAddress() + E.getOffset(); |
376 | |
377 | switch (E.getKind()) { |
| 3 | | Control jumps to 'case Delta64FromGOT:' at line 446 | |
|
378 | |
379 | case Pointer64: { |
380 | uint64_t Value = E.getTarget().getAddress() + E.getAddend(); |
381 | *(ulittle64_t *)FixupPtr = Value; |
382 | break; |
383 | } |
384 | |
385 | case Pointer32: { |
386 | uint64_t Value = E.getTarget().getAddress() + E.getAddend(); |
387 | if (LLVM_LIKELY(isInRangeForImmU32(Value))) |
388 | *(ulittle32_t *)FixupPtr = Value; |
389 | else |
390 | return makeTargetOutOfRangeError(G, B, E); |
391 | break; |
392 | } |
393 | case Pointer32Signed: { |
394 | int64_t Value = E.getTarget().getAddress() + E.getAddend(); |
395 | if (LLVM_LIKELY(isInRangeForImmS32(Value))) |
396 | *(little32_t *)FixupPtr = Value; |
397 | else |
398 | return makeTargetOutOfRangeError(G, B, E); |
399 | break; |
400 | } |
401 | |
402 | case BranchPCRel32: |
403 | case BranchPCRel32ToPtrJumpStub: |
404 | case BranchPCRel32ToPtrJumpStubBypassable: |
405 | case PCRel32GOTLoadRelaxable: |
406 | case PCRel32GOTLoadREXRelaxable: |
407 | case PCRel32TLVPLoadREXRelaxable: { |
408 | int64_t Value = |
409 | E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend(); |
410 | if (LLVM_LIKELY(isInRangeForImmS32(Value))) |
411 | *(little32_t *)FixupPtr = Value; |
412 | else |
413 | return makeTargetOutOfRangeError(G, B, E); |
414 | break; |
415 | } |
416 | |
417 | case Delta64: { |
418 | int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); |
419 | *(little64_t *)FixupPtr = Value; |
420 | break; |
421 | } |
422 | |
423 | case Delta32: { |
424 | int64_t Value = E.getTarget().getAddress() - FixupAddress + E.getAddend(); |
425 | if (LLVM_LIKELY(isInRangeForImmS32(Value))) |
426 | *(little32_t *)FixupPtr = Value; |
427 | else |
428 | return makeTargetOutOfRangeError(G, B, E); |
429 | break; |
430 | } |
431 | |
432 | case NegDelta64: { |
433 | int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); |
434 | *(little64_t *)FixupPtr = Value; |
435 | break; |
436 | } |
437 | |
438 | case NegDelta32: { |
439 | int64_t Value = FixupAddress - E.getTarget().getAddress() + E.getAddend(); |
440 | if (LLVM_LIKELY(isInRangeForImmS32(Value))) |
441 | *(little32_t *)FixupPtr = Value; |
442 | else |
443 | return makeTargetOutOfRangeError(G, B, E); |
444 | break; |
445 | } |
446 | case Delta64FromGOT: { |
447 | assert(GOTSymbol && "No GOT section symbol"); |
448 | int64_t Value = |
449 | E.getTarget().getAddress() - GOTSymbol->getAddress() + E.getAddend(); |
| 4 | | Called C++ object pointer is null |
|
450 | *(little64_t *)FixupPtr = Value; |
451 | break; |
452 | } |
453 | |
454 | default: { |
455 | |
456 | |
457 | llvm_unreachable("Graph contains edge kind with no fixup expression"); |
458 | } |
459 | } |
460 | |
461 | return Error::success(); |
462 | } |
463 | |
464 | |
465 | constexpr uint64_t PointerSize = 8; |
466 | |
467 | |
468 | extern const char NullPointerContent[PointerSize]; |
469 | |
470 | |
471 | |
472 | |
473 | |
474 | |
475 | extern const char PointerJumpStubContent[6]; |
476 | |
477 | |
478 | |
479 | |
480 | |
481 | |
482 | |
483 | |
484 | |
485 | |
486 | |
487 | inline Symbol &createAnonymousPointer(LinkGraph &G, Section &PointerSection, |
488 | Symbol *InitialTarget = nullptr, |
489 | uint64_t InitialAddend = 0) { |
490 | auto &B = |
491 | G.createContentBlock(PointerSection, NullPointerContent, ~7ULL, 8, 0); |
492 | if (InitialTarget) |
493 | B.addEdge(Pointer64, 0, *InitialTarget, InitialAddend); |
494 | return G.addAnonymousSymbol(B, 0, 8, false, false); |
495 | } |
496 | |
497 | |
498 | |
499 | |
500 | |
501 | |
502 | |
503 | inline Block &createPointerJumpStubBlock(LinkGraph &G, Section &StubSection, |
504 | Symbol &PointerSymbol) { |
505 | auto &B = |
506 | G.createContentBlock(StubSection, PointerJumpStubContent, ~5ULL, 1, 0); |
507 | B.addEdge(Delta32, 2, PointerSymbol, -4); |
508 | return B; |
509 | } |
510 | |
511 | |
512 | |
513 | |
514 | |
515 | inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G, |
516 | Section &StubSection, |
517 | Symbol &PointerSymbol) { |
518 | return G.addAnonymousSymbol( |
519 | createPointerJumpStubBlock(G, StubSection, PointerSymbol), 0, 6, true, |
520 | false); |
521 | } |
522 | |
523 | } |
524 | } |
525 | } |
526 | |
527 | #endif // LLVM_EXECUTIONENGINE_JITLINK_X86_64_H |