llvm.org GIT mirror llvm / 6ea6117
[JITLink] Remove a lot of reduntant 'JITLink_' prefixes. NFC. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358869 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 5 months ago
21 changed file(s) with 1651 addition(s) and 1647 deletion(s). Raw diff Collapse all Expand all
0 //===--------- EHFrameSupport.h - JITLink eh-frame utils --------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // EHFrame registration support for JITLink.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
14
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/Support/Error.h"
19
20 namespace llvm {
21 namespace jitlink {
22
23 /// Registers all FDEs in the given eh-frame section with the current process.
24 Error registerEHFrameSection(const void *EHFrameSectionAddr);
25
26 /// Deregisters all FDEs in the given eh-frame section with the current process.
27 Error deregisterEHFrameSection(const void *EHFrameSectionAddr);
28
29 /// Creates a pass that records the address of the EH frame section. If no
30 /// eh-frame section is found, it will set EHFrameAddr to zero.
31 ///
32 /// Authors of JITLinkContexts can use this function to register a post-fixup
33 /// pass that records the address of the eh-frame section. This address can
34 /// be used after finalization to register and deregister the frame.
35 AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
36 JITTargetAddress &EHFrameAddr);
37
38 } // end namespace jitlink
39 } // end namespace llvm
40
41 #endif // LLVM_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORT_H
+0
-42
include/llvm/ExecutionEngine/JITLink/JITLink_EHFrameSupport.h less more
None //===----- JITLink_EHFrameSupport.h - JITLink eh-frame utils ----*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // EHFrame registration support for JITLink.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
14
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/Support/Error.h"
19
20 namespace llvm {
21 namespace jitlink {
22
23 /// Registers all FDEs in the given eh-frame section with the current process.
24 Error registerEHFrameSection(const void *EHFrameSectionAddr);
25
26 /// Deregisters all FDEs in the given eh-frame section with the current process.
27 Error deregisterEHFrameSection(const void *EHFrameSectionAddr);
28
29 /// Creates a pass that records the address of the EH frame section. If no
30 /// eh-frame section is found, it will set EHFrameAddr to zero.
31 ///
32 /// Authors of JITLinkContexts can use this function to register a post-fixup
33 /// pass that records the address of the eh-frame section. This address can
34 /// be used after finalization to register and deregister the frame.
35 AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
36 JITTargetAddress &EHFrameAddr);
37
38 } // end namespace jitlink
39 } // end namespace llvm
40
41 #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORT_H
+0
-30
include/llvm/ExecutionEngine/JITLink/JITLink_MachO.h less more
None //===--- JITLink_MachO.h - Generic JIT link function for MachO --*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Generic jit-link functions for MachO.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_H
14
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16
17 namespace llvm {
18 namespace jitlink {
19
20 /// jit-link the given ObjBuffer, which must be a MachO object file.
21 ///
22 /// Uses conservative defaults for GOT and stub handling based on the target
23 /// platform.
24 void jitLink_MachO(std::unique_ptr Ctx);
25
26 } // end namespace jitlink
27 } // end namespace llvm
28
29 #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
+0
-63
include/llvm/ExecutionEngine/JITLink/JITLink_MachO_x86_64.h less more
None //===--- JITLink_MachO_x86_64.h - JIT link functions for MachO --*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // jit-link functions for MachO/x86-64.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
14
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16
17 namespace llvm {
18 namespace jitlink {
19
20 namespace MachO_x86_64_Edges {
21
22 enum MachOX86RelocationKind : Edge::Kind {
23 Branch32 = Edge::FirstRelocation,
24 Pointer64,
25 Pointer64Anon,
26 PCRel32,
27 PCRel32Minus1,
28 PCRel32Minus2,
29 PCRel32Minus4,
30 PCRel32Anon,
31 PCRel32Minus1Anon,
32 PCRel32Minus2Anon,
33 PCRel32Minus4Anon,
34 PCRel32GOTLoad,
35 PCRel32GOT,
36 PCRel32TLV,
37 Delta32,
38 Delta64,
39 NegDelta32,
40 NegDelta64,
41 };
42
43 } // namespace MachO_x86_64_Edges
44
45 /// jit-link the given object buffer, which must be a MachO x86-64 object file.
46 ///
47 /// If PrePrunePasses is empty then a default mark-live pass will be inserted
48 /// that will mark all exported atoms live. If PrePrunePasses is not empty, the
49 /// caller is responsible for including a pass to mark atoms as live.
50 ///
51 /// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
52 /// be inserted. If PostPrunePasses is not empty then the caller is responsible
53 /// for including a pass to insert GOT and stub edges.
54 void jitLink_MachO_x86_64(std::unique_ptr Ctx);
55
56 /// Return the string name of the given MachO x86-64 edge kind.
57 StringRef getMachOX86RelocationKindName(Edge::Kind R);
58
59 } // end namespace jitlink
60 } // end namespace llvm
61
62 #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINK_MACHO_X86_64_H
0 //===------- MachO.h - Generic JIT link function for MachO ------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Generic jit-link functions for MachO.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_MACHO_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_MACHO_H
14
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16
17 namespace llvm {
18 namespace jitlink {
19
20 /// jit-link the given ObjBuffer, which must be a MachO object file.
21 ///
22 /// Uses conservative defaults for GOT and stub handling based on the target
23 /// platform.
24 void jitLink_MachO(std::unique_ptr Ctx);
25
26 } // end namespace jitlink
27 } // end namespace llvm
28
29 #endif // LLVM_EXECUTIONENGINE_JITLINK_MACHO_H
0 //===--- MachO_x86_64.h - JIT link functions for MachO/x86-64 ---*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // jit-link functions for MachO/x86-64.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_JITLINK_MACHO_X86_64_H
13 #define LLVM_EXECUTIONENGINE_JITLINK_MACHO_X86_64_H
14
15 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
16
17 namespace llvm {
18 namespace jitlink {
19
20 namespace MachO_x86_64_Edges {
21
22 enum MachOX86RelocationKind : Edge::Kind {
23 Branch32 = Edge::FirstRelocation,
24 Pointer64,
25 Pointer64Anon,
26 PCRel32,
27 PCRel32Minus1,
28 PCRel32Minus2,
29 PCRel32Minus4,
30 PCRel32Anon,
31 PCRel32Minus1Anon,
32 PCRel32Minus2Anon,
33 PCRel32Minus4Anon,
34 PCRel32GOTLoad,
35 PCRel32GOT,
36 PCRel32TLV,
37 Delta32,
38 Delta64,
39 NegDelta32,
40 NegDelta64,
41 };
42
43 } // namespace MachO_x86_64_Edges
44
45 /// jit-link the given object buffer, which must be a MachO x86-64 object file.
46 ///
47 /// If PrePrunePasses is empty then a default mark-live pass will be inserted
48 /// that will mark all exported atoms live. If PrePrunePasses is not empty, the
49 /// caller is responsible for including a pass to mark atoms as live.
50 ///
51 /// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
52 /// be inserted. If PostPrunePasses is not empty then the caller is responsible
53 /// for including a pass to insert GOT and stub edges.
54 void jitLink_MachO_x86_64(std::unique_ptr Ctx);
55
56 /// Return the string name of the given MachO x86-64 edge kind.
57 StringRef getMachOX86RelocationKindName(Edge::Kind R);
58
59 } // end namespace jitlink
60 } // end namespace llvm
61
62 #endif // LLVM_EXECUTIONENGINE_JITLINK_MACHO_X86_64_H
0 add_llvm_library(LLVMJITLink
11 JITLink.cpp
22 JITLinkGeneric.cpp
3 JITLink_EHFrameSupport.cpp
4 JITLink_MachO.cpp
5 JITLink_MachO_x86_64.cpp
3 EHFrameSupport.cpp
4 MachO.cpp
5 MachO_x86_64.cpp
66 MachOAtomGraphBuilder.cpp
77
88 DEPENDS
0 //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "EHFrameSupportImpl.h"
10
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/Support/DynamicLibrary.h"
13
14 #define DEBUG_TYPE "jitlink"
15
16 namespace llvm {
17 namespace jitlink {
18
19 EHFrameParser::EHFrameParser(AtomGraph &G, Section &EHFrameSection,
20 StringRef EHFrameContent,
21 JITTargetAddress EHFrameAddress,
22 Edge::Kind FDEToCIERelocKind,
23 Edge::Kind FDEToTargetRelocKind)
24 : G(G), EHFrameSection(EHFrameSection), EHFrameContent(EHFrameContent),
25 EHFrameAddress(EHFrameAddress),
26 EHFrameReader(EHFrameContent, G.getEndianness()),
27 FDEToCIERelocKind(FDEToCIERelocKind),
28 FDEToTargetRelocKind(FDEToTargetRelocKind) {}
29
30 Error EHFrameParser::atomize() {
31 while (!EHFrameReader.empty()) {
32 size_t RecordOffset = EHFrameReader.getOffset();
33
34 LLVM_DEBUG({
35 dbgs() << "Processing eh-frame record at "
36 << format("0x%016" PRIx64, EHFrameAddress + RecordOffset)
37 << " (offset " << RecordOffset << ")\n";
38 });
39
40 size_t CIELength = 0;
41 uint32_t CIELengthField;
42 if (auto Err = EHFrameReader.readInteger(CIELengthField))
43 return Err;
44
45 // Process CIE length/extended-length fields to build the atom.
46 //
47 // The value of these fields describe the length of the *rest* of the CIE
48 // (not including data up to the end of the field itself) so we have to
49 // bump CIELength to include the data up to the end of the field: 4 bytes
50 // for Length, or 12 bytes (4 bytes + 8 bytes) for ExtendedLength.
51 if (CIELengthField == 0) // Length 0 means end of __eh_frame section.
52 break;
53
54 // If the regular length field's value is 0xffffffff, use extended length.
55 if (CIELengthField == 0xffffffff) {
56 uint64_t CIEExtendedLengthField;
57 if (auto Err = EHFrameReader.readInteger(CIEExtendedLengthField))
58 return Err;
59 if (CIEExtendedLengthField > EHFrameReader.bytesRemaining())
60 return make_error("CIE record extends past the end of "
61 "the __eh_frame section");
62 if (CIEExtendedLengthField + 12 > std::numeric_limits::max())
63 return make_error("CIE record too large to process");
64 CIELength = CIEExtendedLengthField + 12;
65 } else {
66 if (CIELengthField > EHFrameReader.bytesRemaining())
67 return make_error("CIE record extends past the end of "
68 "the __eh_frame section");
69 CIELength = CIELengthField + 4;
70 }
71
72 LLVM_DEBUG(dbgs() << " length: " << CIELength << "\n");
73
74 // Add an atom for this record.
75 CurRecordAtom = &G.addAnonymousAtom(
76 EHFrameSection, EHFrameAddress + RecordOffset, G.getPointerSize());
77 CurRecordAtom->setContent(EHFrameContent.substr(RecordOffset, CIELength));
78
79 // Read the CIE Pointer.
80 size_t CIEPointerAddress = EHFrameAddress + EHFrameReader.getOffset();
81 uint32_t CIEPointer;
82 if (auto Err = EHFrameReader.readInteger(CIEPointer))
83 return Err;
84
85 // Based on the CIE pointer value, parse this as a CIE or FDE record.
86 if (CIEPointer == 0) {
87 if (auto Err = processCIE())
88 return Err;
89 } else {
90 if (auto Err = processFDE(CIEPointerAddress, CIEPointer))
91 return Err;
92 }
93
94 EHFrameReader.setOffset(RecordOffset + CIELength);
95 }
96
97 return Error::success();
98 }
99
100 Expected
101 EHFrameParser::parseAugmentationString() {
102 AugmentationInfo AugInfo;
103 uint8_t NextChar;
104 uint8_t *NextField = &AugInfo.Fields[0];
105
106 if (auto Err = EHFrameReader.readInteger(NextChar))
107 return std::move(Err);
108
109 while (NextChar != 0) {
110 switch (NextChar) {
111 case 'z':
112 AugInfo.AugmentationDataPresent = true;
113 break;
114 case 'e':
115 if (auto Err = EHFrameReader.readInteger(NextChar))
116 return std::move(Err);
117 if (NextChar != 'h')
118 return make_error("Unrecognized substring e" +
119 Twine(NextChar) +
120 " in augmentation string");
121 AugInfo.EHDataFieldPresent = true;
122 break;
123 case 'L':
124 case 'P':
125 case 'R':
126 *NextField++ = NextChar;
127 break;
128 default:
129 return make_error("Unrecognized character " +
130 Twine(NextChar) +
131 " in augmentation string");
132 }
133
134 if (auto Err = EHFrameReader.readInteger(NextChar))
135 return std::move(Err);
136 }
137
138 return std::move(AugInfo);
139 }
140
141 Expected EHFrameParser::readAbsolutePointer() {
142 static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
143 "Result must be able to hold a uint64_t");
144 JITTargetAddress Addr;
145 if (G.getPointerSize() == 8) {
146 if (auto Err = EHFrameReader.readInteger(Addr))
147 return std::move(Err);
148 } else if (G.getPointerSize() == 4) {
149 uint32_t Addr32;
150 if (auto Err = EHFrameReader.readInteger(Addr32))
151 return std::move(Err);
152 Addr = Addr32;
153 } else
154 llvm_unreachable("Pointer size is not 32-bit or 64-bit");
155 return Addr;
156 }
157
158 Error EHFrameParser::processCIE() {
159 // Use the dwarf namespace for convenient access to pointer encoding
160 // constants.
161 using namespace dwarf;
162
163 LLVM_DEBUG(dbgs() << " Record is CIE\n");
164
165 /// Reset state for the new CIE.
166 LSDAFieldPresent = false;
167
168 uint8_t Version = 0;
169 if (auto Err = EHFrameReader.readInteger(Version))
170 return Err;
171
172 if (Version != 0x01)
173 return make_error("Bad CIE version " + Twine(Version) +
174 " (should be 0x01) in eh-frame");
175
176 auto AugInfo = parseAugmentationString();
177 if (!AugInfo)
178 return AugInfo.takeError();
179
180 // Skip the EH Data field if present.
181 if (AugInfo->EHDataFieldPresent)
182 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
183 return Err;
184
185 // Read and sanity check the code alignment factor.
186 {
187 uint64_t CodeAlignmentFactor = 0;
188 if (auto Err = EHFrameReader.readULEB128(CodeAlignmentFactor))
189 return Err;
190 if (CodeAlignmentFactor != 1)
191 return make_error("Unsupported CIE code alignment factor " +
192 Twine(CodeAlignmentFactor) +
193 " (expected 1)");
194 }
195
196 // Read and sanity check the data alignment factor.
197 {
198 int64_t DataAlignmentFactor = 0;
199 if (auto Err = EHFrameReader.readSLEB128(DataAlignmentFactor))
200 return Err;
201 if (DataAlignmentFactor != -8)
202 return make_error("Unsupported CIE data alignment factor " +
203 Twine(DataAlignmentFactor) +
204 " (expected -8)");
205 }
206
207 // Skip the return address register field.
208 if (auto Err = EHFrameReader.skip(1))
209 return Err;
210
211 uint64_t AugmentationDataLength = 0;
212 if (auto Err = EHFrameReader.readULEB128(AugmentationDataLength))
213 return Err;
214
215 uint32_t AugmentationDataStartOffset = EHFrameReader.getOffset();
216
217 uint8_t *NextField = &AugInfo->Fields[0];
218 while (uint8_t Field = *NextField++) {
219 switch (Field) {
220 case 'L': {
221 LSDAFieldPresent = true;
222 uint8_t LSDAPointerEncoding;
223 if (auto Err = EHFrameReader.readInteger(LSDAPointerEncoding))
224 return Err;
225 if (LSDAPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
226 return make_error(
227 "Unsupported LSDA pointer encoding " +
228 formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
229 formatv("{0:x16}", CurRecordAtom->getAddress()));
230 break;
231 }
232 case 'P': {
233 uint8_t PersonalityPointerEncoding = 0;
234 if (auto Err = EHFrameReader.readInteger(PersonalityPointerEncoding))
235 return Err;
236 if (PersonalityPointerEncoding !=
237 (DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4))
238 return make_error(
239 "Unspported personality pointer "
240 "encoding " +
241 formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
242 formatv("{0:x16}", CurRecordAtom->getAddress()));
243 uint32_t PersonalityPointerAddress;
244 if (auto Err = EHFrameReader.readInteger(PersonalityPointerAddress))
245 return Err;
246 break;
247 }
248 case 'R': {
249 uint8_t FDEPointerEncoding;
250 if (auto Err = EHFrameReader.readInteger(FDEPointerEncoding))
251 return Err;
252 if (FDEPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
253 return make_error(
254 "Unsupported FDE address pointer "
255 "encoding " +
256 formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
257 formatv("{0:x16}", CurRecordAtom->getAddress()));
258 break;
259 }
260 default:
261 llvm_unreachable("Invalid augmentation string field");
262 }
263 }
264
265 if (EHFrameReader.getOffset() - AugmentationDataStartOffset >
266 AugmentationDataLength)
267 return make_error("Read past the end of the augmentation "
268 "data while parsing fields");
269
270 return Error::success();
271 }
272
273 Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress,
274 uint32_t CIEPointer) {
275 LLVM_DEBUG(dbgs() << " Record is FDE\n");
276
277 LLVM_DEBUG({
278 dbgs() << " CIE pointer: "
279 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
280 });
281
282 auto CIEAtom = G.findAtomByAddress(CIEPointerAddress - CIEPointer);
283 if (!CIEAtom)
284 return CIEAtom.takeError();
285
286 // The CIEPointer looks good. Add a relocation.
287 CurRecordAtom->addEdge(FDEToCIERelocKind,
288 CIEPointerAddress - CurRecordAtom->getAddress(),
289 *CIEAtom, 0);
290
291 // Read and sanity check the PC-start pointer and size.
292 JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset();
293
294 auto PCBeginDelta = readAbsolutePointer();
295 if (!PCBeginDelta)
296 return PCBeginDelta.takeError();
297
298 JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta;
299 LLVM_DEBUG({
300 dbgs() << " PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n";
301 });
302
303 auto *TargetAtom = G.getAtomByAddress(PCBegin);
304
305 if (!TargetAtom)
306 return make_error("FDE PC-begin " +
307 formatv("{0:x16}", PCBegin) +
308 " does not point at atom");
309
310 if (TargetAtom->getAddress() != PCBegin)
311 return make_error(
312 "FDE PC-begin " + formatv("{0:x16}", PCBegin) +
313 " does not point to start of atom at " +
314 formatv("{0:x16}", TargetAtom->getAddress()));
315
316 LLVM_DEBUG(dbgs() << " FDE target: " << *TargetAtom << "\n");
317
318 // The PC-start pointer and size look good. Add relocations.
319 CurRecordAtom->addEdge(FDEToTargetRelocKind,
320 PCBeginAddress - CurRecordAtom->getAddress(),
321 *TargetAtom, 0);
322
323 // Add a keep-alive relocation from the function to the FDE to ensure it is
324 // not dead stripped.
325 TargetAtom->addEdge(Edge::KeepAlive, 0, *CurRecordAtom, 0);
326
327 // Skip over the PC range size field.
328 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
329 return Err;
330
331 if (LSDAFieldPresent) {
332 uint64_t AugmentationDataSize;
333 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
334 return Err;
335 if (AugmentationDataSize != G.getPointerSize())
336 return make_error("Unexpected FDE augmentation data size "
337 "(expected " +
338 Twine(G.getPointerSize()) + ", got " +
339 Twine(AugmentationDataSize) + ")");
340 JITTargetAddress LSDAAddress = EHFrameAddress + EHFrameReader.getOffset();
341 auto LSDADelta = readAbsolutePointer();
342 if (!LSDADelta)
343 return LSDADelta.takeError();
344
345 JITTargetAddress LSDA = LSDAAddress + *LSDADelta;
346
347 auto *LSDAAtom = G.getAtomByAddress(LSDA);
348
349 if (!LSDAAtom)
350 return make_error("FDE LSDA " + formatv("{0:x16}", LSDA) +
351 " does not point at atom");
352
353 if (LSDAAtom->getAddress() != LSDA)
354 return make_error(
355 "FDE LSDA " + formatv("{0:x16}", LSDA) +
356 " does not point to start of atom at " +
357 formatv("{0:x16}", LSDAAtom->getAddress()));
358
359 LLVM_DEBUG(dbgs() << " FDE LSDA: " << *LSDAAtom << "\n");
360
361 // LSDA looks good. Add relocations.
362 CurRecordAtom->addEdge(FDEToTargetRelocKind,
363 LSDAAddress - CurRecordAtom->getAddress(), *LSDAAtom,
364 0);
365 }
366
367 return Error::success();
368 }
369
370 Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
371 StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
372 Edge::Kind FDEToCIERelocKind,
373 Edge::Kind FDEToTargetRelocKind) {
374 return EHFrameParser(G, EHFrameSection, EHFrameContent, EHFrameAddress,
375 FDEToCIERelocKind, FDEToTargetRelocKind)
376 .atomize();
377 }
378
379 // Determine whether we can register EH tables.
380 #if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
381 !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
382 #define HAVE_EHTABLE_SUPPORT 1
383 #else
384 #define HAVE_EHTABLE_SUPPORT 0
385 #endif
386
387 #if HAVE_EHTABLE_SUPPORT
388 extern "C" void __register_frame(const void *);
389 extern "C" void __deregister_frame(const void *);
390
391 Error registerFrameWrapper(const void *P) {
392 __register_frame(P);
393 return Error::success();
394 }
395
396 Error deregisterFrameWrapper(const void *P) {
397 __deregister_frame(P);
398 return Error::success();
399 }
400
401 #else
402
403 // The building compiler does not have __(de)register_frame but
404 // it may be found at runtime in a dynamically-loaded library.
405 // For example, this happens when building LLVM with Visual C++
406 // but using the MingW runtime.
407 static Error registerFrameWrapper(const void *P) {
408 static void((*RegisterFrame)(const void *)) = 0;
409
410 if (!RegisterFrame)
411 *(void **)&RegisterFrame =
412 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
413
414 if (RegisterFrame) {
415 RegisterFrame(P);
416 return Error::success();
417 }
418
419 return make_error("could not register eh-frame: "
420 "__register_frame function not found");
421 }
422
423 static Error deregisterFrameWrapper(const void *P) {
424 static void((*DeregisterFrame)(const void *)) = 0;
425
426 if (!DeregisterFrame)
427 *(void **)&DeregisterFrame =
428 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
429 "__deregister_frame");
430
431 if (DeregisterFrame) {
432 DeregisterFrame(P);
433 return Error::success();
434 }
435
436 return make_error("could not deregister eh-frame: "
437 "__deregister_frame function not found");
438 }
439 #endif
440
441 #ifdef __APPLE__
442
443 template
444 Error walkAppleEHFrameSection(const char *const SectionStart,
445 HandleFDEFn HandleFDE) {
446 const char *CurCFIRecord = SectionStart;
447 uint64_t Size = *reinterpret_cast(CurCFIRecord);
448
449 while (Size != 0) {
450 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
451 if (Size == 0xffffffff)
452 Size = *reinterpret_cast(CurCFIRecord + 4) + 12;
453 else
454 Size += 4;
455 uint32_t Offset = *reinterpret_cast(OffsetField);
456 if (Offset != 0)
457 if (auto Err = HandleFDE(CurCFIRecord))
458 return Err;
459
460 LLVM_DEBUG({
461 dbgs() << "Registering eh-frame section:\n";
462 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
463 << (void *)CurCFIRecord << ": [";
464 for (unsigned I = 0; I < Size; ++I)
465 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
466 dbgs() << " ]\n";
467 });
468 CurCFIRecord += Size;
469
470 Size = *reinterpret_cast(CurCFIRecord);
471 }
472
473 return Error::success();
474 }
475
476 #endif // __APPLE__
477
478 Error registerEHFrameSection(const void *EHFrameSectionAddr) {
479 #ifdef __APPLE__
480 // On Darwin __register_frame has to be called for each FDE entry.
481 return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr),
482 registerFrameWrapper);
483 #else
484 // On Linux __register_frame takes a single argument:
485 // a pointer to the start of the .eh_frame section.
486
487 // How can it find the end? Because crtendS.o is linked
488 // in and it has an .eh_frame section with four zero chars.
489 return registerFrameWrapper(EHFrameSectionAddr);
490 #endif
491 }
492
493 Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
494 #ifdef __APPLE__
495 return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr),
496 deregisterFrameWrapper);
497 #else
498 return deregisterFrameWrapper(EHFrameSectionAddr);
499 #endif
500 }
501
502 AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
503 JITTargetAddress &EHFrameAddr) {
504 const char *EHFrameSectionName = nullptr;
505 if (TT.getObjectFormat() == Triple::MachO)
506 EHFrameSectionName = "__eh_frame";
507 else
508 EHFrameSectionName = ".eh_frame";
509
510 auto RecordEHFrame = [EHFrameSectionName,
511 &EHFrameAddr](AtomGraph &G) -> Error {
512 // Search for a non-empty eh-frame and record the address of the first atom
513 // in it.
514 JITTargetAddress Addr = 0;
515 for (auto &S : G.sections())
516 if (S.getName() == EHFrameSectionName && !S.atoms_empty()) {
517 Addr = (*S.atoms().begin())->getAddress();
518 for (auto *DA : S.atoms())
519 if (DA->getAddress() < Addr)
520 Addr = DA->getAddress();
521 break;
522 }
523
524 EHFrameAddr = Addr;
525 return Error::success();
526 };
527
528 return RecordEHFrame;
529 }
530
531 } // end namespace jitlink
532 } // end namespace llvm
0 //===------- EHFrameSupportImpl.h - JITLink eh-frame utils ------*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // EHFrame registration support for JITLink.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
13 #define LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
14
15 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
16
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/Support/BinaryStreamReader.h"
19
20 namespace llvm {
21 namespace jitlink {
22
23 /// A generic parser for eh-frame sections.
24 ///
25 /// Adds atoms representing CIE and FDE entries, using the given FDE-to-CIE and
26 /// FDEToTarget relocation kinds.
27 class EHFrameParser {
28 public:
29 EHFrameParser(AtomGraph &G, Section &EHFrameSection, StringRef EHFrameContent,
30 JITTargetAddress EHFrameAddress, Edge::Kind FDEToCIERelocKind,
31 Edge::Kind FDEToTargetRelocKind);
32 Error atomize();
33
34 private:
35 struct AugmentationInfo {
36 bool AugmentationDataPresent = false;
37 bool EHDataFieldPresent = false;
38 uint8_t Fields[4] = {0x0, 0x0, 0x0, 0x0};
39 };
40
41 Expected parseAugmentationString();
42 Expected readAbsolutePointer();
43 Error processCIE();
44 Error processFDE(JITTargetAddress CIEPointerAddress, uint32_t CIEPointer);
45
46 AtomGraph &G;
47 Section &EHFrameSection;
48 StringRef EHFrameContent;
49 JITTargetAddress EHFrameAddress;
50 BinaryStreamReader EHFrameReader;
51 DefinedAtom *CurRecordAtom = nullptr;
52 bool LSDAFieldPresent = false;
53 Edge::Kind FDEToCIERelocKind;
54 Edge::Kind FDEToTargetRelocKind;
55 };
56
57 Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
58 StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
59 Edge::Kind FDEToCIERelocKind, Edge::Kind FDEToTargetRelocKind);
60
61 } // end namespace jitlink
62 } // end namespace llvm
63
64 #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_EHFRAMESUPPORTIMPL_H
99 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
1010
1111 #include "llvm/BinaryFormat/Magic.h"
12 #include "llvm/ExecutionEngine/JITLink/JITLink_MachO.h"
12 #include "llvm/ExecutionEngine/JITLink/MachO.h"
1313 #include "llvm/Support/Format.h"
1414 #include "llvm/Support/ManagedStatic.h"
1515 #include "llvm/Support/MemoryBuffer.h"
1010 //===----------------------------------------------------------------------===//
1111
1212 #include "JITLinkGeneric.h"
13 #include "JITLink_EHFrameSupportImpl.h"
13 #include "EHFrameSupportImpl.h"
1414
1515 #include "llvm/Support/BinaryStreamReader.h"
1616 #include "llvm/Support/MemoryBuffer.h"
+0
-533
lib/ExecutionEngine/JITLink/JITLink_EHFrameSupport.cpp less more
None //===-------- JITLink_EHFrameSupport.cpp - JITLink eh-frame utils ---------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "JITLink_EHFrameSupportImpl.h"
10
11 #include "llvm/BinaryFormat/Dwarf.h"
12 #include "llvm/Support/DynamicLibrary.h"
13
14 #define DEBUG_TYPE "jitlink"
15
16 namespace llvm {
17 namespace jitlink {
18
19 EHFrameParser::EHFrameParser(AtomGraph &G, Section &EHFrameSection,
20 StringRef EHFrameContent,
21 JITTargetAddress EHFrameAddress,
22 Edge::Kind FDEToCIERelocKind,
23 Edge::Kind FDEToTargetRelocKind)
24 : G(G), EHFrameSection(EHFrameSection), EHFrameContent(EHFrameContent),
25 EHFrameAddress(EHFrameAddress),
26 EHFrameReader(EHFrameContent, G.getEndianness()),
27 FDEToCIERelocKind(FDEToCIERelocKind),
28 FDEToTargetRelocKind(FDEToTargetRelocKind) {}
29
30 Error EHFrameParser::atomize() {
31 while (!EHFrameReader.empty()) {
32 size_t RecordOffset = EHFrameReader.getOffset();
33
34 LLVM_DEBUG({
35 dbgs() << "Processing eh-frame record at "
36 << format("0x%016" PRIx64, EHFrameAddress + RecordOffset)
37 << " (offset " << RecordOffset << ")\n";
38 });
39
40 size_t CIELength = 0;
41 uint32_t CIELengthField;
42 if (auto Err = EHFrameReader.readInteger(CIELengthField))
43 return Err;
44
45 // Process CIE length/extended-length fields to build the atom.
46 //
47 // The value of these fields describe the length of the *rest* of the CIE
48 // (not including data up to the end of the field itself) so we have to
49 // bump CIELength to include the data up to the end of the field: 4 bytes
50 // for Length, or 12 bytes (4 bytes + 8 bytes) for ExtendedLength.
51 if (CIELengthField == 0) // Length 0 means end of __eh_frame section.
52 break;
53
54 // If the regular length field's value is 0xffffffff, use extended length.
55 if (CIELengthField == 0xffffffff) {
56 uint64_t CIEExtendedLengthField;
57 if (auto Err = EHFrameReader.readInteger(CIEExtendedLengthField))
58 return Err;
59 if (CIEExtendedLengthField > EHFrameReader.bytesRemaining())
60 return make_error("CIE record extends past the end of "
61 "the __eh_frame section");
62 if (CIEExtendedLengthField + 12 > std::numeric_limits::max())
63 return make_error("CIE record too large to process");
64 CIELength = CIEExtendedLengthField + 12;
65 } else {
66 if (CIELengthField > EHFrameReader.bytesRemaining())
67 return make_error("CIE record extends past the end of "
68 "the __eh_frame section");
69 CIELength = CIELengthField + 4;
70 }
71
72 LLVM_DEBUG(dbgs() << " length: " << CIELength << "\n");
73
74 // Add an atom for this record.
75 CurRecordAtom = &G.addAnonymousAtom(
76 EHFrameSection, EHFrameAddress + RecordOffset, G.getPointerSize());
77 CurRecordAtom->setContent(EHFrameContent.substr(RecordOffset, CIELength));
78
79 // Read the CIE Pointer.
80 size_t CIEPointerAddress = EHFrameAddress + EHFrameReader.getOffset();
81 uint32_t CIEPointer;
82 if (auto Err = EHFrameReader.readInteger(CIEPointer))
83 return Err;
84
85 // Based on the CIE pointer value, parse this as a CIE or FDE record.
86 if (CIEPointer == 0) {
87 if (auto Err = processCIE())
88 return Err;
89 } else {
90 if (auto Err = processFDE(CIEPointerAddress, CIEPointer))
91 return Err;
92 }
93
94 EHFrameReader.setOffset(RecordOffset + CIELength);
95 }
96
97 return Error::success();
98 }
99
100 Expected
101 EHFrameParser::parseAugmentationString() {
102 AugmentationInfo AugInfo;
103 uint8_t NextChar;
104 uint8_t *NextField = &AugInfo.Fields[0];
105
106 if (auto Err = EHFrameReader.readInteger(NextChar))
107 return std::move(Err);
108
109 while (NextChar != 0) {
110 switch (NextChar) {
111 case 'z':
112 AugInfo.AugmentationDataPresent = true;
113 break;
114 case 'e':
115 if (auto Err = EHFrameReader.readInteger(NextChar))
116 return std::move(Err);
117 if (NextChar != 'h')
118 return make_error("Unrecognized substring e" +
119 Twine(NextChar) +
120 " in augmentation string");
121 AugInfo.EHDataFieldPresent = true;
122 break;
123 case 'L':
124 case 'P':
125 case 'R':
126 *NextField++ = NextChar;
127 break;
128 default:
129 return make_error("Unrecognized character " +
130 Twine(NextChar) +
131 " in augmentation string");
132 }
133
134 if (auto Err = EHFrameReader.readInteger(NextChar))
135 return std::move(Err);
136 }
137
138 return std::move(AugInfo);
139 }
140
141 Expected EHFrameParser::readAbsolutePointer() {
142 static_assert(sizeof(JITTargetAddress) == sizeof(uint64_t),
143 "Result must be able to hold a uint64_t");
144 JITTargetAddress Addr;
145 if (G.getPointerSize() == 8) {
146 if (auto Err = EHFrameReader.readInteger(Addr))
147 return std::move(Err);
148 } else if (G.getPointerSize() == 4) {
149 uint32_t Addr32;
150 if (auto Err = EHFrameReader.readInteger(Addr32))
151 return std::move(Err);
152 Addr = Addr32;
153 } else
154 llvm_unreachable("Pointer size is not 32-bit or 64-bit");
155 return Addr;
156 }
157
158 Error EHFrameParser::processCIE() {
159 // Use the dwarf namespace for convenient access to pointer encoding
160 // constants.
161 using namespace dwarf;
162
163 LLVM_DEBUG(dbgs() << " Record is CIE\n");
164
165 /// Reset state for the new CIE.
166 LSDAFieldPresent = false;
167
168 uint8_t Version = 0;
169 if (auto Err = EHFrameReader.readInteger(Version))
170 return Err;
171
172 if (Version != 0x01)
173 return make_error("Bad CIE version " + Twine(Version) +
174 " (should be 0x01) in eh-frame");
175
176 auto AugInfo = parseAugmentationString();
177 if (!AugInfo)
178 return AugInfo.takeError();
179
180 // Skip the EH Data field if present.
181 if (AugInfo->EHDataFieldPresent)
182 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
183 return Err;
184
185 // Read and sanity check the code alignment factor.
186 {
187 uint64_t CodeAlignmentFactor = 0;
188 if (auto Err = EHFrameReader.readULEB128(CodeAlignmentFactor))
189 return Err;
190 if (CodeAlignmentFactor != 1)
191 return make_error("Unsupported CIE code alignment factor " +
192 Twine(CodeAlignmentFactor) +
193 " (expected 1)");
194 }
195
196 // Read and sanity check the data alignment factor.
197 {
198 int64_t DataAlignmentFactor = 0;
199 if (auto Err = EHFrameReader.readSLEB128(DataAlignmentFactor))
200 return Err;
201 if (DataAlignmentFactor != -8)
202 return make_error("Unsupported CIE data alignment factor " +
203 Twine(DataAlignmentFactor) +
204 " (expected -8)");
205 }
206
207 // Skip the return address register field.
208 if (auto Err = EHFrameReader.skip(1))
209 return Err;
210
211 uint64_t AugmentationDataLength = 0;
212 if (auto Err = EHFrameReader.readULEB128(AugmentationDataLength))
213 return Err;
214
215 uint32_t AugmentationDataStartOffset = EHFrameReader.getOffset();
216
217 uint8_t *NextField = &AugInfo->Fields[0];
218 while (uint8_t Field = *NextField++) {
219 switch (Field) {
220 case 'L': {
221 LSDAFieldPresent = true;
222 uint8_t LSDAPointerEncoding;
223 if (auto Err = EHFrameReader.readInteger(LSDAPointerEncoding))
224 return Err;
225 if (LSDAPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
226 return make_error(
227 "Unsupported LSDA pointer encoding " +
228 formatv("{0:x2}", LSDAPointerEncoding) + " in CIE at " +
229 formatv("{0:x16}", CurRecordAtom->getAddress()));
230 break;
231 }
232 case 'P': {
233 uint8_t PersonalityPointerEncoding = 0;
234 if (auto Err = EHFrameReader.readInteger(PersonalityPointerEncoding))
235 return Err;
236 if (PersonalityPointerEncoding !=
237 (DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4))
238 return make_error(
239 "Unspported personality pointer "
240 "encoding " +
241 formatv("{0:x2}", PersonalityPointerEncoding) + " in CIE at " +
242 formatv("{0:x16}", CurRecordAtom->getAddress()));
243 uint32_t PersonalityPointerAddress;
244 if (auto Err = EHFrameReader.readInteger(PersonalityPointerAddress))
245 return Err;
246 break;
247 }
248 case 'R': {
249 uint8_t FDEPointerEncoding;
250 if (auto Err = EHFrameReader.readInteger(FDEPointerEncoding))
251 return Err;
252 if (FDEPointerEncoding != (DW_EH_PE_pcrel | DW_EH_PE_absptr))
253 return make_error(
254 "Unsupported FDE address pointer "
255 "encoding " +
256 formatv("{0:x2}", FDEPointerEncoding) + " in CIE at " +
257 formatv("{0:x16}", CurRecordAtom->getAddress()));
258 break;
259 }
260 default:
261 llvm_unreachable("Invalid augmentation string field");
262 }
263 }
264
265 if (EHFrameReader.getOffset() - AugmentationDataStartOffset >
266 AugmentationDataLength)
267 return make_error("Read past the end of the augmentation "
268 "data while parsing fields");
269
270 return Error::success();
271 }
272
273 Error EHFrameParser::processFDE(JITTargetAddress CIEPointerAddress,
274 uint32_t CIEPointer) {
275 LLVM_DEBUG(dbgs() << " Record is FDE\n");
276
277 LLVM_DEBUG({
278 dbgs() << " CIE pointer: "
279 << format("0x%016" PRIx64, CIEPointerAddress - CIEPointer) << "\n";
280 });
281
282 auto CIEAtom = G.findAtomByAddress(CIEPointerAddress - CIEPointer);
283 if (!CIEAtom)
284 return CIEAtom.takeError();
285
286 // The CIEPointer looks good. Add a relocation.
287 CurRecordAtom->addEdge(FDEToCIERelocKind,
288 CIEPointerAddress - CurRecordAtom->getAddress(),
289 *CIEAtom, 0);
290
291 // Read and sanity check the PC-start pointer and size.
292 JITTargetAddress PCBeginAddress = EHFrameAddress + EHFrameReader.getOffset();
293
294 auto PCBeginDelta = readAbsolutePointer();
295 if (!PCBeginDelta)
296 return PCBeginDelta.takeError();
297
298 JITTargetAddress PCBegin = PCBeginAddress + *PCBeginDelta;
299 LLVM_DEBUG({
300 dbgs() << " PC begin: " << format("0x%016" PRIx64, PCBegin) << "\n";
301 });
302
303 auto *TargetAtom = G.getAtomByAddress(PCBegin);
304
305 if (!TargetAtom)
306 return make_error("FDE PC-begin " +
307 formatv("{0:x16}", PCBegin) +
308 " does not point at atom");
309
310 if (TargetAtom->getAddress() != PCBegin)
311 return make_error(
312 "FDE PC-begin " + formatv("{0:x16}", PCBegin) +
313 " does not point to start of atom at " +
314 formatv("{0:x16}", TargetAtom->getAddress()));
315
316 LLVM_DEBUG(dbgs() << " FDE target: " << *TargetAtom << "\n");
317
318 // The PC-start pointer and size look good. Add relocations.
319 CurRecordAtom->addEdge(FDEToTargetRelocKind,
320 PCBeginAddress - CurRecordAtom->getAddress(),
321 *TargetAtom, 0);
322
323 // Add a keep-alive relocation from the function to the FDE to ensure it is
324 // not dead stripped.
325 TargetAtom->addEdge(Edge::KeepAlive, 0, *CurRecordAtom, 0);
326
327 // Skip over the PC range size field.
328 if (auto Err = EHFrameReader.skip(G.getPointerSize()))
329 return Err;
330
331 if (LSDAFieldPresent) {
332 uint64_t AugmentationDataSize;
333 if (auto Err = EHFrameReader.readULEB128(AugmentationDataSize))
334 return Err;
335 if (AugmentationDataSize != G.getPointerSize())
336 return make_error("Unexpected FDE augmentation data size "
337 "(expected " +
338 Twine(G.getPointerSize()) + ", got " +
339 Twine(AugmentationDataSize) + ")");
340 JITTargetAddress LSDAAddress = EHFrameAddress + EHFrameReader.getOffset();
341 auto LSDADelta = readAbsolutePointer();
342 if (!LSDADelta)
343 return LSDADelta.takeError();
344
345 JITTargetAddress LSDA = LSDAAddress + *LSDADelta;
346
347 auto *LSDAAtom = G.getAtomByAddress(LSDA);
348
349 if (!LSDAAtom)
350 return make_error("FDE LSDA " + formatv("{0:x16}", LSDA) +
351 " does not point at atom");
352
353 if (LSDAAtom->getAddress() != LSDA)
354 return make_error(
355 "FDE LSDA " + formatv("{0:x16}", LSDA) +
356 " does not point to start of atom at " +
357 formatv("{0:x16}", LSDAAtom->getAddress()));
358
359 LLVM_DEBUG(dbgs() << " FDE LSDA: " << *LSDAAtom << "\n");
360
361 // LSDA looks good. Add relocations.
362 CurRecordAtom->addEdge(FDEToTargetRelocKind,
363 LSDAAddress - CurRecordAtom->getAddress(), *LSDAAtom,
364 0);
365 }
366
367 return Error::success();
368 }
369
370 Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
371 StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
372 Edge::Kind FDEToCIERelocKind,
373 Edge::Kind FDEToTargetRelocKind) {
374 return EHFrameParser(G, EHFrameSection, EHFrameContent, EHFrameAddress,
375 FDEToCIERelocKind, FDEToTargetRelocKind)
376 .atomize();
377 }
378
379 // Determine whether we can register EH tables.
380 #if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
381 !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
382 #define HAVE_EHTABLE_SUPPORT 1
383 #else
384 #define HAVE_EHTABLE_SUPPORT 0
385 #endif
386
387 #if HAVE_EHTABLE_SUPPORT
388 extern "C" void __register_frame(const void *);
389 extern "C" void __deregister_frame(const void *);
390
391 Error registerFrameWrapper(const void *P) {
392 __register_frame(P);
393 return Error::success();
394 }
395
396 Error deregisterFrameWrapper(const void *P) {
397 __deregister_frame(P);
398 return Error::success();
399 }
400
401 #else
402
403 // The building compiler does not have __(de)register_frame but
404 // it may be found at runtime in a dynamically-loaded library.
405 // For example, this happens when building LLVM with Visual C++
406 // but using the MingW runtime.
407 static Error registerFrameWrapper(const void *P) {
408 static void((*RegisterFrame)(const void *)) = 0;
409
410 if (!RegisterFrame)
411 *(void **)&RegisterFrame =
412 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");
413
414 if (RegisterFrame) {
415 RegisterFrame(P);
416 return Error::success();
417 }
418
419 return make_error("could not register eh-frame: "
420 "__register_frame function not found");
421 }
422
423 static Error deregisterFrameWrapper(const void *P) {
424 static void((*DeregisterFrame)(const void *)) = 0;
425
426 if (!DeregisterFrame)
427 *(void **)&DeregisterFrame =
428 llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(
429 "__deregister_frame");
430
431 if (DeregisterFrame) {
432 DeregisterFrame(P);
433 return Error::success();
434 }
435
436 return make_error("could not deregister eh-frame: "
437 "__deregister_frame function not found");
438 }
439 #endif
440
441 #ifdef __APPLE__
442
443 template
444 Error walkAppleEHFrameSection(const char *const SectionStart,
445 HandleFDEFn HandleFDE) {
446 const char *CurCFIRecord = SectionStart;
447 uint64_t Size = *reinterpret_cast(CurCFIRecord);
448
449 while (Size != 0) {
450 const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
451 if (Size == 0xffffffff)
452 Size = *reinterpret_cast(CurCFIRecord + 4) + 12;
453 else
454 Size += 4;
455 uint32_t Offset = *reinterpret_cast(OffsetField);
456 if (Offset != 0)
457 if (auto Err = HandleFDE(CurCFIRecord))
458 return Err;
459
460 LLVM_DEBUG({
461 dbgs() << "Registering eh-frame section:\n";
462 dbgs() << "Processing " << (Offset ? "FDE" : "CIE") << " @"
463 << (void *)CurCFIRecord << ": [";
464 for (unsigned I = 0; I < Size; ++I)
465 dbgs() << format(" 0x%02" PRIx8, *(CurCFIRecord + I));
466 dbgs() << " ]\n";
467 });
468 CurCFIRecord += Size;
469
470 Size = *reinterpret_cast(CurCFIRecord);
471 }
472
473 return Error::success();
474 }
475
476 #endif // __APPLE__
477
478 Error registerEHFrameSection(const void *EHFrameSectionAddr) {
479 #ifdef __APPLE__
480 // On Darwin __register_frame has to be called for each FDE entry.
481 return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr),
482 registerFrameWrapper);
483 #else
484 // On Linux __register_frame takes a single argument:
485 // a pointer to the start of the .eh_frame section.
486
487 // How can it find the end? Because crtendS.o is linked
488 // in and it has an .eh_frame section with four zero chars.
489 return registerFrameWrapper(EHFrameSectionAddr);
490 #endif
491 }
492
493 Error deregisterEHFrameSection(const void *EHFrameSectionAddr) {
494 #ifdef __APPLE__
495 return walkAppleEHFrameSection(static_cast(EHFrameSectionAddr),
496 deregisterFrameWrapper);
497 #else
498 return deregisterFrameWrapper(EHFrameSectionAddr);
499 #endif
500 }
501
502 AtomGraphPassFunction createEHFrameRecorderPass(const Triple &TT,
503 JITTargetAddress &EHFrameAddr) {
504 const char *EHFrameSectionName = nullptr;
505 if (TT.getObjectFormat() == Triple::MachO)
506 EHFrameSectionName = "__eh_frame";
507 else
508 EHFrameSectionName = ".eh_frame";
509
510 auto RecordEHFrame = [EHFrameSectionName,
511 &EHFrameAddr](AtomGraph &G) -> Error {
512 // Search for a non-empty eh-frame and record the address of the first atom
513 // in it.
514 JITTargetAddress Addr = 0;
515 for (auto &S : G.sections())
516 if (S.getName() == EHFrameSectionName && !S.atoms_empty()) {
517 Addr = (*S.atoms().begin())->getAddress();
518 for (auto *DA : S.atoms())
519 if (DA->getAddress() < Addr)
520 Addr = DA->getAddress();
521 break;
522 }
523
524 EHFrameAddr = Addr;
525 return Error::success();
526 };
527
528 return RecordEHFrame;
529 }
530
531 } // end namespace jitlink
532 } // end namespace llvm
+0
-65
lib/ExecutionEngine/JITLink/JITLink_EHFrameSupportImpl.h less more
None //===----- JITLink_EHFrameSupport.h - JITLink eh-frame utils ----*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // EHFrame registration support for JITLink.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORTIMPL_H
13 #define LLVM_LIB_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORTIMPL_H
14
15 #include "llvm/ExecutionEngine/JITLink/JITLink_EHFrameSupport.h"
16
17 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
18 #include "llvm/Support/BinaryStreamReader.h"
19
20 namespace llvm {
21 namespace jitlink {
22
23 /// A generic parser for eh-frame sections.
24 ///
25 /// Adds atoms representing CIE and FDE entries, using the given FDE-to-CIE and
26 /// FDEToTarget relocation kinds.
27 class EHFrameParser {
28 public:
29 EHFrameParser(AtomGraph &G, Section &EHFrameSection, StringRef EHFrameContent,
30 JITTargetAddress EHFrameAddress, Edge::Kind FDEToCIERelocKind,
31 Edge::Kind FDEToTargetRelocKind);
32 Error atomize();
33
34 private:
35 struct AugmentationInfo {
36 bool AugmentationDataPresent = false;
37 bool EHDataFieldPresent = false;
38 uint8_t Fields[4] = {0x0, 0x0, 0x0, 0x0};
39 };
40
41 Expected parseAugmentationString();
42 Expected readAbsolutePointer();
43 Error processCIE();
44 Error processFDE(JITTargetAddress CIEPointerAddress, uint32_t CIEPointer);
45
46 AtomGraph &G;
47 Section &EHFrameSection;
48 StringRef EHFrameContent;
49 JITTargetAddress EHFrameAddress;
50 BinaryStreamReader EHFrameReader;
51 DefinedAtom *CurRecordAtom = nullptr;
52 bool LSDAFieldPresent = false;
53 Edge::Kind FDEToCIERelocKind;
54 Edge::Kind FDEToTargetRelocKind;
55 };
56
57 Error addEHFrame(AtomGraph &G, Section &EHFrameSection,
58 StringRef EHFrameContent, JITTargetAddress EHFrameAddress,
59 Edge::Kind FDEToCIERelocKind, Edge::Kind FDEToTargetRelocKind);
60
61 } // end namespace jitlink
62 } // end namespace llvm
63
64 #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_JITLINK_EHFRAMESUPPORTIMPL_H
+0
-73
lib/ExecutionEngine/JITLink/JITLink_MachO.cpp less more
None //===------------ JITLink.cpp - Run-time JIT linker for MachO -------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/JITLink/JITLink_MachO.h"
10
11 #include "llvm/BinaryFormat/MachO.h"
12 #include "llvm/ExecutionEngine/JITLink/JITLink_MachO_x86_64.h"
13 #include "llvm/Support/Endian.h"
14 #include "llvm/Support/Format.h"
15 #include "llvm/Support/MemoryBuffer.h"
16
17 using namespace llvm;
18
19 #define DEBUG_TYPE "jitlink"
20
21 namespace llvm {
22 namespace jitlink {
23
24 void jitLink_MachO(std::unique_ptr Ctx) {
25
26 // We don't want to do full MachO validation here. Just parse enough of the
27 // header to find out what MachO linker to use.
28
29 StringRef Data = Ctx->getObjectBuffer().getBuffer();
30 if (Data.size() < 4) {
31 Ctx->notifyFailed(make_error("Truncated MachO buffer"));
32 return;
33 }
34
35 uint32_t Magic;
36 memcpy(&Magic, Data.data(), sizeof(uint32_t));
37 LLVM_DEBUG({
38 dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic)
39 << "\n";
40 });
41
42 if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) {
43 Ctx->notifyFailed(
44 make_error("MachO 32-bit platforms not supported"));
45 return;
46 } else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
47 MachO::mach_header_64 Header;
48
49 memcpy(&Header, Data.data(), sizeof(MachO::mach_header_64));
50 if (Magic == MachO::MH_CIGAM_64)
51 swapStruct(Header);
52
53 LLVM_DEBUG({
54 dbgs() << "jitLink_MachO: cputype = "
55 << format("0x%08" PRIx32, Header.cputype)
56 << ", cpusubtype = " << format("0x%08" PRIx32, Header.cpusubtype)
57 << "\n";
58 });
59
60 switch (Header.cputype) {
61 case MachO::CPU_TYPE_X86_64:
62 return jitLink_MachO_x86_64(std::move(Ctx));
63 }
64 Ctx->notifyFailed(make_error("MachO-64 CPU type not valid"));
65 return;
66 }
67
68 Ctx->notifyFailed(make_error("MachO magic not valid"));
69 }
70
71 } // end namespace jitlink
72 } // end namespace llvm
+0
-605
lib/ExecutionEngine/JITLink/JITLink_MachO_x86_64.cpp less more
None //===------- JITLink_MachO_x86_64.cpp - JIT linker functionality ----------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // MachO jit-link implementation.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm/ExecutionEngine/JITLink/JITLink_MachO_x86_64.h"
13
14 #include "BasicGOTAndStubsBuilder.h"
15 #include "MachOAtomGraphBuilder.h"
16
17 #define DEBUG_TYPE "jitlink"
18
19 using namespace llvm;
20 using namespace llvm::jitlink;
21 using namespace llvm::jitlink::MachO_x86_64_Edges;
22
23 namespace {
24
25 class MachOAtomGraphBuilder_x86_64 : public MachOAtomGraphBuilder {
26 public:
27 MachOAtomGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
28 : MachOAtomGraphBuilder(Obj),
29 NumSymbols(Obj.getSymtabLoadCommand().nsyms) {
30 addCustomAtomizer("__eh_frame", [this](MachOSection &EHFrameSection) {
31 return addEHFrame(getGraph(), EHFrameSection.getGenericSection(),
32 EHFrameSection.getContent(),
33 EHFrameSection.getAddress(), NegDelta32, Delta64);
34 });
35 }
36
37 private:
38 static Expected
39 getRelocationKind(const MachO::relocation_info &RI) {
40 switch (RI.r_type) {
41 case MachO::X86_64_RELOC_UNSIGNED:
42 if (!RI.r_pcrel && RI.r_length == 3)
43 return RI.r_extern ? Pointer64 : Pointer64Anon;
44 break;
45 case MachO::X86_64_RELOC_SIGNED:
46 if (RI.r_pcrel && RI.r_length == 2)
47 return RI.r_extern ? PCRel32 : PCRel32Anon;
48 break;
49 case MachO::X86_64_RELOC_BRANCH:
50 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
51 return Branch32;
52 break;
53 case MachO::X86_64_RELOC_GOT_LOAD:
54 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
55 return PCRel32GOTLoad;
56 break;
57 case MachO::X86_64_RELOC_GOT:
58 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
59 return PCRel32GOT;
60 break;
61 case MachO::X86_64_RELOC_SUBTRACTOR:
62 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
63 // Initially represent SUBTRACTOR relocations with 'Delta'. They may
64 // be turned into NegDelta by parsePairRelocation.
65 if (!RI.r_pcrel && RI.r_extern) {
66 if (RI.r_length == 2)
67 return Delta32;
68 else if (RI.r_length == 3)
69 return Delta64;
70 }
71 break;
72 case MachO::X86_64_RELOC_SIGNED_1:
73 if (RI.r_pcrel && RI.r_length == 2)
74 return RI.r_extern ? PCRel32Minus1 : PCRel32Minus1Anon;
75 break;
76 case MachO::X86_64_RELOC_SIGNED_2:
77 if (RI.r_pcrel && RI.r_length == 2)
78 return RI.r_extern ? PCRel32Minus2 : PCRel32Minus2Anon;
79 break;
80 case MachO::X86_64_RELOC_SIGNED_4:
81 if (RI.r_pcrel && RI.r_length == 2)
82 return RI.r_extern ? PCRel32Minus4 : PCRel32Minus4Anon;
83 break;
84 case MachO::X86_64_RELOC_TLV:
85 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
86 return PCRel32TLV;
87 break;
88 }
89
90 return make_error(
91 "Unsupported x86-64 relocation: address=" +
92 formatv("{0:x8}", RI.r_address) +
93 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
94 ", kind=" + formatv("{0:x1}", RI.r_type) +
95 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
96 ", extern= " + (RI.r_extern ? "true" : "false") +
97 ", length=" + formatv("{0:d}", RI.r_length));
98 }
99
100 Expected findAtomBySymbolIndex(const MachO::relocation_info &RI) {
101 auto &Obj = getObject();
102 if (RI.r_symbolnum >= NumSymbols)
103 return make_error("Symbol index out of range");
104 auto SymI = Obj.getSymbolByIndex(RI.r_symbolnum);
105 auto Name = SymI->getName();
106 if (!Name)
107 return Name.takeError();
108 return getGraph().getAtomByName(*Name);
109 }
110
111 MachO::relocation_info
112 getRelocationInfo(const object::relocation_iterator RelItr) {
113 MachO::any_relocation_info ARI =
114 getObject().getRelocation(RelItr->getRawDataRefImpl());
115 MachO::relocation_info RI;
116 memcpy(&RI, &ARI, sizeof(MachO::relocation_info));
117 return RI;
118 }
119
120 using PairRelocInfo = std::tuple;
121
122 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
123 // returns the edge kind and addend to be used.
124 Expected
125 parsePairRelocation(DefinedAtom &AtomToFix, Edge::Kind SubtractorKind,
126 const MachO::relocation_info &SubRI,
127 JITTargetAddress FixupAddress, const char *FixupContent,
128 object::relocation_iterator &UnsignedRelItr,
129 object::relocation_iterator &RelEnd) {
130 using namespace support;
131
132 assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
133 (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
134 "Subtractor kind should match length");
135 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
136 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
137
138 if (UnsignedRelItr == RelEnd)
139 return make_error("x86_64 SUBTRACTOR without paired "
140 "UNSIGNED relocation");
141
142 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
143
144 if (SubRI.r_address != UnsignedRI.r_address)
145 return make_error("x86_64 SUBTRACTOR and paired UNSIGNED "
146 "point to different addresses");
147
148 if (SubRI.r_length != UnsignedRI.r_length)
149 return make_error("length of x86_64 SUBTRACTOR and paired "
150 "UNSIGNED reloc must match");
151
152 auto FromAtom = findAtomBySymbolIndex(SubRI);
153 if (!FromAtom)
154 return FromAtom.takeError();
155
156 // Read the current fixup value.
157 uint64_t FixupValue = 0;
158 if (SubRI.r_length == 3)
159 FixupValue = *(const ulittle64_t *)FixupContent;
160 else
161 FixupValue = *(const ulittle32_t *)FixupContent;
162
163 // Find 'ToAtom' using symbol number or address, depending on whether the
164 // paired UNSIGNED relocation is extern.
165 Atom *ToAtom = nullptr;
166 if (UnsignedRI.r_extern) {
167 // Find target atom by symbol index.
168 if (auto ToAtomOrErr = findAtomBySymbolIndex(UnsignedRI))
169 ToAtom = &*ToAtomOrErr;
170 else
171 return ToAtomOrErr.takeError();
172 } else {
173 if (auto ToAtomOrErr = getGraph().findAtomByAddress(FixupValue))
174 ToAtom = &*ToAtomOrErr;
175 else
176 return ToAtomOrErr.takeError();
177 FixupValue -= ToAtom->getAddress();
178 }
179
180 MachOX86RelocationKind DeltaKind;
181 Atom *TargetAtom;
182 uint64_t Addend;
183 if (&AtomToFix == &*FromAtom) {
184 TargetAtom = ToAtom;
185 DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
186 Addend = FixupValue + (FixupAddress - FromAtom->getAddress());
187 // FIXME: handle extern 'from'.
188 } else if (&AtomToFix == ToAtom) {
189 TargetAtom = &*FromAtom;
190 DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
191 Addend = FixupValue - (FixupAddress - ToAtom->getAddress());
192 } else {
193 // AtomToFix was neither FromAtom nor ToAtom.
194 return make_error("SUBTRACTOR relocation must fix up "
195 "either 'A' or 'B'");
196 }
197
198 return PairRelocInfo(DeltaKind, TargetAtom, Addend);
199 }
200
201 Error addRelocations() override {
202 using namespace support;
203 auto &G = getGraph();
204 auto &Obj = getObject();
205
206 for (auto &S : Obj.sections()) {
207
208 JITTargetAddress SectionAddress = S.getAddress();
209
210 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
211 RelItr != RelEnd; ++RelItr) {
212
213 MachO::relocation_info RI = getRelocationInfo(RelItr);
214
215 // Sanity check the relocation kind.
216 auto Kind = getRelocationKind(RI);
217 if (!Kind)
218 return Kind.takeError();
219
220 // Find the address of the value to fix up.
221 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
222
223 LLVM_DEBUG({
224 dbgs() << "Processing relocation at "
225 << format("0x%016" PRIx64, FixupAddress) << "\n";
226 });
227
228 // Find the atom that the fixup points to.
229 DefinedAtom *AtomToFix = nullptr;
230 {
231 auto AtomToFixOrErr = G.findAtomByAddress(FixupAddress);
232 if (!AtomToFixOrErr)
233 return AtomToFixOrErr.takeError();
234 AtomToFix = &*AtomToFixOrErr;
235 }
236
237 if (FixupAddress + static_cast(1 << RI.r_length) >
238 AtomToFix->getAddress() + AtomToFix->getContent().size())
239 return make_error(
240 "Relocation content extends past end of fixup atom");
241
242 // Get a pointer to the fixup content.
243 const char *FixupContent = AtomToFix->getContent().data() +
244 (FixupAddress - AtomToFix->getAddress());
245
246 // The target atom and addend will be populated by the switch below.
247 Atom *TargetAtom = nullptr;
248 uint64_t Addend = 0;
249
250 switch (*Kind) {
251 case Branch32:
252 case PCRel32:
253 case PCRel32GOTLoad:
254 case PCRel32GOT:
255 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
256 TargetAtom = &*TargetAtomOrErr;
257 else
258 return TargetAtomOrErr.takeError();
259 Addend = *(const ulittle32_t *)FixupContent;
260 break;
261 case Pointer64:
262 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
263 TargetAtom = &*TargetAtomOrErr;
264 else
265 return TargetAtomOrErr.takeError();
266 Addend = *(const ulittle64_t *)FixupContent;
267 break;
268 case Pointer64Anon: {
269 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
270 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
271 TargetAtom = &*TargetAtomOrErr;
272 else
273 return TargetAtomOrErr.takeError();
274 Addend = TargetAddress - TargetAtom->getAddress();
275 break;
276 }
277 case PCRel32Minus1:
278 case PCRel32Minus2:
279 case PCRel32Minus4:
280 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
281 TargetAtom = &*TargetAtomOrErr;
282 else
283 return TargetAtomOrErr.takeError();
284 Addend = *(const ulittle32_t *)FixupContent +
285 (1 << (*Kind - PCRel32Minus1));
286 break;
287 case PCRel32Anon: {
288 JITTargetAddress TargetAddress =
289 FixupAddress + 4 + *(const ulittle32_t *)FixupContent;
290 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
291 TargetAtom = &*TargetAtomOrErr;
292 else
293 return TargetAtomOrErr.takeError();
294 Addend = TargetAddress - TargetAtom->getAddress();
295 break;
296 }
297 case PCRel32Minus1Anon:
298 case PCRel32Minus2Anon:
299 case PCRel32Minus4Anon: {
300 JITTargetAddress Delta =
301 static_cast(1 << (*Kind - PCRel32Minus1Anon));
302 JITTargetAddress TargetAddress =
303 FixupAddress + 4 + Delta + *(const ulittle32_t *)FixupContent;
304 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
305 TargetAtom = &*TargetAtomOrErr;
306 else
307 return TargetAtomOrErr.takeError();
308 Addend = TargetAddress - TargetAtom->getAddress();
309 break;
310 }
311 case Delta32:
312 case Delta64: {
313 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
314 // parsePairRelocation handles the paired reloc, and returns the
315 // edge kind to be used (either Delta32/Delta64, or
316 // NegDelta32/NegDelta64, depending on the direction of the
317 // subtraction) along with the addend.
318 auto PairInfo =
319 parsePairRelocation(*AtomToFix, *Kind, RI, FixupAddress,
320 FixupContent, ++RelItr, RelEnd);
321 if (!PairInfo)
322 return PairInfo.takeError();
323 std::tie(*Kind, TargetAtom, Addend) = *PairInfo;
324 assert(TargetAtom && "No target atom from parsePairRelocation?");
325 break;
326 }
327 default:
328 llvm_unreachable("Special relocation kind should not appear in "
329 "mach-o file");
330 }
331
332 LLVM_DEBUG({
333 Edge GE(*Kind, FixupAddress - AtomToFix->getAddress(), *TargetAtom,
334 Addend);
335 printEdge(dbgs(), *AtomToFix, GE,
336 getMachOX86RelocationKindName(*Kind));
337 dbgs() << "\n";
338 });
339 AtomToFix->addEdge(*Kind, FixupAddress - AtomToFix->getAddress(),
340 *TargetAtom, Addend);
341 }
342 }
343 return Error::success();
344 }
345
346 unsigned NumSymbols = 0;
347 };
348
349 class MachO_x86_64_GOTAndStubsBuilder
350 : public BasicGOTAndStubsBuilder {
351 public:
352 MachO_x86_64_GOTAndStubsBuilder(AtomGraph &G)
353 : BasicGOTAndStubsBuilder(G) {}
354
355 bool isGOTEdge(Edge &E) const {
356 return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
357 }
358
359 DefinedAtom &createGOTEntry(Atom &Target) {
360 auto &GOTEntryAtom = G.addAnonymousAtom(getGOTSection(), 0x0, 8);
361 GOTEntryAtom.setContent(
362 StringRef(reinterpret_cast(NullGOTEntryContent), 8));
363 GOTEntryAtom.addEdge(Pointer64, 0, Target, 0);
364 return GOTEntryAtom;
365 }
366
367 void fixGOTEdge(Edge &E, Atom &GOTEntry) {
368 assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
369 "Not a GOT edge?");
370 E.setKind(PCRel32);
371 E.setTarget(GOTEntry);
372 // Leave the edge addend as-is.
373 }
374
375 bool isExternalBranchEdge(Edge &E) {
376 return E.getKind() == Branch32 && !E.getTarget().isDefined();
377 }
378
379 DefinedAtom &createStub(Atom &Target) {
380 auto &StubAtom = G.addAnonymousAtom(getStubsSection(), 0x0, 2);
381 StubAtom.setContent(
382 StringRef(reinterpret_cast(StubContent), 6));
383
384 // Re-use GOT entries for stub targets.
385 auto &GOTEntryAtom = getGOTEntryAtom(Target);
386 StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0);
387
388 return StubAtom;
389 }
390
391 void fixExternalBranchEdge(Edge &E, Atom &Stub) {
392 assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
393 assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
394 E.setTarget(Stub);
395 }
396
397 private:
398 Section &getGOTSection() {
399 if (!GOTSection)
400 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false);
401 return *GOTSection;
402 }
403
404 Section &getStubsSection() {
405 if (!StubsSection) {
406 auto StubsProt = static_cast(
407 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
408 StubsSection = &G.createSection("$__STUBS", StubsProt, false);
409 }
410 return *StubsSection;
411 }
412
413 static const uint8_t NullGOTEntryContent[8];
414 static const uint8_t StubContent[6];
415 Section *GOTSection = nullptr;
416 Section *StubsSection = nullptr;
417 };
418
419 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
421 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
422 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
423 } // namespace
424
425 namespace llvm {
426 namespace jitlink {
427
428 class MachOJITLinker_x86_64 : public JITLinker {
429 friend class JITLinker;
430
431 public:
432 MachOJITLinker_x86_64(std::unique_ptr Ctx,
433 PassConfiguration PassConfig)
434 : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
435
436 private:
437 StringRef getEdgeKindName(Edge::Kind R) const override {
438 return getMachOX86RelocationKindName(R);
439 }
440
441 Expected>
442 buildGraph(MemoryBufferRef ObjBuffer) override {
443 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
444 if (!MachOObj)
445 return MachOObj.takeError();
446 return MachOAtomGraphBuilder_x86_64(**MachOObj).buildGraph();
447 }
448
449 static Error targetOutOfRangeError(const Edge &E) {
450 std::string ErrMsg;
451 {
452 raw_string_ostream ErrStream(ErrMsg);
453 ErrStream << "Target \"" << E.getTarget() << "\" out of range";
454 }
455 return make_error(std::move(ErrMsg));
456 }
457
458 Error applyFixup(DefinedAtom &A, const Edge &E, char *AtomWorkingMem) const {
459 using namespace support;
460
461 char *FixupPtr = AtomWorkingMem + E.getOffset();
462 JITTargetAddress FixupAddress = A.getAddress() + E.getOffset();
463
464 switch (E.getKind()) {
465 case Branch32:
466 case PCRel32:
467 case PCRel32Anon: {
468 int64_t Value =
469 E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
470 if (Value < std::numeric_limits::min() ||
471 Value > std::numeric_limits::max())
472 return targetOutOfRangeError(E);
473 *(little32_t *)FixupPtr = Value;
474 break;
475 }
476 case Pointer64:
477 case Pointer64Anon: {
478 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
479 *(ulittle64_t *)FixupPtr = Value;
480 break;
481 }
482 case PCRel32Minus1:
483 case PCRel32Minus2:
484 case PCRel32Minus4: {
485 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
486 int64_t Value =
487 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
488 if (Value < std::numeric_limits::min() ||
489 Value > std::numeric_limits::max())
490 return targetOutOfRangeError(E);
491 *(little32_t *)FixupPtr = Value;
492 break;
493 }
494 case PCRel32Minus1Anon:
495 case PCRel32Minus2Anon:
496 case PCRel32Minus4Anon: {
497 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
498 int64_t Value =
499 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
500 if (Value < std::numeric_limits::min() ||
501 Value > std::numeric_limits::max())
502 return targetOutOfRangeError(E);
503 *(little32_t *)FixupPtr = Value;
504 break;
505 }
506 case Delta32:
507 case Delta64:
508 case NegDelta32:
509 case NegDelta64: {
510 int64_t Value;
511 if (E.getKind() == Delta32 || E.getKind() == Delta64)
512 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
513 else
514 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
515
516 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
517 if (Value < std::numeric_limits::min() ||
518 Value > std::numeric_limits::max())
519 return targetOutOfRangeError(E);
520 *(little32_t *)FixupPtr = Value;
521 } else
522 *(little64_t *)FixupPtr = Value;
523 break;
524 }
525 default:
526 llvm_unreachable("Unrecognized edge kind");
527 }
528
529 return Error::success();
530 }
531
532 uint64_t NullValue = 0;
533 };
534
535 void jitLink_MachO_x86_64(std::unique_ptr Ctx) {
536 PassConfiguration Config;
537 Triple TT("x86_64-apple-macosx");
538
539 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
540 // Add a mark-live pass.
541 if (auto MarkLive = Ctx->getMarkLivePass(TT))
542 Config.PrePrunePasses.push_back(std::move(MarkLive));
543 else
544 Config.PrePrunePasses.push_back(markAllAtomsLive);
545
546 // Add an in-place GOT/Stubs pass.
547 Config.PostPrunePasses.push_back([](AtomGraph &G) -> Error {
548 MachO_x86_64_GOTAndStubsBuilder(G).run();
549 return Error::success();
550 });
551 }
552
553 if (auto Err = Ctx->modifyPassConfig(TT, Config))
554 return Ctx->notifyFailed(std::move(Err));
555
556 // Construct a JITLinker and run the link function.
557 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
558 }
559
560 StringRef getMachOX86RelocationKindName(Edge::Kind R) {
561 switch (R) {
562 case Branch32:
563 return "Branch32";
564 case Pointer64:
565 return "Pointer64";
566 case Pointer64Anon:
567 return "Pointer64Anon";
568 case PCRel32:
569 return "PCRel32";
570 case PCRel32Minus1:
571 return "PCRel32Minus1";
572 case PCRel32Minus2:
573 return "PCRel32Minus2";
574 case PCRel32Minus4:
575 return "PCRel32Minus4";
576 case PCRel32Anon:
577 return "PCRel32Anon";
578 case PCRel32Minus1Anon:
579 return "PCRel32Minus1Anon";
580 case PCRel32Minus2Anon:
581 return "PCRel32Minus2Anon";
582 case PCRel32Minus4Anon:
583 return "PCRel32Minus4Anon";
584 case PCRel32GOTLoad:
585 return "PCRel32GOTLoad";
586 case PCRel32GOT:
587 return "PCRel32GOT";
588 case PCRel32TLV:
589 return "PCRel32TLV";
590 case Delta32:
591 return "Delta32";
592 case Delta64:
593 return "Delta64";
594 case NegDelta32:
595 return "NegDelta32";
596 case NegDelta64:
597 return "NegDelta64";
598 default:
599 return getGenericEdgeKindName(static_cast(R));
600 }
601 }
602
603 } // end namespace jitlink
604 } // end namespace llvm
0 //===-------------- MachO.cpp - JIT linker function for MachO -------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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_x86_64.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/MemoryBuffer.h"
20
21 using namespace llvm;
22
23 #define DEBUG_TYPE "jitlink"
24
25 namespace llvm {
26 namespace jitlink {
27
28 void jitLink_MachO(std::unique_ptr Ctx) {
29
30 // We don't want to do full MachO validation here. Just parse enough of the
31 // header to find out what MachO linker to use.
32
33 StringRef Data = Ctx->getObjectBuffer().getBuffer();
34 if (Data.size() < 4) {
35 Ctx->notifyFailed(make_error("Truncated MachO buffer"));
36 return;
37 }
38
39 uint32_t Magic;
40 memcpy(&Magic, Data.data(), sizeof(uint32_t));
41 LLVM_DEBUG({
42 dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic)
43 << "\n";
44 });
45
46 if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) {
47 Ctx->notifyFailed(
48 make_error("MachO 32-bit platforms not supported"));
49 return;
50 } else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
51 MachO::mach_header_64 Header;
52
53 memcpy(&Header, Data.data(), sizeof(MachO::mach_header_64));
54 if (Magic == MachO::MH_CIGAM_64)
55 swapStruct(Header);
56
57 LLVM_DEBUG({
58 dbgs() << "jitLink_MachO: cputype = "
59 << format("0x%08" PRIx32, Header.cputype)
60 << ", cpusubtype = " << format("0x%08" PRIx32, Header.cpusubtype)
61 << "\n";
62 });
63
64 switch (Header.cputype) {
65 case MachO::CPU_TYPE_X86_64:
66 return jitLink_MachO_x86_64(std::move(Ctx));
67 }
68 Ctx->notifyFailed(make_error("MachO-64 CPU type not valid"));
69 return;
70 }
71
72 Ctx->notifyFailed(make_error("MachO magic not valid"));
73 }
74
75 } // end namespace jitlink
76 } // end namespace llvm
0 //===---- MachO_x86_64.cpp -JIT linker implementation for MachO/x86-64 ----===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // MachO/x86-64 jit-link implementation.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
13
14 #include "BasicGOTAndStubsBuilder.h"
15 #include "MachOAtomGraphBuilder.h"
16
17 #define DEBUG_TYPE "jitlink"
18
19 using namespace llvm;
20 using namespace llvm::jitlink;
21 using namespace llvm::jitlink::MachO_x86_64_Edges;
22
23 namespace {
24
25 class MachOAtomGraphBuilder_x86_64 : public MachOAtomGraphBuilder {
26 public:
27 MachOAtomGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
28 : MachOAtomGraphBuilder(Obj),
29 NumSymbols(Obj.getSymtabLoadCommand().nsyms) {
30 addCustomAtomizer("__eh_frame", [this](MachOSection &EHFrameSection) {
31 return addEHFrame(getGraph(), EHFrameSection.getGenericSection(),
32 EHFrameSection.getContent(),
33 EHFrameSection.getAddress(), NegDelta32, Delta64);
34 });
35 }
36
37 private:
38 static Expected
39 getRelocationKind(const MachO::relocation_info &RI) {
40 switch (RI.r_type) {
41 case MachO::X86_64_RELOC_UNSIGNED:
42 if (!RI.r_pcrel && RI.r_length == 3)
43 return RI.r_extern ? Pointer64 : Pointer64Anon;
44 break;
45 case MachO::X86_64_RELOC_SIGNED:
46 if (RI.r_pcrel && RI.r_length == 2)
47 return RI.r_extern ? PCRel32 : PCRel32Anon;
48 break;
49 case MachO::X86_64_RELOC_BRANCH:
50 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
51 return Branch32;
52 break;
53 case MachO::X86_64_RELOC_GOT_LOAD:
54 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
55 return PCRel32GOTLoad;
56 break;
57 case MachO::X86_64_RELOC_GOT:
58 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
59 return PCRel32GOT;
60 break;
61 case MachO::X86_64_RELOC_SUBTRACTOR:
62 // SUBTRACTOR must be non-pc-rel, extern, with length 2 or 3.
63 // Initially represent SUBTRACTOR relocations with 'Delta'. They may
64 // be turned into NegDelta by parsePairRelocation.
65 if (!RI.r_pcrel && RI.r_extern) {
66 if (RI.r_length == 2)
67 return Delta32;
68 else if (RI.r_length == 3)
69 return Delta64;
70 }
71 break;
72 case MachO::X86_64_RELOC_SIGNED_1:
73 if (RI.r_pcrel && RI.r_length == 2)
74 return RI.r_extern ? PCRel32Minus1 : PCRel32Minus1Anon;
75 break;
76 case MachO::X86_64_RELOC_SIGNED_2:
77 if (RI.r_pcrel && RI.r_length == 2)
78 return RI.r_extern ? PCRel32Minus2 : PCRel32Minus2Anon;
79 break;
80 case MachO::X86_64_RELOC_SIGNED_4:
81 if (RI.r_pcrel && RI.r_length == 2)
82 return RI.r_extern ? PCRel32Minus4 : PCRel32Minus4Anon;
83 break;
84 case MachO::X86_64_RELOC_TLV:
85 if (RI.r_pcrel && RI.r_extern && RI.r_length == 2)
86 return PCRel32TLV;
87 break;
88 }
89
90 return make_error(
91 "Unsupported x86-64 relocation: address=" +
92 formatv("{0:x8}", RI.r_address) +
93 ", symbolnum=" + formatv("{0:x6}", RI.r_symbolnum) +
94 ", kind=" + formatv("{0:x1}", RI.r_type) +
95 ", pc_rel=" + (RI.r_pcrel ? "true" : "false") +
96 ", extern= " + (RI.r_extern ? "true" : "false") +
97 ", length=" + formatv("{0:d}", RI.r_length));
98 }
99
100 Expected findAtomBySymbolIndex(const MachO::relocation_info &RI) {
101 auto &Obj = getObject();
102 if (RI.r_symbolnum >= NumSymbols)
103 return make_error("Symbol index out of range");
104 auto SymI = Obj.getSymbolByIndex(RI.r_symbolnum);
105 auto Name = SymI->getName();
106 if (!Name)
107 return Name.takeError();
108 return getGraph().getAtomByName(*Name);
109 }
110
111 MachO::relocation_info
112 getRelocationInfo(const object::relocation_iterator RelItr) {
113 MachO::any_relocation_info ARI =
114 getObject().getRelocation(RelItr->getRawDataRefImpl());
115 MachO::relocation_info RI;
116 memcpy(&RI, &ARI, sizeof(MachO::relocation_info));
117 return RI;
118 }
119
120 using PairRelocInfo = std::tuple;
121
122 // Parses paired SUBTRACTOR/UNSIGNED relocations and, on success,
123 // returns the edge kind and addend to be used.
124 Expected
125 parsePairRelocation(DefinedAtom &AtomToFix, Edge::Kind SubtractorKind,
126 const MachO::relocation_info &SubRI,
127 JITTargetAddress FixupAddress, const char *FixupContent,
128 object::relocation_iterator &UnsignedRelItr,
129 object::relocation_iterator &RelEnd) {
130 using namespace support;
131
132 assert(((SubtractorKind == Delta32 && SubRI.r_length == 2) ||
133 (SubtractorKind == Delta64 && SubRI.r_length == 3)) &&
134 "Subtractor kind should match length");
135 assert(SubRI.r_extern && "SUBTRACTOR reloc symbol should be extern");
136 assert(!SubRI.r_pcrel && "SUBTRACTOR reloc should not be PCRel");
137
138 if (UnsignedRelItr == RelEnd)
139 return make_error("x86_64 SUBTRACTOR without paired "
140 "UNSIGNED relocation");
141
142 auto UnsignedRI = getRelocationInfo(UnsignedRelItr);
143
144 if (SubRI.r_address != UnsignedRI.r_address)
145 return make_error("x86_64 SUBTRACTOR and paired UNSIGNED "
146 "point to different addresses");
147
148 if (SubRI.r_length != UnsignedRI.r_length)
149 return make_error("length of x86_64 SUBTRACTOR and paired "
150 "UNSIGNED reloc must match");
151
152 auto FromAtom = findAtomBySymbolIndex(SubRI);
153 if (!FromAtom)
154 return FromAtom.takeError();
155
156 // Read the current fixup value.
157 uint64_t FixupValue = 0;
158 if (SubRI.r_length == 3)
159 FixupValue = *(const ulittle64_t *)FixupContent;
160 else
161 FixupValue = *(const ulittle32_t *)FixupContent;
162
163 // Find 'ToAtom' using symbol number or address, depending on whether the
164 // paired UNSIGNED relocation is extern.
165 Atom *ToAtom = nullptr;
166 if (UnsignedRI.r_extern) {
167 // Find target atom by symbol index.
168 if (auto ToAtomOrErr = findAtomBySymbolIndex(UnsignedRI))
169 ToAtom = &*ToAtomOrErr;
170 else
171 return ToAtomOrErr.takeError();
172 } else {
173 if (auto ToAtomOrErr = getGraph().findAtomByAddress(FixupValue))
174 ToAtom = &*ToAtomOrErr;
175 else
176 return ToAtomOrErr.takeError();
177 FixupValue -= ToAtom->getAddress();
178 }
179
180 MachOX86RelocationKind DeltaKind;
181 Atom *TargetAtom;
182 uint64_t Addend;
183 if (&AtomToFix == &*FromAtom) {
184 TargetAtom = ToAtom;
185 DeltaKind = (SubRI.r_length == 3) ? Delta64 : Delta32;
186 Addend = FixupValue + (FixupAddress - FromAtom->getAddress());
187 // FIXME: handle extern 'from'.
188 } else if (&AtomToFix == ToAtom) {
189 TargetAtom = &*FromAtom;
190 DeltaKind = (SubRI.r_length == 3) ? NegDelta64 : NegDelta32;
191 Addend = FixupValue - (FixupAddress - ToAtom->getAddress());
192 } else {
193 // AtomToFix was neither FromAtom nor ToAtom.
194 return make_error("SUBTRACTOR relocation must fix up "
195 "either 'A' or 'B'");
196 }
197
198 return PairRelocInfo(DeltaKind, TargetAtom, Addend);
199 }
200
201 Error addRelocations() override {
202 using namespace support;
203 auto &G = getGraph();
204 auto &Obj = getObject();
205
206 for (auto &S : Obj.sections()) {
207
208 JITTargetAddress SectionAddress = S.getAddress();
209
210 for (auto RelItr = S.relocation_begin(), RelEnd = S.relocation_end();
211 RelItr != RelEnd; ++RelItr) {
212
213 MachO::relocation_info RI = getRelocationInfo(RelItr);
214
215 // Sanity check the relocation kind.
216 auto Kind = getRelocationKind(RI);
217 if (!Kind)
218 return Kind.takeError();
219
220 // Find the address of the value to fix up.
221 JITTargetAddress FixupAddress = SectionAddress + (uint32_t)RI.r_address;
222
223 LLVM_DEBUG({
224 dbgs() << "Processing relocation at "
225 << format("0x%016" PRIx64, FixupAddress) << "\n";
226 });
227
228 // Find the atom that the fixup points to.
229 DefinedAtom *AtomToFix = nullptr;
230 {
231 auto AtomToFixOrErr = G.findAtomByAddress(FixupAddress);
232 if (!AtomToFixOrErr)
233 return AtomToFixOrErr.takeError();
234 AtomToFix = &*AtomToFixOrErr;
235 }
236
237 if (FixupAddress + static_cast(1 << RI.r_length) >
238 AtomToFix->getAddress() + AtomToFix->getContent().size())
239 return make_error(
240 "Relocation content extends past end of fixup atom");
241
242 // Get a pointer to the fixup content.
243 const char *FixupContent = AtomToFix->getContent().data() +
244 (FixupAddress - AtomToFix->getAddress());
245
246 // The target atom and addend will be populated by the switch below.
247 Atom *TargetAtom = nullptr;
248 uint64_t Addend = 0;
249
250 switch (*Kind) {
251 case Branch32:
252 case PCRel32:
253 case PCRel32GOTLoad:
254 case PCRel32GOT:
255 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
256 TargetAtom = &*TargetAtomOrErr;
257 else
258 return TargetAtomOrErr.takeError();
259 Addend = *(const ulittle32_t *)FixupContent;
260 break;
261 case Pointer64:
262 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
263 TargetAtom = &*TargetAtomOrErr;
264 else
265 return TargetAtomOrErr.takeError();
266 Addend = *(const ulittle64_t *)FixupContent;
267 break;
268 case Pointer64Anon: {
269 JITTargetAddress TargetAddress = *(const ulittle64_t *)FixupContent;
270 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
271 TargetAtom = &*TargetAtomOrErr;
272 else
273 return TargetAtomOrErr.takeError();
274 Addend = TargetAddress - TargetAtom->getAddress();
275 break;
276 }
277 case PCRel32Minus1:
278 case PCRel32Minus2:
279 case PCRel32Minus4:
280 if (auto TargetAtomOrErr = findAtomBySymbolIndex(RI))
281 TargetAtom = &*TargetAtomOrErr;
282 else
283 return TargetAtomOrErr.takeError();
284 Addend = *(const ulittle32_t *)FixupContent +
285 (1 << (*Kind - PCRel32Minus1));
286 break;
287 case PCRel32Anon: {
288 JITTargetAddress TargetAddress =
289 FixupAddress + 4 + *(const ulittle32_t *)FixupContent;
290 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
291 TargetAtom = &*TargetAtomOrErr;
292 else
293 return TargetAtomOrErr.takeError();
294 Addend = TargetAddress - TargetAtom->getAddress();
295 break;
296 }
297 case PCRel32Minus1Anon:
298 case PCRel32Minus2Anon:
299 case PCRel32Minus4Anon: {
300 JITTargetAddress Delta =
301 static_cast(1 << (*Kind - PCRel32Minus1Anon));
302 JITTargetAddress TargetAddress =
303 FixupAddress + 4 + Delta + *(const ulittle32_t *)FixupContent;
304 if (auto TargetAtomOrErr = G.findAtomByAddress(TargetAddress))
305 TargetAtom = &*TargetAtomOrErr;
306 else
307 return TargetAtomOrErr.takeError();
308 Addend = TargetAddress - TargetAtom->getAddress();
309 break;
310 }
311 case Delta32:
312 case Delta64: {
313 // We use Delta32/Delta64 to represent SUBTRACTOR relocations.
314 // parsePairRelocation handles the paired reloc, and returns the
315 // edge kind to be used (either Delta32/Delta64, or
316 // NegDelta32/NegDelta64, depending on the direction of the
317 // subtraction) along with the addend.
318 auto PairInfo =
319 parsePairRelocation(*AtomToFix, *Kind, RI, FixupAddress,
320 FixupContent, ++RelItr, RelEnd);
321 if (!PairInfo)
322 return PairInfo.takeError();
323 std::tie(*Kind, TargetAtom, Addend) = *PairInfo;
324 assert(TargetAtom && "No target atom from parsePairRelocation?");
325 break;
326 }
327 default:
328 llvm_unreachable("Special relocation kind should not appear in "
329 "mach-o file");
330 }
331
332 LLVM_DEBUG({
333 Edge GE(*Kind, FixupAddress - AtomToFix->getAddress(), *TargetAtom,
334 Addend);
335 printEdge(dbgs(), *AtomToFix, GE,
336 getMachOX86RelocationKindName(*Kind));
337 dbgs() << "\n";
338 });
339 AtomToFix->addEdge(*Kind, FixupAddress - AtomToFix->getAddress(),
340 *TargetAtom, Addend);
341 }
342 }
343 return Error::success();
344 }
345
346 unsigned NumSymbols = 0;
347 };
348
349 class MachO_x86_64_GOTAndStubsBuilder
350 : public BasicGOTAndStubsBuilder {
351 public:
352 MachO_x86_64_GOTAndStubsBuilder(AtomGraph &G)
353 : BasicGOTAndStubsBuilder(G) {}
354
355 bool isGOTEdge(Edge &E) const {
356 return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
357 }
358
359 DefinedAtom &createGOTEntry(Atom &Target) {
360 auto &GOTEntryAtom = G.addAnonymousAtom(getGOTSection(), 0x0, 8);
361 GOTEntryAtom.setContent(
362 StringRef(reinterpret_cast(NullGOTEntryContent), 8));
363 GOTEntryAtom.addEdge(Pointer64, 0, Target, 0);
364 return GOTEntryAtom;
365 }
366
367 void fixGOTEdge(Edge &E, Atom &GOTEntry) {
368 assert((E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad) &&
369 "Not a GOT edge?");
370 E.setKind(PCRel32);
371 E.setTarget(GOTEntry);
372 // Leave the edge addend as-is.
373 }
374
375 bool isExternalBranchEdge(Edge &E) {
376 return E.getKind() == Branch32 && !E.getTarget().isDefined();
377 }
378
379 DefinedAtom &createStub(Atom &Target) {
380 auto &StubAtom = G.addAnonymousAtom(getStubsSection(), 0x0, 2);
381 StubAtom.setContent(
382 StringRef(reinterpret_cast(StubContent), 6));
383
384 // Re-use GOT entries for stub targets.
385 auto &GOTEntryAtom = getGOTEntryAtom(Target);
386 StubAtom.addEdge(PCRel32, 2, GOTEntryAtom, 0);
387
388 return StubAtom;
389 }
390
391 void fixExternalBranchEdge(Edge &E, Atom &Stub) {
392 assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
393 assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
394 E.setTarget(Stub);
395 }
396
397 private:
398 Section &getGOTSection() {
399 if (!GOTSection)
400 GOTSection = &G.createSection("$__GOT", sys::Memory::MF_READ, false);
401 return *GOTSection;
402 }
403
404 Section &getStubsSection() {
405 if (!StubsSection) {
406 auto StubsProt = static_cast(
407 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
408 StubsSection = &G.createSection("$__STUBS", StubsProt, false);
409 }
410 return *StubsSection;
411 }
412
413 static const uint8_t NullGOTEntryContent[8];
414 static const uint8_t StubContent[6];
415 Section *GOTSection = nullptr;
416 Section *StubsSection = nullptr;
417 };
418
419 const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
420 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
421 const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
422 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
423 } // namespace
424
425 namespace llvm {
426 namespace jitlink {
427
428 class MachOJITLinker_x86_64 : public JITLinker {
429 friend class JITLinker;
430
431 public:
432 MachOJITLinker_x86_64(std::unique_ptr Ctx,
433 PassConfiguration PassConfig)
434 : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
435
436 private:
437 StringRef getEdgeKindName(Edge::Kind R) const override {
438 return getMachOX86RelocationKindName(R);
439 }
440
441 Expected>
442 buildGraph(MemoryBufferRef ObjBuffer) override {
443 auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
444 if (!MachOObj)
445 return MachOObj.takeError();
446 return MachOAtomGraphBuilder_x86_64(**MachOObj).buildGraph();
447 }
448
449 static Error targetOutOfRangeError(const Edge &E) {
450 std::string ErrMsg;
451 {
452 raw_string_ostream ErrStream(ErrMsg);
453 ErrStream << "Target \"" << E.getTarget() << "\" out of range";
454 }
455 return make_error(std::move(ErrMsg));
456 }
457
458 Error applyFixup(DefinedAtom &A, const Edge &E, char *AtomWorkingMem) const {
459 using namespace support;
460
461 char *FixupPtr = AtomWorkingMem + E.getOffset();
462 JITTargetAddress FixupAddress = A.getAddress() + E.getOffset();
463
464 switch (E.getKind()) {
465 case Branch32:
466 case PCRel32:
467 case PCRel32Anon: {
468 int64_t Value =
469 E.getTarget().getAddress() - (FixupAddress + 4) + E.getAddend();
470 if (Value < std::numeric_limits::min() ||
471 Value > std::numeric_limits::max())
472 return targetOutOfRangeError(E);
473 *(little32_t *)FixupPtr = Value;
474 break;
475 }
476 case Pointer64:
477 case Pointer64Anon: {
478 uint64_t Value = E.getTarget().getAddress() + E.getAddend();
479 *(ulittle64_t *)FixupPtr = Value;
480 break;
481 }
482 case PCRel32Minus1:
483 case PCRel32Minus2:
484 case PCRel32Minus4: {
485 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1));
486 int64_t Value =
487 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
488 if (Value < std::numeric_limits::min() ||
489 Value > std::numeric_limits::max())
490 return targetOutOfRangeError(E);
491 *(little32_t *)FixupPtr = Value;
492 break;
493 }
494 case PCRel32Minus1Anon:
495 case PCRel32Minus2Anon:
496 case PCRel32Minus4Anon: {
497 int Delta = 4 + (1 << (E.getKind() - PCRel32Minus1Anon));
498 int64_t Value =
499 E.getTarget().getAddress() - (FixupAddress + Delta) + E.getAddend();
500 if (Value < std::numeric_limits::min() ||
501 Value > std::numeric_limits::max())
502 return targetOutOfRangeError(E);
503 *(little32_t *)FixupPtr = Value;
504 break;
505 }
506 case Delta32:
507 case Delta64:
508 case NegDelta32:
509 case NegDelta64: {
510 int64_t Value;
511 if (E.getKind() == Delta32 || E.getKind() == Delta64)
512 Value = E.getTarget().getAddress() - FixupAddress + E.getAddend();
513 else
514 Value = FixupAddress - E.getTarget().getAddress() + E.getAddend();
515
516 if (E.getKind() == Delta32 || E.getKind() == NegDelta32) {
517 if (Value < std::numeric_limits::min() ||
518 Value > std::numeric_limits::max())
519 return targetOutOfRangeError(E);
520 *(little32_t *)FixupPtr = Value;
521 } else
522 *(little64_t *)FixupPtr = Value;
523 break;
524 }
525 default:
526 llvm_unreachable("Unrecognized edge kind");
527 }
528
529 return Error::success();
530 }
531
532 uint64_t NullValue = 0;
533 };
534
535 void jitLink_MachO_x86_64(std::unique_ptr Ctx) {
536 PassConfiguration Config;
537 Triple TT("x86_64-apple-macosx");
538
539 if (Ctx->shouldAddDefaultTargetPasses(TT)) {
540 // Add a mark-live pass.
541 if (auto MarkLive = Ctx->getMarkLivePass(TT))
542 Config.PrePrunePasses.push_back(std::move(MarkLive));
543 else
544 Config.PrePrunePasses.push_back(markAllAtomsLive);
545
546 // Add an in-place GOT/Stubs pass.
547 Config.PostPrunePasses.push_back([](AtomGraph &G) -> Error {
548 MachO_x86_64_GOTAndStubsBuilder(G).run();
549 return Error::success();
550 });
551 }
552
553 if (auto Err = Ctx->modifyPassConfig(TT, Config))
554 return Ctx->notifyFailed(std::move(Err));
555
556 // Construct a JITLinker and run the link function.
557 MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
558 }
559
560 StringRef getMachOX86RelocationKindName(Edge::Kind R) {
561 switch (R) {
562 case Branch32:
563 return "Branch32";
564 case Pointer64:
565 return "Pointer64";
566 case Pointer64Anon:
567 return "Pointer64Anon";
568 case PCRel32:
569 return "PCRel32";
570 case PCRel32Minus1:
571 return "PCRel32Minus1";
572 case PCRel32Minus2:
573 return "PCRel32Minus2";
574 case PCRel32Minus4:
575 return "PCRel32Minus4";
576 case PCRel32Anon:
577 return "PCRel32Anon";
578 case PCRel32Minus1Anon:
579 return "PCRel32Minus1Anon";
580 case PCRel32Minus2Anon:
581 return "PCRel32Minus2Anon";
582 case PCRel32Minus4Anon:
583 return "PCRel32Minus4Anon";
584 case PCRel32GOTLoad:
585 return "PCRel32GOTLoad";
586 case PCRel32GOT:
587 return "PCRel32GOT";
588 case PCRel32TLV:
589 return "PCRel32TLV";
590 case Delta32:
591 return "Delta32";
592 case Delta64:
593 return "Delta64";
594 case NegDelta32:
595 return "NegDelta32";
596 case NegDelta64:
597 return "NegDelta64";
598 default:
599 return getGenericEdgeKindName(static_cast(R));
600 }
601 }
602
603 } // end namespace jitlink
604 } // end namespace llvm
88 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
99
1010 #include "llvm/ADT/Optional.h"
11 #include "llvm/ExecutionEngine/JITLink/JITLink_EHFrameSupport.h"
11 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
1212
1313 #include
1414
1111
1212 add_llvm_unittest(JITLinkTests
1313 JITLinkTestCommon.cpp
14 JITLinkTest_MachO_x86_64_Tests.cpp
14 MachO_x86_64_Tests.cpp
1515 )
1616
1717 target_link_libraries(JITLinkTests PRIVATE LLVMTestingSupport)
+0
-229
unittests/ExecutionEngine/JITLink/JITLinkTest_MachO_x86_64_Tests.cpp less more
None //===---- JITLinkTest_MachO_x86_64.cpp - Tests for JITLink MachO/x86-64 ---===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "JITLinkTestCommon.h"
9
10 #include "llvm/ADT/DenseSet.h"
11 #include "llvm/ExecutionEngine/JITLink/JITLink_MachO_x86_64.h"
12 #include "llvm/Testing/Support/Error.h"
13
14 #include "gtest/gtest.h"
15
16 using namespace llvm;
17 using namespace llvm::jitlink;
18 using namespace llvm::jitlink::MachO_x86_64_Edges;
19
20 namespace {
21
22 class JITLinkTest_MachO_x86_64 : public JITLinkTestCommon,
23 public testing::Test {
24 public:
25 using BasicVerifyGraphFunction =
26 std::function;
27
28 void runBasicVerifyGraphTest(StringRef AsmSrc, StringRef Triple,
29 StringMap Externals,
30 bool PIC, bool LargeCodeModel,
31 MCTargetOptions Options,
32 BasicVerifyGraphFunction RunGraphTest) {
33 auto TR = getTestResources(AsmSrc, Triple, PIC, LargeCodeModel,
34 std::move(Options));
35 if (!TR) {
36 dbgs() << "Skipping JITLInk unit test: " << toString(TR.takeError())
37 << "\n";
38 return;
39 }
40
41 auto JTCtx = llvm::make_unique(
42 **TR, [&](AtomGraph &G) { RunGraphTest(G, (*TR)->getDisassembler()); });
43
44 JTCtx->externals() = std::move(Externals);
45
46 jitLink_MachO_x86_64(std::move(JTCtx));
47 }
48
49 protected:
50 static void verifyIsPointerTo(AtomGraph &G, DefinedAtom &A, Atom &Target) {
51 EXPECT_EQ(A.edges_size(), 1U) << "Incorrect number of edges for pointer";
52 if (A.edges_size() != 1U)
53 return;
54 auto &E = *A.edges().begin();
55 EXPECT_EQ(E.getKind(), Pointer64)
56 << "Expected pointer to have a pointer64 relocation";
57 EXPECT_EQ(&E.getTarget(), &Target) << "Expected edge to point at target";
58 EXPECT_THAT_EXPECTED(readInt(G, A), HasValue(Target.getAddress()))
59 << "Pointer does not point to target";
60 }
61
62 static void verifyGOTLoad(AtomGraph &G, DefinedAtom &A, Edge &E,
63 Atom &Target) {
64 EXPECT_EQ(E.getAddend(), 0U) << "Expected GOT load to have a zero addend";
65 EXPECT_TRUE(E.getTarget().isDefined())
66 << "GOT entry should be a defined atom";
67 if (!E.getTarget().isDefined())
68 return;
69
70 verifyIsPointerTo(G, static_cast(E.getTarget()), Target);
71 }
72
73 static void verifyCall(const MCDisassembler &Dis, AtomGraph &G,
74 DefinedAtom &Caller, Edge &E, Atom &Callee) {
75 EXPECT_EQ(E.getKind(), Branch32) << "Edge is not a Branch32";
76 EXPECT_EQ(E.getAddend(), 0U) << "Expected no addend on stub call";
77 EXPECT_EQ(&E.getTarget(), &Callee)
78 << "Edge does not point at expected callee";
79
80 JITTargetAddress FixupAddress = Caller.getAddress() + E.getOffset();
81 uint64_t PCRelDelta = Callee.getAddress() - (FixupAddress + 4);
82
83 EXPECT_THAT_EXPECTED(
84 decodeImmediateOperand(Dis, Caller, 0, E.getOffset() - 1),
85 HasValue(PCRelDelta));
86 }
87
88 static void verifyIndirectCall(const MCDisassembler &Dis, AtomGraph &G,
89 DefinedAtom &Caller, Edge &E, Atom &Callee) {
90 EXPECT_EQ(E.getKind(), PCRel32) << "Edge is not a PCRel32";
91 EXPECT_EQ(E.getAddend(), 0) << "Expected no addend on stub cal";
92 EXPECT_TRUE(E.getTarget().isDefined()) << "Target is not a defined atom";
93 if (!E.getTarget().isDefined())
94 return;
95 verifyIsPointerTo(G, static_cast(E.getTarget()), Callee);
96
97 JITTargetAddress FixupAddress = Caller.getAddress() + E.getOffset();
98 uint64_t PCRelDelta = E.getTarget().getAddress() - (FixupAddress + 4);
99
100 EXPECT_THAT_EXPECTED(
101 decodeImmediateOperand(Dis, Caller, 3, E.getOffset() - 2),
102 HasValue(PCRelDelta));
103 }
104
105 static void verifyCallViaStub(const MCDisassembler &Dis, AtomGraph &G,
106 DefinedAtom &Caller, Edge &E, Atom &Callee) {
107 verifyCall(Dis, G, Caller, E, E.getTarget());
108
109 if (!E.getTarget().isDefined()) {
110 ADD_FAILURE() << "Edge target is not a stub";
111 return;
112 }
113
114 auto &StubAtom = static_cast(E.getTarget());
115 EXPECT_EQ(StubAtom.edges_size(), 1U)
116 << "Expected one edge from stub to target";
117
118 auto &StubEdge = *StubAtom.edges().begin();
119
120 verifyIndirectCall(Dis, G, static_cast(StubAtom), StubEdge,
121 Callee);
122 }
123 };
124
125 } // end anonymous namespace
126
127 // Test each operation on LegacyObjectTransformLayer.
128 TEST_F(JITLinkTest_MachO_x86_64, BasicRelocations) {
129 runBasicVerifyGraphTest(
130 R"(
131 .section __TEXT,__text,regular,pure_instructions
132 .build_version macos, 10, 14
133 .globl _bar
134 .p2align 4, 0x90
135 _bar:
136 callq _baz
137
138 .globl _foo
139 .p2align 4, 0x90
140 _foo:
141 callq _bar
142 _foo.1:
143 movq _y@GOTPCREL(%rip), %rcx
144 _foo.2:
145 movq _p(%rip), %rdx
146
147 .section __DATA,__data
148 .globl _x
149 .p2align 2
150 _x:
151 .long 42
152
153 .globl _p
154 .p2align 3
155 _p:
156 .quad _x
157
158 .subsections_via_symbols)",
159 "x86_64-apple-macosx10.14",
160 {{"_y", JITEvaluatedSymbol(0xdeadbeef, JITSymbolFlags::Exported)},
161 {"_baz", JITEvaluatedSymbol(0xcafef00d, JITSymbolFlags::Exported)}},
162 true, false, MCTargetOptions(),
163 [](AtomGraph &G, const MCDisassembler &Dis) {
164 // Name the atoms in the asm above.
165 auto &Baz = atom(G, "_baz");
166 auto &Y = atom(G, "_y");
167
168 auto &Bar = definedAtom(G, "_bar");
169 auto &Foo = definedAtom(G, "_foo");
170 auto &Foo_1 = definedAtom(G, "_foo.1");
171 auto &Foo_2 = definedAtom(G, "_foo.2");
172 auto &X = definedAtom(G, "_x");
173 auto &P = definedAtom(G, "_p");
174
175 // Check unsigned reloc for _p
176 {
177 EXPECT_EQ(P.edges_size(), 1U) << "Unexpected number of relocations";
178 EXPECT_EQ(P.edges().begin()->getKind(), Pointer64)
179 << "Unexpected edge kind for _p";
180 EXPECT_THAT_EXPECTED(readInt(G, P),
181 HasValue(X.getAddress()))
182 << "Unsigned relocation did not apply correctly";
183 }
184
185 // Check that _bar is a call-via-stub to _baz.
186 // This will check that the call goes to a stub, that the stub is an
187 // indirect call, and that the pointer for the indirect call points to
188 // baz.
189 {
190 EXPECT_EQ(Bar.edges_size(), 1U)
191 << "Incorrect number of edges for bar";
192 EXPECT_EQ(Bar.edges().begin()->getKind(), Branch32)
193 << "Unexpected edge kind for _bar";
194 verifyCallViaStub(Dis, G, Bar, *Bar.edges().begin(), Baz);
195 }
196
197 // Check that _foo is a direct call to _bar.
198 {
199 EXPECT_EQ(Foo.edges_size(), 1U)
200 << "Incorrect number of edges for foo";
201 EXPECT_EQ(Foo.edges().begin()->getKind(), Branch32);
202 verifyCall(Dis, G, Foo, *Foo.edges().begin(), Bar);
203 }
204
205 // Check .got load in _foo.1
206 {
207 EXPECT_EQ(Foo_1.edges_size(), 1U)
208 << "Incorrect number of edges for foo_1";
209 EXPECT_EQ(Foo_1.edges().begin()->getKind(), PCRel32);
210 verifyGOTLoad(G, Foo_1, *Foo_1.edges().begin(), Y);
211 }
212
213 // Check PCRel ref to _p in _foo.2
214 {
215 EXPECT_EQ(Foo_2.edges_size(), 1U)
216 << "Incorrect number of edges for foo_2";
217 EXPECT_EQ(Foo_2.edges().begin()->getKind(), PCRel32);
218
219 JITTargetAddress FixupAddress =
220 Foo_2.getAddress() + Foo_2.edges().begin()->getOffset();
221 uint64_t PCRelDelta = P.getAddress() - (FixupAddress + 4);
222
223 EXPECT_THAT_EXPECTED(decodeImmediateOperand(Dis, Foo_2, 4, 0),
224 HasValue(PCRelDelta))
225 << "PCRel load does not reference expected target";
226 }
227 });
228 }
0 //===--------- MachO_x86_64.cpp - Tests for JITLink MachO/x86-64 ----------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "JITLinkTestCommon.h"
9
10 #include "llvm/ADT/DenseSet.h"
11 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
12 #include "llvm/Testing/Support/Error.h"
13
14 #include "gtest/gtest.h"
15
16 using namespace llvm;
17 using namespace llvm::jitlink;
18 using namespace llvm::jitlink::MachO_x86_64_Edges;
19
20 namespace {
21
22 class JITLinkTest_MachO_x86_64 : public JITLinkTestCommon,
23 public testing::Test {
24 public:
25 using BasicVerifyGraphFunction =
26 std::function;
27
28 void runBasicVerifyGraphTest(StringRef AsmSrc, StringRef Triple,
29 StringMap Externals,
30 bool PIC, bool LargeCodeModel,
31 MCTargetOptions Options,
32 BasicVerifyGraphFunction RunGraphTest) {
33 auto TR = getTestResources(AsmSrc, Triple, PIC, LargeCodeModel,
34 std::move(Options));
35 if (!TR) {
36 dbgs() << "Skipping JITLInk unit test: " << toString(TR.takeError())
37 << "\n";
38 return;
39 }
40
41 auto JTCtx = llvm::make_unique(
42 **TR, [&](AtomGraph &G) { RunGraphTest(G, (*TR)->getDisassembler()); });
43
44 JTCtx->externals() = std::move(Externals);
45
46 jitLink_MachO_x86_64(std::move(JTCtx));
47 }
48
49 protected:
50 static void verifyIsPointerTo(AtomGraph &G, DefinedAtom &A, Atom &Target) {
51 EXPECT_EQ(A.edges_size(), 1U) << "Incorrect number of edges for pointer";
52 if (A.edges_size() != 1U)
53 return;
54 auto &E = *A.edges().begin();
55 EXPECT_EQ(E.getKind(), Pointer64)
56 << "Expected pointer to have a pointer64 relocation";
57 EXPECT_EQ(&E.getTarget(), &Target) << "Expected edge to point at target";
58 EXPECT_THAT_EXPECTED(readInt(G, A), HasValue(Target.getAddress()))
59 << "Pointer does not point to target";
60 }
61
62 static void verifyGOTLoad(AtomGraph &G, DefinedAtom &A, Edge &E,
63 Atom &Target) {
64 EXPECT_EQ(E.getAddend(), 0U) << "Expected GOT load to have a zero addend";
65 EXPECT_TRUE(E.getTarget().isDefined())
66 << "GOT entry should be a defined atom";
67 if (!E.getTarget().isDefined())
68 return;
69
70 verifyIsPointerTo(G, static_cast(E.getTarget()), Target);
71 }
72
73 static void verifyCall(const MCDisassembler &Dis, AtomGraph &G,
74 DefinedAtom &Caller, Edge &E, Atom &Callee) {
75 EXPECT_EQ(E.getKind(), Branch32) << "Edge is not a Branch32";
76 EXPECT_EQ(E.getAddend(), 0U) << "Expected no addend on stub call";
77 EXPECT_EQ(&E.getTarget(), &Callee)
78 << "Edge does not point at expected callee";
79
80 JITTargetAddress FixupAddress = Caller.getAddress() + E.getOffset();
81 uint64_t PCRelDelta = Callee.getAddress() - (FixupAddress + 4);
82
83 EXPECT_THAT_EXPECTED(
84 decodeImmediateOperand(Dis, Caller, 0, E.getOffset() - 1),
85 HasValue(PCRelDelta));
86 }
87
88 static void verifyIndirectCall(const MCDisassembler &Dis, AtomGraph &G,
89 DefinedAtom &Caller, Edge &E, Atom &Callee) {
90 EXPECT_EQ(E.getKind(), PCRel32) << "Edge is not a PCRel32";
91 EXPECT_EQ(E.getAddend(), 0) << "Expected no addend on stub cal";
92 EXPECT_TRUE(E.getTarget().isDefined()) << "Target is not a defined atom";
93 if (!E.getTarget().isDefined())
94 return;
95 verifyIsPointerTo(G, static_cast(E.getTarget()), Callee);
96
97 JITTargetAddress FixupAddress = Caller.getAddress() + E.getOffset();
98 uint64_t PCRelDelta = E.getTarget().getAddress() - (FixupAddress + 4);
99
100 EXPECT_THAT_EXPECTED(
101 decodeImmediateOperand(Dis, Caller, 3, E.getOffset() - 2),
102 HasValue(PCRelDelta));
103 }
104
105 static void verifyCallViaStub(const MCDisassembler &Dis, AtomGraph &G,
106 DefinedAtom &Caller, Edge &E, Atom &Callee) {
107 verifyCall(Dis, G, Caller, E, E.getTarget());
108
109 if (!E.getTarget().isDefined()) {
110 ADD_FAILURE() << "Edge target is not a stub";
111 return;
112 }
113
114 auto &StubAtom = static_cast(E.getTarget());
115 EXPECT_EQ(StubAtom.edges_size(), 1U)
116 << "Expected one edge from stub to target";
117
118 auto &StubEdge = *StubAtom.edges().begin();
119
120 verifyIndirectCall(Dis, G, static_cast(StubAtom), StubEdge,
121 Callee);
122 }
123 };
124
125 } // end anonymous namespace
126
127 // Test each operation on LegacyObjectTransformLayer.
128 TEST_F(JITLinkTest_MachO_x86_64, BasicRelocations) {
129 runBasicVerifyGraphTest(
130 R"(
131 .section __TEXT,__text,regular,pure_instructions
132 .build_version macos, 10, 14
133 .globl _bar
134 .p2align 4, 0x90
135 _bar:
136 callq _baz
137
138 .globl _foo
139 .p2align 4, 0x90
140 _foo:
141 callq _bar
142 _foo.1:
143 movq _y@GOTPCREL(%rip), %rcx
144 _foo.2:
145 movq _p(%rip), %rdx
146
147 .section __DATA,__data
148 .globl _x
149 .p2align 2
150 _x:
151 .long 42
152
153 .globl _p
154 .p2align 3
155 _p:
156 .quad _x
157
158 .subsections_via_symbols)",
159 "x86_64-apple-macosx10.14",
160 {{"_y", JITEvaluatedSymbol(0xdeadbeef, JITSymbolFlags::Exported)},
161 {"_baz", JITEvaluatedSymbol(0xcafef00d, JITSymbolFlags::Exported)}},
162 true, false, MCTargetOptions(),
163 [](AtomGraph &G, const MCDisassembler &Dis) {
164 // Name the atoms in the asm above.
165 auto &Baz = atom(G, "_baz");
166 auto &Y = atom(G, "_y");
167
168 auto &Bar = definedAtom(G, "_bar");
169 auto &Foo = definedAtom(G, "_foo");
170 auto &Foo_1 = definedAtom(G, "_foo.1");
171 auto &Foo_2 = definedAtom(G, "_foo.2");
172 auto &X = definedAtom(G, "_x");
173 auto &P = definedAtom(G, "_p");
174
175 // Check unsigned reloc for _p
176 {
177 EXPECT_EQ(P.edges_size(), 1U) << "Unexpected number of relocations";
178 EXPECT_EQ(P.edges().begin()->getKind(), Pointer64)
179 << "Unexpected edge kind for _p";
180 EXPECT_THAT_EXPECTED(readInt(G, P),
181 HasValue(X.getAddress()))
182 << "Unsigned relocation did not apply correctly";
183 }
184
185 // Check that _bar is a call-via-stub to _baz.
186 // This will check that the call goes to a stub, that the stub is an
187 // indirect call, and that the pointer for the indirect call points to
188 // baz.
189 {
190 EXPECT_EQ(Bar.edges_size(), 1U)
191 << "Incorrect number of edges for bar";
192 EXPECT_EQ(Bar.edges().begin()->getKind(), Branch32)
193 << "Unexpected edge kind for _bar";
194 verifyCallViaStub(Dis, G, Bar, *Bar.edges().begin(), Baz);
195 }
196
197 // Check that _foo is a direct call to _bar.
198 {
199 EXPECT_EQ(Foo.edges_size(), 1U)
200 << "Incorrect number of edges for foo";
201 EXPECT_EQ(Foo.edges().begin()->getKind(), Branch32);
202 verifyCall(Dis, G, Foo, *Foo.edges().begin(), Bar);
203 }
204
205 // Check .got load in _foo.1
206 {
207 EXPECT_EQ(Foo_1.edges_size(), 1U)
208 << "Incorrect number of edges for foo_1";
209 EXPECT_EQ(Foo_1.edges().begin()->getKind(), PCRel32);
210 verifyGOTLoad(G, Foo_1, *Foo_1.edges().begin(), Y);
211 }
212
213 // Check PCRel ref to _p in _foo.2
214 {
215 EXPECT_EQ(Foo_2.edges_size(), 1U)
216 << "Incorrect number of edges for foo_2";
217 EXPECT_EQ(Foo_2.edges().begin()->getKind(), PCRel32);
218
219 JITTargetAddress FixupAddress =
220 Foo_2.getAddress() + Foo_2.edges().begin()->getOffset();
221 uint64_t PCRelDelta = P.getAddress() - (FixupAddress + 4);
222
223 EXPECT_THAT_EXPECTED(decodeImmediateOperand(Dis, Foo_2, 4, 0),
224 HasValue(PCRelDelta))
225 << "PCRel load does not reference expected target";
226 }
227 });
228 }