1 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
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 // MachO/x86-64 jit-link implementation.
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:
MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile & Obj)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>
getRelocKind(const MachO::relocation_info & RI)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 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
119 // returns the edge kind and addend to be used.
parsePairRelocation(Block & BlockToFix,MachONormalizedRelocationType SubtractorKind,const MachO::relocation_info & SubRI,JITTargetAddress FixupAddress,const char * FixupContent,object::relocation_iterator & UnsignedRelItr,object::relocation_iterator & RelEnd)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 // Read the current fixup value.
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 // Find 'ToSymbol' using symbol number or address, depending on whether the
161 // paired UNSIGNED relocation is extern.
162 Symbol *ToSymbol = nullptr;
163 if (UnsignedRI.r_extern) {
164 // Find target symbol by symbol index.
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 // FIXME: handle extern 'from'.
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 // BlockToFix was neither FromSymbol nor ToSymbol.
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
addRelocations()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 // Skip relocations virtual sections.
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 // Skip relocations for debug symbols.
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 // Add relocations for section.
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 // Find the address of the value to fix up.
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 // Find the block that the fixup points to.
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 // Get a pointer to the fixup content.
264 const char *FixupContent = BlockToFix->getContent().data() +
265 (FixupAddress - BlockToFix->getAddress());
266
267 size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
268
269 // The target symbol and addend will be populated by the switch below.
270 Symbol *TargetSymbol = nullptr;
271 uint64_t Addend = 0;
272
273 // Sanity check the relocation kind.
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::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
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 MachOPointer32:
317 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
318 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
319 else
320 return TargetSymbolOrErr.takeError();
321 Addend = *(const ulittle32_t *)FixupContent;
322 Kind = x86_64::Pointer32;
323 break;
324 case MachOPointer64:
325 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
326 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
327 else
328 return TargetSymbolOrErr.takeError();
329 Addend = *(const ulittle64_t *)FixupContent;
330 Kind = x86_64::Pointer64;
331 break;
332 case MachOPointer64Anon: {
333 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
334 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
335 TargetSymbol = &*TargetSymbolOrErr;
336 else
337 return TargetSymbolOrErr.takeError();
338 Addend = TargetAddress - TargetSymbol->getAddress();
339 Kind = x86_64::Pointer64;
340 break;
341 }
342 case MachOPCRel32Minus1:
343 case MachOPCRel32Minus2:
344 case MachOPCRel32Minus4:
345 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
346 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
347 else
348 return TargetSymbolOrErr.takeError();
349 Addend = *(const little32_t *)FixupContent - 4;
350 Kind = x86_64::Delta32;
351 break;
352 case MachOPCRel32Anon: {
353 JITTargetAddress TargetAddress =
354 FixupAddress + 4 + *(const little32_t *)FixupContent;
355 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
356 TargetSymbol = &*TargetSymbolOrErr;
357 else
358 return TargetSymbolOrErr.takeError();
359 Addend = TargetAddress - TargetSymbol->getAddress() - 4;
360 Kind = x86_64::Delta32;
361 break;
362 }
363 case MachOPCRel32Minus1Anon:
364 case MachOPCRel32Minus2Anon:
365 case MachOPCRel32Minus4Anon: {
366 JITTargetAddress Delta =
367 4 + static_cast<JITTargetAddress>(
368 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
369 JITTargetAddress TargetAddress =
370 FixupAddress + Delta + *(const little32_t *)FixupContent;
371 if (auto TargetSymbolOrErr = findSymbolByAddress(TargetAddress))
372 TargetSymbol = &*TargetSymbolOrErr;
373 else
374 return TargetSymbolOrErr.takeError();
375 Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
376 Kind = x86_64::Delta32;
377 break;
378 }
379 case MachOSubtractor32:
380 case MachOSubtractor64: {
381 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
382 // parsePairRelocation handles the paired reloc, and returns the
383 // edge kind to be used (either Delta32/Delta64, or
384 // NegDelta32/NegDelta64, depending on the direction of the
385 // subtraction) along with the addend.
386 auto PairInfo =
387 parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
388 FixupAddress, FixupContent, ++RelItr, RelEnd);
389 if (!PairInfo)
390 return PairInfo.takeError();
391 std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
392 assert(TargetSymbol && "No target symbol from parsePairRelocation?");
393 break;
394 }
395 case MachOPCRel32TLV:
396 return make_error<JITLinkError>(
397 "MachO TLV relocations not yet supported");
398 }
399
400 LLVM_DEBUG({
401 dbgs() << " ";
402 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
403 Addend);
404 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
405 dbgs() << "\n";
406 });
407 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
408 *TargetSymbol, Addend);
409 }
410 }
411 return Error::success();
412 }
413 };
414
415 class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
416 : public PerGraphGOTAndPLTStubsBuilder<
417 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
418 public:
419
420 using PerGraphGOTAndPLTStubsBuilder<
421 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
422 PerGraphGOTAndPLTStubsBuilder;
423
isGOTEdgeToFix(Edge & E) const424 bool isGOTEdgeToFix(Edge &E) const {
425 return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
426 E.getKind() ==
427 x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
428 }
429
createGOTEntry(Symbol & Target)430 Symbol &createGOTEntry(Symbol &Target) {
431 return x86_64::createAnonymousPointer(G, getGOTSection(), &Target);
432 }
433
fixGOTEdge(Edge & E,Symbol & GOTEntry)434 void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
435 // Fix the edge kind.
436 switch (E.getKind()) {
437 case x86_64::RequestGOTAndTransformToDelta32:
438 E.setKind(x86_64::Delta32);
439 break;
440 case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
441 E.setKind(x86_64::PCRel32GOTLoadRelaxable);
442 break;
443 default:
444 llvm_unreachable("Not a GOT transform edge");
445 }
446 // Fix the target, leave the addend as-is.
447 E.setTarget(GOTEntry);
448 }
449
isExternalBranchEdge(Edge & E)450 bool isExternalBranchEdge(Edge &E) {
451 return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal();
452 }
453
createPLTStub(Symbol & Target)454 Symbol &createPLTStub(Symbol &Target) {
455 return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(),
456 getGOTEntry(Target));
457 }
458
fixPLTEdge(Edge & E,Symbol & Stub)459 void fixPLTEdge(Edge &E, Symbol &Stub) {
460 assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?");
461 assert(E.getAddend() == 0 &&
462 "BranchPCRel32 edge has unexpected addend value");
463
464 // Set the edge kind to BranchPCRel32ToPtrJumpStubRelaxable. We will use
465 // this to check for stub optimization opportunities in the
466 // optimizeMachO_x86_64_GOTAndStubs pass below.
467 E.setKind(x86_64::BranchPCRel32ToPtrJumpStubRelaxable);
468 E.setTarget(Stub);
469 }
470
471 private:
getGOTSection()472 Section &getGOTSection() {
473 if (!GOTSection)
474 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ);
475 return *GOTSection;
476 }
477
getStubsSection()478 Section &getStubsSection() {
479 if (!StubsSection) {
480 auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
481 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
482 StubsSection = &G.createSection("$__STUBS", StubsProt);
483 }
484 return *StubsSection;
485 }
486
487 Section *GOTSection = nullptr;
488 Section *StubsSection = nullptr;
489 };
490
491 } // namespace
492
optimizeMachO_x86_64_GOTAndStubs(LinkGraph & G)493 static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) {
494 LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
495
496 for (auto *B : G.blocks())
497 for (auto &E : B->edges())
498 if (E.getKind() == x86_64::PCRel32GOTLoadRelaxable) {
499 assert(E.getOffset() >= 3 && "GOT edge occurs too early in block");
500
501 // Optimize GOT references.
502 auto &GOTBlock = E.getTarget().getBlock();
503 assert(GOTBlock.getSize() == G.getPointerSize() &&
504 "GOT entry block should be pointer sized");
505 assert(GOTBlock.edges_size() == 1 &&
506 "GOT entry should only have one outgoing edge");
507
508 auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
509 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
510 JITTargetAddress TargetAddr = GOTTarget.getAddress();
511
512 // Check that this is a recognized MOV instruction.
513 // FIXME: Can we assume this?
514 constexpr uint8_t MOVQRIPRel[] = {0x48, 0x8b};
515 if (strncmp(B->getContent().data() + E.getOffset() - 3,
516 reinterpret_cast<const char *>(MOVQRIPRel), 2) != 0)
517 continue;
518
519 int64_t Displacement = TargetAddr - EdgeAddr + 4;
520 if (Displacement >= std::numeric_limits<int32_t>::min() &&
521 Displacement <= std::numeric_limits<int32_t>::max()) {
522 E.setTarget(GOTTarget);
523 E.setKind(x86_64::Delta32);
524 E.setAddend(E.getAddend() - 4);
525 auto *BlockData = reinterpret_cast<uint8_t *>(
526 const_cast<char *>(B->getContent().data()));
527 BlockData[E.getOffset() - 2] = 0x8d;
528 LLVM_DEBUG({
529 dbgs() << " Replaced GOT load wih LEA:\n ";
530 printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind()));
531 dbgs() << "\n";
532 });
533 }
534 } else if (E.getKind() == x86_64::BranchPCRel32ToPtrJumpStubRelaxable) {
535 auto &StubBlock = E.getTarget().getBlock();
536 assert(StubBlock.getSize() == sizeof(x86_64::PointerJumpStubContent) &&
537 "Stub block should be stub sized");
538 assert(StubBlock.edges_size() == 1 &&
539 "Stub block should only have one outgoing edge");
540
541 auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
542 assert(GOTBlock.getSize() == G.getPointerSize() &&
543 "GOT block should be pointer sized");
544 assert(GOTBlock.edges_size() == 1 &&
545 "GOT block should only have one outgoing edge");
546
547 auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
548 JITTargetAddress EdgeAddr = B->getAddress() + E.getOffset();
549 JITTargetAddress TargetAddr = GOTTarget.getAddress();
550
551 int64_t Displacement = TargetAddr - EdgeAddr + 4;
552 if (Displacement >= std::numeric_limits<int32_t>::min() &&
553 Displacement <= std::numeric_limits<int32_t>::max()) {
554 E.setKind(x86_64::BranchPCRel32);
555 E.setTarget(GOTTarget);
556 LLVM_DEBUG({
557 dbgs() << " Replaced stub branch with direct branch:\n ";
558 printEdge(dbgs(), *B, E, x86_64::getEdgeKindName(E.getKind()));
559 dbgs() << "\n";
560 });
561 }
562 }
563
564 return Error::success();
565 }
566
567 namespace llvm {
568 namespace jitlink {
569
570 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
571 friend class JITLinker<MachOJITLinker_x86_64>;
572
573 public:
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration PassConfig)574 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
575 std::unique_ptr<LinkGraph> G,
576 PassConfiguration PassConfig)
577 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
578
579 private:
applyFixup(LinkGraph & G,Block & B,const Edge & E,char * BlockWorkingMem) const580 Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
581 char *BlockWorkingMem) const {
582 return x86_64::applyFixup(G, B, E, BlockWorkingMem);
583 }
584 };
585
586 Expected<std::unique_ptr<LinkGraph>>
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer)587 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
588 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
589 if (!MachOObj)
590 return MachOObj.takeError();
591 return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
592 }
593
link_MachO_x86_64(std::unique_ptr<LinkGraph> G,std::unique_ptr<JITLinkContext> Ctx)594 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
595 std::unique_ptr<JITLinkContext> Ctx) {
596
597 PassConfiguration Config;
598
599 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
600 // Add eh-frame passses.
601 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
602 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
603
604 // Add a mark-live pass.
605 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
606 Config.PrePrunePasses.push_back(std::move(MarkLive));
607 else
608 Config.PrePrunePasses.push_back(markAllSymbolsLive);
609
610 // Add an in-place GOT/Stubs pass.
611 Config.PostPrunePasses.push_back(
612 PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass);
613
614 // Add GOT/Stubs optimizer pass.
615 Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
616 }
617
618 if (auto Err = Ctx->modifyPassConfig(*G, Config))
619 return Ctx->notifyFailed(std::move(Err));
620
621 // Construct a JITLinker and run the link function.
622 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
623 }
624
createEHFrameSplitterPass_MachO_x86_64()625 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
626 return EHFrameSplitter("__TEXT,__eh_frame");
627 }
628
createEHFrameEdgeFixerPass_MachO_x86_64()629 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
630 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
631 x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
632 }
633
634 } // end namespace jitlink
635 } // end namespace llvm
636