1 | //===-------------- MachO.cpp - JIT linker function for MachO -------------===// |
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 jit-link function. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/ExecutionEngine/JITLink/MachO.h" |
14 | |
15 | #include "llvm/BinaryFormat/MachO.h" |
16 | #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h" |
17 | #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h" |
18 | #include "llvm/Support/Format.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | #define DEBUG_TYPE "jitlink" |
23 | |
24 | namespace llvm { |
25 | namespace jitlink { |
26 | |
27 | Expected<std::unique_ptr<LinkGraph>> |
28 | createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer, |
29 | std::shared_ptr<orc::SymbolStringPool> SSP) { |
30 | StringRef Data = ObjectBuffer.getBuffer(); |
31 | if (Data.size() < 4) |
32 | return make_error<JITLinkError>(Args: "Truncated MachO buffer \"" + |
33 | ObjectBuffer.getBufferIdentifier() + "\"" ); |
34 | |
35 | uint32_t Magic; |
36 | memcpy(dest: &Magic, src: Data.data(), n: sizeof(uint32_t)); |
37 | LLVM_DEBUG({ |
38 | dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic) |
39 | << ", identifier = \"" << ObjectBuffer.getBufferIdentifier() |
40 | << "\"\n" ; |
41 | }); |
42 | |
43 | if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) |
44 | return make_error<JITLinkError>(Args: "MachO 32-bit platforms not supported" ); |
45 | else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) { |
46 | |
47 | if (Data.size() < sizeof(MachO::mach_header_64)) |
48 | return make_error<JITLinkError>(Args: "Truncated MachO buffer \"" + |
49 | ObjectBuffer.getBufferIdentifier() + |
50 | "\"" ); |
51 | |
52 | // Read the CPU type from the header. |
53 | uint32_t CPUType; |
54 | memcpy(dest: &CPUType, src: Data.data() + 4, n: sizeof(uint32_t)); |
55 | if (Magic == MachO::MH_CIGAM_64) |
56 | CPUType = llvm::byteswap<uint32_t>(V: CPUType); |
57 | |
58 | LLVM_DEBUG({ |
59 | dbgs() << "jitLink_MachO: cputype = " << format("0x%08" PRIx32, CPUType) |
60 | << "\n" ; |
61 | }); |
62 | |
63 | switch (CPUType) { |
64 | case MachO::CPU_TYPE_ARM64: |
65 | return createLinkGraphFromMachOObject_arm64(ObjectBuffer, SSP: std::move(SSP)); |
66 | case MachO::CPU_TYPE_X86_64: |
67 | return createLinkGraphFromMachOObject_x86_64(ObjectBuffer, |
68 | SSP: std::move(SSP)); |
69 | } |
70 | return make_error<JITLinkError>(Args: "MachO-64 CPU type not valid" ); |
71 | } else |
72 | return make_error<JITLinkError>(Args: "Unrecognized MachO magic value" ); |
73 | } |
74 | |
75 | void link_MachO(std::unique_ptr<LinkGraph> G, |
76 | std::unique_ptr<JITLinkContext> Ctx) { |
77 | |
78 | switch (G->getTargetTriple().getArch()) { |
79 | case Triple::aarch64: |
80 | return link_MachO_arm64(G: std::move(G), Ctx: std::move(Ctx)); |
81 | case Triple::x86_64: |
82 | return link_MachO_x86_64(G: std::move(G), Ctx: std::move(Ctx)); |
83 | default: |
84 | Ctx->notifyFailed(Err: make_error<JITLinkError>(Args: "MachO-64 CPU type not valid" )); |
85 | return; |
86 | } |
87 | } |
88 | |
89 | template <typename MachOHeaderType> |
90 | static Expected<Block &> (LinkGraph &G, Section &Sec) { |
91 | auto &B = G.createMutableContentBlock(Parent&: Sec, ContentSize: sizeof(MachOHeaderType), |
92 | Address: orc::ExecutorAddr(), Alignment: 8, AlignmentOffset: 0, ZeroInitialize: true); |
93 | MachOHeaderType Hdr; |
94 | Hdr.magic = G.getPointerSize() == 4 ? MachO::MH_MAGIC : MachO::MH_MAGIC_64; |
95 | if (auto CPUType = MachO::getCPUType(T: G.getTargetTriple())) |
96 | Hdr.cputype = *CPUType; |
97 | else |
98 | return CPUType.takeError(); |
99 | if (auto CPUSubType = MachO::getCPUSubType(T: G.getTargetTriple())) |
100 | Hdr.cpusubtype = *CPUSubType; |
101 | else |
102 | return CPUSubType.takeError(); |
103 | Hdr.filetype = MachO::MH_OBJECT; |
104 | |
105 | if (G.getEndianness() != endianness::native) |
106 | MachO::swapStruct(Hdr); |
107 | |
108 | memcpy(B.getAlreadyMutableContent().data(), &Hdr, sizeof(Hdr)); |
109 | |
110 | return B; |
111 | } |
112 | |
113 | Expected<Symbol &> (LinkGraph &G) { |
114 | StringRef ("__TEXT,__lcl_macho_hdr" ); |
115 | Section *Sec = G.findSectionByName(Name: LocalHeaderSectionName); |
116 | if (Sec) { |
117 | assert(Sec->blocks_size() == 1 && "Unexpected number of blocks" ); |
118 | assert(Sec->symbols_size() == 1 && "Unexpected number of symbols" ); |
119 | auto &Sym = **Sec->symbols().begin(); |
120 | assert(Sym.getOffset() == 0 && "Symbol not at start of header block" ); |
121 | return Sym; |
122 | } |
123 | |
124 | // Create the local header section, move all other sections up in the |
125 | // section ordering to ensure that it's laid out first. |
126 | for (auto &Sec : G.sections()) |
127 | Sec.setOrdinal(Sec.getOrdinal() + 1); |
128 | |
129 | Sec = &G.createSection(Name: LocalHeaderSectionName, Prot: orc::MemProt::Read); |
130 | |
131 | Sec->setOrdinal(0); |
132 | |
133 | Block *B = nullptr; |
134 | switch (G.getTargetTriple().getArch()) { |
135 | case Triple::aarch64: |
136 | case Triple::x86_64: |
137 | if (auto BOrErr = createLocalHeaderBlock<MachO::mach_header_64>(G, Sec&: *Sec)) |
138 | B = &*BOrErr; |
139 | else |
140 | return BOrErr.takeError(); |
141 | break; |
142 | default: |
143 | return make_error<JITLinkError>(Args: "Cannot create local Mach-O header for " + |
144 | G.getName() + ": unsupported triple " + |
145 | G.getTargetTriple().str()); |
146 | } |
147 | |
148 | return G.addAnonymousSymbol(Content&: *B, Offset: 0, Size: B->getSize(), IsCallable: false, IsLive: false); |
149 | } |
150 | |
151 | } // end namespace jitlink |
152 | } // end namespace llvm |
153 | |