[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / lib / ExecutionEngine / JITLink / MachO_x86_64.cpp
blob82afaa3aa3c554e4d91a7991bd105ca48b282171
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.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
14 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
16 #include "MachOLinkGraphBuilder.h"
17 #include "PerGraphGOTAndPLTStubsBuilder.h"
19 #define DEBUG_TYPE "jitlink"
21 using namespace llvm;
22 using namespace llvm::jitlink;
24 namespace {
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) {}
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,
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;
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;
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;
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));
116 using PairRelocInfo = std::tuple<Edge::Kind, Symbol *, uint64_t>;
118 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
119 // returns the edge kind and addend to be used.
120 Expected<PairRelocInfo> parsePairRelocation(
121 Block &BlockToFix, MachONormalizedRelocationType SubtractorKind,
122 const MachO::relocation_info &SubRI, orc::ExecutorAddr FixupAddress,
123 const char *FixupContent, object::relocation_iterator &UnsignedRelItr,
124 object::relocation_iterator &RelEnd) {
125 using namespace support;
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");
133 if (UnsignedRelItr == RelEnd)
134 return make_error<JITLinkError>("x86_64 SUBTRACTOR without paired "
135 "UNSIGNED relocation");
137 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
139 if (SubRI.r_address != UnsignedRI.r_address)
140 return make_error<JITLinkError>("x86_64 SUBTRACTOR and paired UNSIGNED "
141 "point to different addresses");
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");
147 Symbol *FromSymbol;
148 if (auto FromSymbolOrErr = findSymbolByIndex(SubRI.r_symbolnum))
149 FromSymbol = FromSymbolOrErr->GraphSymbol;
150 else
151 return FromSymbolOrErr.takeError();
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;
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, ToSymbolSec->Address);
174 assert(ToSymbol && "No symbol for section");
175 FixupValue -= ToSymbol->getAddress().getValue();
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)");
198 return PairRelocInfo(DeltaKind, TargetSymbol, Addend);
201 Error addRelocations() override {
202 using namespace support;
203 auto &Obj = getObject();
205 LLVM_DEBUG(dbgs() << "Processing relocations:\n");
207 for (auto &S : Obj.sections()) {
209 orc::ExecutorAddr SectionAddress(S.getAddress());
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;
219 auto NSec =
220 findSectionByIndex(Obj.getSectionIndex(S.getRawDataRefImpl()));
221 if (!NSec)
222 return NSec.takeError();
224 // Skip relocations for MachO sections without corresponding graph
225 // sections.
227 if (!NSec->GraphSection) {
228 LLVM_DEBUG({
229 dbgs() << " Skipping relocations for MachO section "
230 << NSec->SegName << "/" << NSec->SectName
231 << " which has no associated graph section\n";
233 continue;
237 // Add relocations for section.
238 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
239 RelItr != RelEnd; ++RelItr) {
241 MachO::relocation_info RI = getRelocationInfo(RelItr);
243 // Find the address of the value to fix up.
244 auto FixupAddress = SectionAddress + (uint32_t)RI.r_address;
246 LLVM_DEBUG({
247 dbgs() << " " << NSec->SectName << " + "
248 << formatv("{0:x8}", RI.r_address) << ":\n";
251 // Find the block that the fixup points to.
252 Block *BlockToFix = nullptr;
254 auto SymbolToFixOrErr = findSymbolByAddress(*NSec, FixupAddress);
255 if (!SymbolToFixOrErr)
256 return SymbolToFixOrErr.takeError();
257 BlockToFix = &SymbolToFixOrErr->getBlock();
260 if (FixupAddress + orc::ExecutorAddrDiff(1ULL << RI.r_length) >
261 BlockToFix->getAddress() + BlockToFix->getContent().size())
262 return make_error<JITLinkError>(
263 "Relocation extends past end of fixup block");
265 // Get a pointer to the fixup content.
266 const char *FixupContent = BlockToFix->getContent().data() +
267 (FixupAddress - BlockToFix->getAddress());
269 size_t FixupOffset = FixupAddress - BlockToFix->getAddress();
271 // The target symbol and addend will be populated by the switch below.
272 Symbol *TargetSymbol = nullptr;
273 uint64_t Addend = 0;
275 // Validate the relocation kind.
276 auto MachORelocKind = getRelocKind(RI);
277 if (!MachORelocKind)
278 return MachORelocKind.takeError();
280 Edge::Kind Kind = Edge::Invalid;
282 switch (*MachORelocKind) {
283 case MachOBranch32:
284 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
285 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
286 else
287 return TargetSymbolOrErr.takeError();
288 Addend = *(const little32_t *)FixupContent;
289 Kind = x86_64::BranchPCRel32;
290 break;
291 case MachOPCRel32:
292 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
293 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
294 else
295 return TargetSymbolOrErr.takeError();
296 Addend = *(const little32_t *)FixupContent - 4;
297 Kind = x86_64::Delta32;
298 break;
299 case MachOPCRel32GOTLoad:
300 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
301 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
302 else
303 return TargetSymbolOrErr.takeError();
304 Addend = *(const little32_t *)FixupContent;
305 Kind = x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
306 if (FixupOffset < 3)
307 return make_error<JITLinkError>("GOTLD at invalid offset " +
308 formatv("{0}", FixupOffset));
309 break;
310 case MachOPCRel32GOT:
311 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
312 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
313 else
314 return TargetSymbolOrErr.takeError();
315 Addend = *(const little32_t *)FixupContent - 4;
316 Kind = x86_64::RequestGOTAndTransformToDelta32;
317 break;
318 case MachOPCRel32TLV:
319 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
320 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
321 else
322 return TargetSymbolOrErr.takeError();
323 Addend = *(const little32_t *)FixupContent;
324 Kind = x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable;
325 if (FixupOffset < 3)
326 return make_error<JITLinkError>("TLV at invalid offset " +
327 formatv("{0}", FixupOffset));
328 break;
329 case MachOPointer32:
330 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
331 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
332 else
333 return TargetSymbolOrErr.takeError();
334 Addend = *(const ulittle32_t *)FixupContent;
335 Kind = x86_64::Pointer32;
336 break;
337 case MachOPointer64:
338 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
339 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
340 else
341 return TargetSymbolOrErr.takeError();
342 Addend = *(const ulittle64_t *)FixupContent;
343 Kind = x86_64::Pointer64;
344 break;
345 case MachOPointer64Anon: {
346 orc::ExecutorAddr TargetAddress(*(const ulittle64_t *)FixupContent);
347 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
348 if (!TargetNSec)
349 return TargetNSec.takeError();
350 if (auto TargetSymbolOrErr =
351 findSymbolByAddress(*TargetNSec, TargetAddress))
352 TargetSymbol = &*TargetSymbolOrErr;
353 else
354 return TargetSymbolOrErr.takeError();
355 Addend = TargetAddress - TargetSymbol->getAddress();
356 Kind = x86_64::Pointer64;
357 break;
359 case MachOPCRel32Minus1:
360 case MachOPCRel32Minus2:
361 case MachOPCRel32Minus4:
362 if (auto TargetSymbolOrErr = findSymbolByIndex(RI.r_symbolnum))
363 TargetSymbol = TargetSymbolOrErr->GraphSymbol;
364 else
365 return TargetSymbolOrErr.takeError();
366 Addend = *(const little32_t *)FixupContent - 4;
367 Kind = x86_64::Delta32;
368 break;
369 case MachOPCRel32Anon: {
370 orc::ExecutorAddr TargetAddress(FixupAddress + 4 +
371 *(const little32_t *)FixupContent);
372 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
373 if (!TargetNSec)
374 return TargetNSec.takeError();
375 if (auto TargetSymbolOrErr =
376 findSymbolByAddress(*TargetNSec, TargetAddress))
377 TargetSymbol = &*TargetSymbolOrErr;
378 else
379 return TargetSymbolOrErr.takeError();
380 Addend = TargetAddress - TargetSymbol->getAddress() - 4;
381 Kind = x86_64::Delta32;
382 break;
384 case MachOPCRel32Minus1Anon:
385 case MachOPCRel32Minus2Anon:
386 case MachOPCRel32Minus4Anon: {
387 orc::ExecutorAddrDiff Delta =
388 4 + orc::ExecutorAddrDiff(
389 1ULL << (*MachORelocKind - MachOPCRel32Minus1Anon));
390 orc::ExecutorAddr TargetAddress =
391 FixupAddress + Delta + *(const little32_t *)FixupContent;
392 auto TargetNSec = findSectionByIndex(RI.r_symbolnum - 1);
393 if (!TargetNSec)
394 return TargetNSec.takeError();
395 if (auto TargetSymbolOrErr =
396 findSymbolByAddress(*TargetNSec, TargetAddress))
397 TargetSymbol = &*TargetSymbolOrErr;
398 else
399 return TargetSymbolOrErr.takeError();
400 Addend = TargetAddress - TargetSymbol->getAddress() - Delta;
401 Kind = x86_64::Delta32;
402 break;
404 case MachOSubtractor32:
405 case MachOSubtractor64: {
406 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
407 // parsePairRelocation handles the paired reloc, and returns the
408 // edge kind to be used (either Delta32/Delta64, or
409 // NegDelta32/NegDelta64, depending on the direction of the
410 // subtraction) along with the addend.
411 auto PairInfo =
412 parsePairRelocation(*BlockToFix, *MachORelocKind, RI,
413 FixupAddress, FixupContent, ++RelItr, RelEnd);
414 if (!PairInfo)
415 return PairInfo.takeError();
416 std::tie(Kind, TargetSymbol, Addend) = *PairInfo;
417 assert(TargetSymbol && "No target symbol from parsePairRelocation?");
418 break;
422 LLVM_DEBUG({
423 dbgs() << " ";
424 Edge GE(Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
425 Addend);
426 printEdge(dbgs(), *BlockToFix, GE, x86_64::getEdgeKindName(Kind));
427 dbgs() << "\n";
429 BlockToFix->addEdge(Kind, FixupAddress - BlockToFix->getAddress(),
430 *TargetSymbol, Addend);
433 return Error::success();
437 Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
438 x86_64::GOTTableManager GOT;
439 x86_64::PLTTableManager PLT(GOT);
440 visitExistingEdges(G, GOT, PLT);
441 return Error::success();
444 } // namespace
446 namespace llvm {
447 namespace jitlink {
449 class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
450 friend class JITLinker<MachOJITLinker_x86_64>;
452 public:
453 MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
454 std::unique_ptr<LinkGraph> G,
455 PassConfiguration PassConfig)
456 : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
458 private:
459 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
460 return x86_64::applyFixup(G, B, E, nullptr);
464 Expected<std::unique_ptr<LinkGraph>>
465 createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
466 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
467 if (!MachOObj)
468 return MachOObj.takeError();
469 return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
472 void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
473 std::unique_ptr<JITLinkContext> Ctx) {
475 PassConfiguration Config;
477 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
478 // Add eh-frame passses.
479 Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64());
480 Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64());
482 // Add compact unwind splitter pass.
483 Config.PrePrunePasses.push_back(
484 CompactUnwindSplitter("__LD,__compact_unwind"));
486 // Add a mark-live pass.
487 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
488 Config.PrePrunePasses.push_back(std::move(MarkLive));
489 else
490 Config.PrePrunePasses.push_back(markAllSymbolsLive);
492 // Add an in-place GOT/Stubs pass.
493 Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
495 // Add GOT/Stubs optimizer pass.
496 Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
499 if (auto Err = Ctx->modifyPassConfig(*G, Config))
500 return Ctx->notifyFailed(std::move(Err));
502 // Construct a JITLinker and run the link function.
503 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
506 LinkGraphPassFunction createEHFrameSplitterPass_MachO_x86_64() {
507 return EHFrameSplitter("__TEXT,__eh_frame");
510 LinkGraphPassFunction createEHFrameEdgeFixerPass_MachO_x86_64() {
511 return EHFrameEdgeFixer("__TEXT,__eh_frame", x86_64::PointerSize,
512 x86_64::Delta64, x86_64::Delta32, x86_64::NegDelta32);
515 } // end namespace jitlink
516 } // end namespace llvm