1 | //===------ MachOPlatform.cpp - Utilities for executing MachO in Orc ------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ExecutionEngine/Orc/MachOPlatform.h" |
10 | |
11 | #include "llvm/BinaryFormat/MachO.h" |
12 | #include "llvm/ExecutionEngine/JITLink/MachO.h" |
13 | #include "llvm/ExecutionEngine/JITLink/aarch64.h" |
14 | #include "llvm/ExecutionEngine/JITLink/x86_64.h" |
15 | #include "llvm/ExecutionEngine/Orc/DebugUtils.h" |
16 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" |
17 | #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" |
18 | #include "llvm/ExecutionEngine/Orc/MachOBuilder.h" |
19 | #include "llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h" |
20 | #include "llvm/Support/BinaryByteStream.h" |
21 | #include "llvm/Support/Debug.h" |
22 | #include <optional> |
23 | |
24 | #define DEBUG_TYPE "orc" |
25 | |
26 | using namespace llvm; |
27 | using namespace llvm::orc; |
28 | using namespace llvm::orc::shared; |
29 | |
30 | namespace llvm { |
31 | namespace orc { |
32 | namespace shared { |
33 | |
34 | using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>; |
35 | using SPSMachOJITDylibDepInfoMap = |
36 | SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>; |
37 | |
38 | class SPSMachOExecutorSymbolFlags; |
39 | |
40 | template <> |
41 | class SPSSerializationTraits<SPSMachOJITDylibDepInfo, |
42 | MachOPlatform::MachOJITDylibDepInfo> { |
43 | public: |
44 | static size_t size(const MachOPlatform::MachOJITDylibDepInfo &DDI) { |
45 | return SPSMachOJITDylibDepInfo::AsArgList::size(Arg: DDI.Sealed, Args: DDI.DepHeaders); |
46 | } |
47 | |
48 | static bool serialize(SPSOutputBuffer &OB, |
49 | const MachOPlatform::MachOJITDylibDepInfo &DDI) { |
50 | return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, Arg: DDI.Sealed, |
51 | Args: DDI.DepHeaders); |
52 | } |
53 | |
54 | static bool deserialize(SPSInputBuffer &IB, |
55 | MachOPlatform::MachOJITDylibDepInfo &DDI) { |
56 | return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, Arg&: DDI.Sealed, |
57 | Args&: DDI.DepHeaders); |
58 | } |
59 | }; |
60 | |
61 | template <> |
62 | class SPSSerializationTraits<SPSMachOExecutorSymbolFlags, |
63 | MachOPlatform::MachOExecutorSymbolFlags> { |
64 | private: |
65 | using UT = std::underlying_type_t<MachOPlatform::MachOExecutorSymbolFlags>; |
66 | |
67 | public: |
68 | static size_t size(const MachOPlatform::MachOExecutorSymbolFlags &SF) { |
69 | return sizeof(UT); |
70 | } |
71 | |
72 | static bool serialize(SPSOutputBuffer &OB, |
73 | const MachOPlatform::MachOExecutorSymbolFlags &SF) { |
74 | return SPSArgList<UT>::serialize(OB, Arg: static_cast<UT>(SF)); |
75 | } |
76 | |
77 | static bool deserialize(SPSInputBuffer &IB, |
78 | MachOPlatform::MachOExecutorSymbolFlags &SF) { |
79 | UT Tmp; |
80 | if (!SPSArgList<UT>::deserialize(IB, Arg&: Tmp)) |
81 | return false; |
82 | SF = static_cast<MachOPlatform::MachOExecutorSymbolFlags>(Tmp); |
83 | return true; |
84 | } |
85 | }; |
86 | |
87 | } // namespace shared |
88 | } // namespace orc |
89 | } // namespace llvm |
90 | |
91 | namespace { |
92 | |
93 | using SPSRegisterSymbolsArgs = |
94 | SPSArgList<SPSExecutorAddr, |
95 | SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr, |
96 | SPSMachOExecutorSymbolFlags>>>; |
97 | |
98 | std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP, |
99 | std::string Name) { |
100 | unsigned PointerSize; |
101 | llvm::endianness Endianness; |
102 | const auto &TT = MOP.getExecutionSession().getTargetTriple(); |
103 | |
104 | switch (TT.getArch()) { |
105 | case Triple::aarch64: |
106 | case Triple::x86_64: |
107 | PointerSize = 8; |
108 | Endianness = llvm::endianness::little; |
109 | break; |
110 | default: |
111 | llvm_unreachable("Unrecognized architecture" ); |
112 | } |
113 | |
114 | return std::make_unique<jitlink::LinkGraph>(args: std::move(Name), args: TT, args&: PointerSize, |
115 | args&: Endianness, |
116 | args&: jitlink::getGenericEdgeKindName); |
117 | } |
118 | |
119 | // Creates a Bootstrap-Complete LinkGraph to run deferred actions. |
120 | class MachOPlatformCompleteBootstrapMaterializationUnit |
121 | : public MaterializationUnit { |
122 | public: |
123 | using SymbolTableVector = |
124 | SmallVector<std::tuple<ExecutorAddr, ExecutorAddr, |
125 | MachOPlatform::MachOExecutorSymbolFlags>>; |
126 | |
127 | MachOPlatformCompleteBootstrapMaterializationUnit( |
128 | MachOPlatform &MOP, StringRef PlatformJDName, |
129 | SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab, |
130 | shared::AllocActions DeferredAAs, ExecutorAddr , |
131 | ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown, |
132 | ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib, |
133 | ExecutorAddr RegisterObjectSymbolTable, |
134 | ExecutorAddr DeregisterObjectSymbolTable) |
135 | : MaterializationUnit( |
136 | {{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}), |
137 | MOP(MOP), PlatformJDName(PlatformJDName), |
138 | CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)), |
139 | SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)), |
140 | MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap), |
141 | PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib), |
142 | DeregisterJITDylib(DeregisterJITDylib), |
143 | RegisterObjectSymbolTable(RegisterObjectSymbolTable), |
144 | DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {} |
145 | |
146 | StringRef getName() const override { |
147 | return "MachOPlatformCompleteBootstrap" ; |
148 | } |
149 | |
150 | void materialize(std::unique_ptr<MaterializationResponsibility> R) override { |
151 | using namespace jitlink; |
152 | auto G = createPlatformGraph(MOP, Name: "<OrcRTCompleteBootstrap>" ); |
153 | auto &PlaceholderSection = |
154 | G->createSection(Name: "__orc_rt_cplt_bs" , Prot: MemProt::Read); |
155 | auto &PlaceholderBlock = |
156 | G->createZeroFillBlock(Parent&: PlaceholderSection, Size: 1, Address: ExecutorAddr(), Alignment: 1, AlignmentOffset: 0); |
157 | G->addDefinedSymbol(Content&: PlaceholderBlock, Offset: 0, Name: *CompleteBootstrapSymbol, Size: 1, |
158 | L: Linkage::Strong, S: Scope::Hidden, IsCallable: false, IsLive: true); |
159 | |
160 | // Reserve space for the stolen actions, plus two extras. |
161 | G->allocActions().reserve(n: DeferredAAs.size() + 3); |
162 | |
163 | // 1. Bootstrap the platform support code. |
164 | G->allocActions().push_back( |
165 | x: {.Finalize: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSArgList<>>(FnAddr: PlatformBootstrap)), |
166 | .Dealloc: cantFail( |
167 | ValOrErr: WrapperFunctionCall::Create<SPSArgList<>>(FnAddr: PlatformShutdown))}); |
168 | |
169 | // 2. Register the platform JITDylib. |
170 | G->allocActions().push_back( |
171 | x: {.Finalize: cantFail(ValOrErr: WrapperFunctionCall::Create< |
172 | SPSArgList<SPSString, SPSExecutorAddr>>( |
173 | FnAddr: RegisterJITDylib, Args: PlatformJDName, Args: MachOHeaderAddr)), |
174 | .Dealloc: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( |
175 | FnAddr: DeregisterJITDylib, Args: MachOHeaderAddr))}); |
176 | |
177 | // 3. Register deferred symbols. |
178 | G->allocActions().push_back( |
179 | x: {.Finalize: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( |
180 | FnAddr: RegisterObjectSymbolTable, Args: MachOHeaderAddr, Args: SymTab)), |
181 | .Dealloc: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( |
182 | FnAddr: DeregisterObjectSymbolTable, Args: MachOHeaderAddr, Args: SymTab))}); |
183 | |
184 | // 4. Add the deferred actions to the graph. |
185 | std::move(first: DeferredAAs.begin(), last: DeferredAAs.end(), |
186 | result: std::back_inserter(x&: G->allocActions())); |
187 | |
188 | MOP.getObjectLinkingLayer().emit(R: std::move(R), G: std::move(G)); |
189 | } |
190 | |
191 | void discard(const JITDylib &JD, const SymbolStringPtr &Sym) override {} |
192 | |
193 | private: |
194 | MachOPlatform &MOP; |
195 | StringRef PlatformJDName; |
196 | SymbolStringPtr CompleteBootstrapSymbol; |
197 | SymbolTableVector SymTab; |
198 | shared::AllocActions DeferredAAs; |
199 | ExecutorAddr ; |
200 | ExecutorAddr PlatformBootstrap; |
201 | ExecutorAddr PlatformShutdown; |
202 | ExecutorAddr RegisterJITDylib; |
203 | ExecutorAddr DeregisterJITDylib; |
204 | ExecutorAddr RegisterObjectSymbolTable; |
205 | ExecutorAddr DeregisterObjectSymbolTable; |
206 | }; |
207 | |
208 | static StringRef ObjCRuntimeObjectSectionsData[] = { |
209 | MachOObjCCatListSectionName, MachOObjCCatList2SectionName, |
210 | MachOObjCClassListSectionName, MachOObjCClassRefsSectionName, |
211 | MachOObjCConstSectionName, MachOObjCDataSectionName, |
212 | MachOObjCProtoListSectionName, MachOObjCProtoRefsSectionName, |
213 | MachOObjCNLCatListSectionName, MachOObjCNLClassListSectionName, |
214 | MachOObjCSelRefsSectionName}; |
215 | |
216 | static StringRef ObjCRuntimeObjectSectionsText[] = { |
217 | MachOObjCClassNameSectionName, MachOObjCMethNameSectionName, |
218 | MachOObjCMethTypeSectionName, MachOSwift5TypesSectionName, |
219 | MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName, |
220 | MachOSwift5EntrySectionName, MachOSwift5ProtoSectionName, |
221 | MachOSwift5ProtosSectionName}; |
222 | |
223 | static StringRef ObjCRuntimeObjectSectionName = |
224 | "__llvm_jitlink_ObjCRuntimeRegistrationObject" ; |
225 | |
226 | static StringRef ObjCImageInfoSymbolName = |
227 | "__llvm_jitlink_macho_objc_imageinfo" ; |
228 | |
229 | struct ObjCImageInfoFlags { |
230 | uint16_t SwiftABIVersion; |
231 | uint16_t SwiftVersion; |
232 | bool HasCategoryClassProperties; |
233 | bool HasSignedObjCClassROs; |
234 | |
235 | static constexpr uint32_t SIGNED_CLASS_RO = (1 << 4); |
236 | static constexpr uint32_t HAS_CATEGORY_CLASS_PROPERTIES = (1 << 6); |
237 | |
238 | explicit ObjCImageInfoFlags(uint32_t RawFlags) { |
239 | HasSignedObjCClassROs = RawFlags & SIGNED_CLASS_RO; |
240 | HasCategoryClassProperties = RawFlags & HAS_CATEGORY_CLASS_PROPERTIES; |
241 | SwiftABIVersion = (RawFlags >> 8) & 0xFF; |
242 | SwiftVersion = (RawFlags >> 16) & 0xFFFF; |
243 | } |
244 | |
245 | uint32_t rawFlags() const { |
246 | uint32_t Result = 0; |
247 | if (HasCategoryClassProperties) |
248 | Result |= HAS_CATEGORY_CLASS_PROPERTIES; |
249 | if (HasSignedObjCClassROs) |
250 | Result |= SIGNED_CLASS_RO; |
251 | Result |= (SwiftABIVersion << 8); |
252 | Result |= (SwiftVersion << 16); |
253 | return Result; |
254 | } |
255 | }; |
256 | } // end anonymous namespace |
257 | |
258 | namespace llvm { |
259 | namespace orc { |
260 | |
261 | std::optional<MachOPlatform::HeaderOptions::BuildVersionOpts> |
262 | MachOPlatform::HeaderOptions::BuildVersionOpts::(const Triple &TT, |
263 | uint32_t MinOS, |
264 | uint32_t SDK) { |
265 | |
266 | uint32_t Platform; |
267 | switch (TT.getOS()) { |
268 | case Triple::IOS: |
269 | Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_IOSSIMULATOR |
270 | : MachO::PLATFORM_IOS; |
271 | break; |
272 | case Triple::MacOSX: |
273 | Platform = MachO::PLATFORM_MACOS; |
274 | break; |
275 | case Triple::TvOS: |
276 | Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_TVOSSIMULATOR |
277 | : MachO::PLATFORM_TVOS; |
278 | break; |
279 | case Triple::WatchOS: |
280 | Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_WATCHOSSIMULATOR |
281 | : MachO::PLATFORM_WATCHOS; |
282 | break; |
283 | case Triple::XROS: |
284 | Platform = TT.isSimulatorEnvironment() ? MachO::PLATFORM_XROS_SIMULATOR |
285 | : MachO::PLATFORM_XROS; |
286 | break; |
287 | default: |
288 | return std::nullopt; |
289 | } |
290 | |
291 | return MachOPlatform::HeaderOptions::BuildVersionOpts{.Platform: Platform, .MinOS: MinOS, .SDK: SDK}; |
292 | } |
293 | |
294 | Expected<std::unique_ptr<MachOPlatform>> MachOPlatform::Create( |
295 | ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
296 | JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime, |
297 | HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder , |
298 | std::optional<SymbolAliasMap> RuntimeAliases) { |
299 | |
300 | // If the target is not supported then bail out immediately. |
301 | if (!supportedTarget(TT: ES.getTargetTriple())) |
302 | return make_error<StringError>(Args: "Unsupported MachOPlatform triple: " + |
303 | ES.getTargetTriple().str(), |
304 | Args: inconvertibleErrorCode()); |
305 | |
306 | auto &EPC = ES.getExecutorProcessControl(); |
307 | |
308 | // Create default aliases if the caller didn't supply any. |
309 | if (!RuntimeAliases) |
310 | RuntimeAliases = standardPlatformAliases(ES); |
311 | |
312 | // Define the aliases. |
313 | if (auto Err = PlatformJD.define(MU: symbolAliases(Aliases: std::move(*RuntimeAliases)))) |
314 | return std::move(Err); |
315 | |
316 | // Add JIT-dispatch function support symbols. |
317 | if (auto Err = PlatformJD.define( |
318 | MU: absoluteSymbols(Symbols: {{ES.intern(SymName: "___orc_rt_jit_dispatch" ), |
319 | {EPC.getJITDispatchInfo().JITDispatchFunction, |
320 | JITSymbolFlags::Exported}}, |
321 | {ES.intern(SymName: "___orc_rt_jit_dispatch_ctx" ), |
322 | {EPC.getJITDispatchInfo().JITDispatchContext, |
323 | JITSymbolFlags::Exported}}}))) |
324 | return std::move(Err); |
325 | |
326 | // Create the instance. |
327 | Error Err = Error::success(); |
328 | auto P = std::unique_ptr<MachOPlatform>(new MachOPlatform( |
329 | ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), |
330 | std::move(PlatformJDOpts), std::move(BuildMachOHeaderMU), Err)); |
331 | if (Err) |
332 | return std::move(Err); |
333 | return std::move(P); |
334 | } |
335 | |
336 | Expected<std::unique_ptr<MachOPlatform>> |
337 | MachOPlatform::(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
338 | JITDylib &PlatformJD, const char *OrcRuntimePath, |
339 | HeaderOptions PlatformJDOpts, |
340 | MachOHeaderMUBuilder , |
341 | std::optional<SymbolAliasMap> RuntimeAliases) { |
342 | |
343 | // Create a generator for the ORC runtime archive. |
344 | auto OrcRuntimeArchiveGenerator = |
345 | StaticLibraryDefinitionGenerator::Load(L&: ObjLinkingLayer, FileName: OrcRuntimePath); |
346 | if (!OrcRuntimeArchiveGenerator) |
347 | return OrcRuntimeArchiveGenerator.takeError(); |
348 | |
349 | return Create(ES, ObjLinkingLayer, PlatformJD, |
350 | OrcRuntime: std::move(*OrcRuntimeArchiveGenerator), |
351 | PlatformJDOpts: std::move(PlatformJDOpts), BuildMachOHeaderMU: std::move(BuildMachOHeaderMU), |
352 | RuntimeAliases: std::move(RuntimeAliases)); |
353 | } |
354 | |
355 | Error MachOPlatform::setupJITDylib(JITDylib &JD) { |
356 | return setupJITDylib(JD, /*Opts=*/{}); |
357 | } |
358 | |
359 | Error MachOPlatform::(JITDylib &JD, HeaderOptions Opts) { |
360 | if (auto Err = JD.define(MU: BuildMachOHeaderMU(*this, std::move(Opts)))) |
361 | return Err; |
362 | |
363 | return ES.lookup(SearchOrder: {&JD}, Symbol: MachOHeaderStartSymbol).takeError(); |
364 | } |
365 | |
366 | Error MachOPlatform::teardownJITDylib(JITDylib &JD) { |
367 | std::lock_guard<std::mutex> Lock(PlatformMutex); |
368 | auto I = JITDylibToHeaderAddr.find(Val: &JD); |
369 | if (I != JITDylibToHeaderAddr.end()) { |
370 | assert(HeaderAddrToJITDylib.count(I->second) && |
371 | "HeaderAddrToJITDylib missing entry" ); |
372 | HeaderAddrToJITDylib.erase(Val: I->second); |
373 | JITDylibToHeaderAddr.erase(I); |
374 | } |
375 | JITDylibToPThreadKey.erase(Val: &JD); |
376 | return Error::success(); |
377 | } |
378 | |
379 | Error MachOPlatform::notifyAdding(ResourceTracker &RT, |
380 | const MaterializationUnit &MU) { |
381 | auto &JD = RT.getJITDylib(); |
382 | const auto &InitSym = MU.getInitializerSymbol(); |
383 | if (!InitSym) |
384 | return Error::success(); |
385 | |
386 | RegisteredInitSymbols[&JD].add(Name: InitSym, |
387 | Flags: SymbolLookupFlags::WeaklyReferencedSymbol); |
388 | LLVM_DEBUG({ |
389 | dbgs() << "MachOPlatform: Registered init symbol " << *InitSym << " for MU " |
390 | << MU.getName() << "\n" ; |
391 | }); |
392 | return Error::success(); |
393 | } |
394 | |
395 | Error MachOPlatform::notifyRemoving(ResourceTracker &RT) { |
396 | llvm_unreachable("Not supported yet" ); |
397 | } |
398 | |
399 | static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases, |
400 | ArrayRef<std::pair<const char *, const char *>> AL) { |
401 | for (auto &KV : AL) { |
402 | auto AliasName = ES.intern(SymName: KV.first); |
403 | assert(!Aliases.count(AliasName) && "Duplicate symbol name in alias map" ); |
404 | Aliases[std::move(AliasName)] = {ES.intern(SymName: KV.second), |
405 | JITSymbolFlags::Exported}; |
406 | } |
407 | } |
408 | |
409 | SymbolAliasMap MachOPlatform::standardPlatformAliases(ExecutionSession &ES) { |
410 | SymbolAliasMap Aliases; |
411 | addAliases(ES, Aliases, AL: requiredCXXAliases()); |
412 | addAliases(ES, Aliases, AL: standardRuntimeUtilityAliases()); |
413 | return Aliases; |
414 | } |
415 | |
416 | ArrayRef<std::pair<const char *, const char *>> |
417 | MachOPlatform::requiredCXXAliases() { |
418 | static const std::pair<const char *, const char *> RequiredCXXAliases[] = { |
419 | {"___cxa_atexit" , "___orc_rt_macho_cxa_atexit" }}; |
420 | |
421 | return ArrayRef<std::pair<const char *, const char *>>(RequiredCXXAliases); |
422 | } |
423 | |
424 | ArrayRef<std::pair<const char *, const char *>> |
425 | MachOPlatform::standardRuntimeUtilityAliases() { |
426 | static const std::pair<const char *, const char *> |
427 | StandardRuntimeUtilityAliases[] = { |
428 | {"___orc_rt_run_program" , "___orc_rt_macho_run_program" }, |
429 | {"___orc_rt_jit_dlerror" , "___orc_rt_macho_jit_dlerror" }, |
430 | {"___orc_rt_jit_dlopen" , "___orc_rt_macho_jit_dlopen" }, |
431 | {"___orc_rt_jit_dlclose" , "___orc_rt_macho_jit_dlclose" }, |
432 | {"___orc_rt_jit_dlsym" , "___orc_rt_macho_jit_dlsym" }, |
433 | {"___orc_rt_log_error" , "___orc_rt_log_error_to_stderr" }}; |
434 | |
435 | return ArrayRef<std::pair<const char *, const char *>>( |
436 | StandardRuntimeUtilityAliases); |
437 | } |
438 | |
439 | bool MachOPlatform::supportedTarget(const Triple &TT) { |
440 | switch (TT.getArch()) { |
441 | case Triple::aarch64: |
442 | case Triple::x86_64: |
443 | return true; |
444 | default: |
445 | return false; |
446 | } |
447 | } |
448 | |
449 | jitlink::Edge::Kind MachOPlatform::getPointerEdgeKind(jitlink::LinkGraph &G) { |
450 | switch (G.getTargetTriple().getArch()) { |
451 | case Triple::aarch64: |
452 | return jitlink::aarch64::Pointer64; |
453 | case Triple::x86_64: |
454 | return jitlink::x86_64::Pointer64; |
455 | default: |
456 | llvm_unreachable("Unsupported architecture" ); |
457 | } |
458 | } |
459 | |
460 | MachOPlatform::MachOExecutorSymbolFlags |
461 | MachOPlatform::flagsForSymbol(jitlink::Symbol &Sym) { |
462 | MachOPlatform::MachOExecutorSymbolFlags Flags{}; |
463 | if (Sym.getLinkage() == jitlink::Linkage::Weak) |
464 | Flags |= MachOExecutorSymbolFlags::Weak; |
465 | |
466 | if (Sym.isCallable()) |
467 | Flags |= MachOExecutorSymbolFlags::Callable; |
468 | |
469 | return Flags; |
470 | } |
471 | |
472 | MachOPlatform::MachOPlatform( |
473 | ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer, |
474 | JITDylib &PlatformJD, |
475 | std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, |
476 | HeaderOptions PlatformJDOpts, MachOHeaderMUBuilder , |
477 | Error &Err) |
478 | : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer), |
479 | BuildMachOHeaderMU(std::move(BuildMachOHeaderMU)) { |
480 | ErrorAsOutParameter _(&Err); |
481 | ObjLinkingLayer.addPlugin(P: std::make_unique<MachOPlatformPlugin>(args&: *this)); |
482 | PlatformJD.addGenerator(DefGenerator: std::move(OrcRuntimeGenerator)); |
483 | |
484 | BootstrapInfo BI; |
485 | Bootstrap = &BI; |
486 | |
487 | // Bootstrap process -- here be phase-ordering dragons. |
488 | // |
489 | // The MachOPlatform class uses allocation actions to register metadata |
490 | // sections with the ORC runtime, however the runtime contains metadata |
491 | // registration functions that have their own metadata that they need to |
492 | // register (e.g. the frame-info registration functions have frame-info). |
493 | // We can't use an ordinary lookup to find these registration functions |
494 | // because their address is needed during the link of the containing graph |
495 | // itself (to build the allocation actions that will call the registration |
496 | // functions). Further complicating the situation (a) the graph containing |
497 | // the registration functions is allowed to depend on other graphs (e.g. the |
498 | // graph containing the ORC runtime RTTI support) so we need to handle an |
499 | // unknown set of dependencies during bootstrap, and (b) these graphs may |
500 | // be linked concurrently if the user has installed a concurrent dispatcher. |
501 | // |
502 | // We satisfy these constraints by implementing a bootstrap phase during which |
503 | // allocation actions generated by MachOPlatform are appended to a list of |
504 | // deferred allocation actions, rather than to the graphs themselves. At the |
505 | // end of the bootstrap process the deferred actions are attached to a final |
506 | // "complete-bootstrap" graph that causes them to be run. |
507 | // |
508 | // The bootstrap steps are as follows: |
509 | // |
510 | // 1. Request the graph containing the mach header. This graph is guaranteed |
511 | // not to have any metadata so the fact that the registration functions |
512 | // are not available yet is not a problem. |
513 | // |
514 | // 2. Look up the registration functions and discard the results. This will |
515 | // trigger linking of the graph containing these functions, and |
516 | // consequently any graphs that it depends on. We do not use the lookup |
517 | // result to find the addresses of the functions requested (as described |
518 | // above the lookup will return too late for that), instead we capture the |
519 | // addresses in a post-allocation pass injected by the platform runtime |
520 | // during bootstrap only. |
521 | // |
522 | // 3. During bootstrap the MachOPlatformPlugin keeps a count of the number of |
523 | // graphs being linked (potentially concurrently), and we block until all |
524 | // of these graphs have completed linking. This is to avoid a race on the |
525 | // deferred-actions vector: the lookup for the runtime registration |
526 | // functions may return while some functions (those that are being |
527 | // incidentally linked in, but aren't reachable via the runtime functions) |
528 | // are still being linked, and we need to capture any allocation actions |
529 | // for this incidental code before we proceed. |
530 | // |
531 | // 4. Once all active links are complete we transfer the deferred actions to |
532 | // a newly added CompleteBootstrap graph and then request a symbol from |
533 | // the CompleteBootstrap graph to trigger materialization. This will cause |
534 | // all deferred actions to be run, and once this lookup returns we can |
535 | // proceed. |
536 | // |
537 | // 5. Finally, we associate runtime support methods in MachOPlatform with |
538 | // the corresponding jit-dispatch tag variables in the ORC runtime to make |
539 | // the support methods callable. The bootstrap is now complete. |
540 | |
541 | // Step (1) Add header materialization unit and request. |
542 | if ((Err = PlatformJD.define( |
543 | MU: this->BuildMachOHeaderMU(*this, std::move(PlatformJDOpts))))) |
544 | return; |
545 | if ((Err = ES.lookup(SearchOrder: &PlatformJD, Symbol: MachOHeaderStartSymbol).takeError())) |
546 | return; |
547 | |
548 | // Step (2) Request runtime registration functions to trigger |
549 | // materialization.. |
550 | if ((Err = ES.lookup(SearchOrder: makeJITDylibSearchOrder(JDs: &PlatformJD), |
551 | Symbols: SymbolLookupSet( |
552 | {PlatformBootstrap.Name, PlatformShutdown.Name, |
553 | RegisterJITDylib.Name, DeregisterJITDylib.Name, |
554 | RegisterObjectSymbolTable.Name, |
555 | DeregisterObjectSymbolTable.Name, |
556 | RegisterObjectPlatformSections.Name, |
557 | DeregisterObjectPlatformSections.Name, |
558 | CreatePThreadKey.Name})) |
559 | .takeError())) |
560 | return; |
561 | |
562 | // Step (3) Wait for any incidental linker work to complete. |
563 | { |
564 | std::unique_lock<std::mutex> Lock(BI.Mutex); |
565 | BI.CV.wait(lock&: Lock, p: [&]() { return BI.ActiveGraphs == 0; }); |
566 | Bootstrap = nullptr; |
567 | } |
568 | |
569 | // Step (4) Add complete-bootstrap materialization unit and request. |
570 | auto BootstrapCompleteSymbol = ES.intern(SymName: "__orc_rt_macho_complete_bootstrap" ); |
571 | if ((Err = PlatformJD.define( |
572 | MU: std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>( |
573 | args&: *this, args: PlatformJD.getName(), args&: BootstrapCompleteSymbol, |
574 | args: std::move(BI.SymTab), args: std::move(BI.DeferredAAs), |
575 | args&: BI.MachOHeaderAddr, args&: PlatformBootstrap.Addr, |
576 | args&: PlatformShutdown.Addr, args&: RegisterJITDylib.Addr, |
577 | args&: DeregisterJITDylib.Addr, args&: RegisterObjectSymbolTable.Addr, |
578 | args&: DeregisterObjectSymbolTable.Addr)))) |
579 | return; |
580 | if ((Err = ES.lookup(SearchOrder: makeJITDylibSearchOrder( |
581 | JDs: &PlatformJD, Flags: JITDylibLookupFlags::MatchAllSymbols), |
582 | Symbol: std::move(BootstrapCompleteSymbol)) |
583 | .takeError())) |
584 | return; |
585 | |
586 | // (5) Associate runtime support functions. |
587 | if ((Err = associateRuntimeSupportFunctions())) |
588 | return; |
589 | } |
590 | |
591 | Error MachOPlatform::associateRuntimeSupportFunctions() { |
592 | ExecutionSession::JITDispatchHandlerAssociationMap WFs; |
593 | |
594 | using = |
595 | SPSExpected<SPSMachOJITDylibDepInfoMap>(SPSExecutorAddr); |
596 | WFs[ES.intern(SymName: "___orc_rt_macho_push_initializers_tag" )] = |
597 | ES.wrapAsyncWithSPS<PushInitializersSPSSig>( |
598 | Instance: this, Method: &MachOPlatform::rt_pushInitializers); |
599 | |
600 | using PushSymbolsSPSSig = |
601 | SPSError(SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>); |
602 | WFs[ES.intern(SymName: "___orc_rt_macho_push_symbols_tag" )] = |
603 | ES.wrapAsyncWithSPS<PushSymbolsSPSSig>(Instance: this, |
604 | Method: &MachOPlatform::rt_pushSymbols); |
605 | |
606 | return ES.registerJITDispatchHandlers(JD&: PlatformJD, WFs: std::move(WFs)); |
607 | } |
608 | |
609 | void MachOPlatform::pushInitializersLoop( |
610 | PushInitializersSendResultFn SendResult, JITDylibSP JD) { |
611 | DenseMap<JITDylib *, SymbolLookupSet> NewInitSymbols; |
612 | DenseMap<JITDylib *, SmallVector<JITDylib *>> JDDepMap; |
613 | SmallVector<JITDylib *, 16> Worklist({JD.get()}); |
614 | |
615 | ES.runSessionLocked(F: [&]() { |
616 | while (!Worklist.empty()) { |
617 | // FIXME: Check for defunct dylibs. |
618 | |
619 | auto DepJD = Worklist.back(); |
620 | Worklist.pop_back(); |
621 | |
622 | // If we've already visited this JITDylib on this iteration then continue. |
623 | if (JDDepMap.count(Val: DepJD)) |
624 | continue; |
625 | |
626 | // Add dep info. |
627 | auto &DM = JDDepMap[DepJD]; |
628 | DepJD->withLinkOrderDo(F: [&](const JITDylibSearchOrder &O) { |
629 | for (auto &KV : O) { |
630 | if (KV.first == DepJD) |
631 | continue; |
632 | DM.push_back(Elt: KV.first); |
633 | Worklist.push_back(Elt: KV.first); |
634 | } |
635 | }); |
636 | |
637 | // Add any registered init symbols. |
638 | auto RISItr = RegisteredInitSymbols.find(Val: DepJD); |
639 | if (RISItr != RegisteredInitSymbols.end()) { |
640 | NewInitSymbols[DepJD] = std::move(RISItr->second); |
641 | RegisteredInitSymbols.erase(I: RISItr); |
642 | } |
643 | } |
644 | }); |
645 | |
646 | // If there are no further init symbols to look up then send the link order |
647 | // (as a list of header addresses) to the caller. |
648 | if (NewInitSymbols.empty()) { |
649 | |
650 | // To make the list intelligible to the runtime we need to convert all |
651 | // JITDylib pointers to their header addresses. Only include JITDylibs |
652 | // that appear in the JITDylibToHeaderAddr map (i.e. those that have been |
653 | // through setupJITDylib) -- bare JITDylibs aren't managed by the platform. |
654 | DenseMap<JITDylib *, ExecutorAddr> ; |
655 | HeaderAddrs.reserve(NumEntries: JDDepMap.size()); |
656 | { |
657 | std::lock_guard<std::mutex> Lock(PlatformMutex); |
658 | for (auto &KV : JDDepMap) { |
659 | auto I = JITDylibToHeaderAddr.find(Val: KV.first); |
660 | if (I != JITDylibToHeaderAddr.end()) |
661 | HeaderAddrs[KV.first] = I->second; |
662 | } |
663 | } |
664 | |
665 | // Build the dep info map to return. |
666 | MachOJITDylibDepInfoMap DIM; |
667 | DIM.reserve(n: JDDepMap.size()); |
668 | for (auto &KV : JDDepMap) { |
669 | auto HI = HeaderAddrs.find(Val: KV.first); |
670 | // Skip unmanaged JITDylibs. |
671 | if (HI == HeaderAddrs.end()) |
672 | continue; |
673 | auto H = HI->second; |
674 | MachOJITDylibDepInfo DepInfo; |
675 | for (auto &Dep : KV.second) { |
676 | auto HJ = HeaderAddrs.find(Val: Dep); |
677 | if (HJ != HeaderAddrs.end()) |
678 | DepInfo.DepHeaders.push_back(x: HJ->second); |
679 | } |
680 | DIM.push_back(x: std::make_pair(x&: H, y: std::move(DepInfo))); |
681 | } |
682 | SendResult(DIM); |
683 | return; |
684 | } |
685 | |
686 | // Otherwise issue a lookup and re-run this phase when it completes. |
687 | lookupInitSymbolsAsync( |
688 | OnComplete: [this, SendResult = std::move(SendResult), JD](Error Err) mutable { |
689 | if (Err) |
690 | SendResult(std::move(Err)); |
691 | else |
692 | pushInitializersLoop(SendResult: std::move(SendResult), JD); |
693 | }, |
694 | ES, InitSyms: std::move(NewInitSymbols)); |
695 | } |
696 | |
697 | void MachOPlatform::rt_pushInitializers(PushInitializersSendResultFn SendResult, |
698 | ExecutorAddr ) { |
699 | JITDylibSP JD; |
700 | { |
701 | std::lock_guard<std::mutex> Lock(PlatformMutex); |
702 | auto I = HeaderAddrToJITDylib.find(Val: JDHeaderAddr); |
703 | if (I != HeaderAddrToJITDylib.end()) |
704 | JD = I->second; |
705 | } |
706 | |
707 | LLVM_DEBUG({ |
708 | dbgs() << "MachOPlatform::rt_pushInitializers(" << JDHeaderAddr << ") " ; |
709 | if (JD) |
710 | dbgs() << "pushing initializers for " << JD->getName() << "\n" ; |
711 | else |
712 | dbgs() << "No JITDylib for header address.\n" ; |
713 | }); |
714 | |
715 | if (!JD) { |
716 | SendResult(make_error<StringError>(Args: "No JITDylib with header addr " + |
717 | formatv(Fmt: "{0:x}" , Vals&: JDHeaderAddr), |
718 | Args: inconvertibleErrorCode())); |
719 | return; |
720 | } |
721 | |
722 | pushInitializersLoop(SendResult: std::move(SendResult), JD); |
723 | } |
724 | |
725 | void MachOPlatform::rt_pushSymbols( |
726 | PushSymbolsInSendResultFn SendResult, ExecutorAddr Handle, |
727 | const std::vector<std::pair<StringRef, bool>> &SymbolNames) { |
728 | |
729 | JITDylib *JD = nullptr; |
730 | |
731 | { |
732 | std::lock_guard<std::mutex> Lock(PlatformMutex); |
733 | auto I = HeaderAddrToJITDylib.find(Val: Handle); |
734 | if (I != HeaderAddrToJITDylib.end()) |
735 | JD = I->second; |
736 | } |
737 | LLVM_DEBUG({ |
738 | dbgs() << "MachOPlatform::rt_pushSymbols(" ; |
739 | if (JD) |
740 | dbgs() << "\"" << JD->getName() << "\", [ " ; |
741 | else |
742 | dbgs() << "<invalid handle " << Handle << ">, [ " ; |
743 | for (auto &Name : SymbolNames) |
744 | dbgs() << "\"" << Name.first << "\" " ; |
745 | dbgs() << "])\n" ; |
746 | }); |
747 | |
748 | if (!JD) { |
749 | SendResult(make_error<StringError>(Args: "No JITDylib associated with handle " + |
750 | formatv(Fmt: "{0:x}" , Vals&: Handle), |
751 | Args: inconvertibleErrorCode())); |
752 | return; |
753 | } |
754 | |
755 | SymbolLookupSet LS; |
756 | for (auto &[Name, Required] : SymbolNames) |
757 | LS.add(Name: ES.intern(SymName: Name), Flags: Required |
758 | ? SymbolLookupFlags::RequiredSymbol |
759 | : SymbolLookupFlags::WeaklyReferencedSymbol); |
760 | |
761 | ES.lookup( |
762 | K: LookupKind::DLSym, SearchOrder: {{JD, JITDylibLookupFlags::MatchExportedSymbolsOnly}}, |
763 | Symbols: std::move(LS), RequiredState: SymbolState::Ready, |
764 | NotifyComplete: [SendResult = std::move(SendResult)](Expected<SymbolMap> Result) mutable { |
765 | SendResult(Result.takeError()); |
766 | }, |
767 | RegisterDependencies: NoDependenciesToRegister); |
768 | } |
769 | |
770 | Expected<uint64_t> MachOPlatform::createPThreadKey() { |
771 | if (!CreatePThreadKey.Addr) |
772 | return make_error<StringError>( |
773 | Args: "Attempting to create pthread key in target, but runtime support has " |
774 | "not been loaded yet" , |
775 | Args: inconvertibleErrorCode()); |
776 | |
777 | Expected<uint64_t> Result(0); |
778 | if (auto Err = ES.callSPSWrapper<SPSExpected<uint64_t>(void)>( |
779 | WrapperFnAddr: CreatePThreadKey.Addr, WrapperCallArgs&: Result)) |
780 | return std::move(Err); |
781 | return Result; |
782 | } |
783 | |
784 | void MachOPlatform::MachOPlatformPlugin::modifyPassConfig( |
785 | MaterializationResponsibility &MR, jitlink::LinkGraph &LG, |
786 | jitlink::PassConfiguration &Config) { |
787 | |
788 | using namespace jitlink; |
789 | |
790 | bool InBootstrapPhase = |
791 | &MR.getTargetJITDylib() == &MP.PlatformJD && MP.Bootstrap; |
792 | |
793 | // If we're in the bootstrap phase then increment the active graphs. |
794 | if (InBootstrapPhase) { |
795 | Config.PrePrunePasses.push_back( |
796 | x: [this](LinkGraph &G) { return bootstrapPipelineStart(G); }); |
797 | Config.PostAllocationPasses.push_back(x: [this](LinkGraph &G) { |
798 | return bootstrapPipelineRecordRuntimeFunctions(G); |
799 | }); |
800 | } |
801 | |
802 | // --- Handle Initializers --- |
803 | if (auto InitSymbol = MR.getInitializerSymbol()) { |
804 | |
805 | // If the initializer symbol is the MachOHeader start symbol then just |
806 | // register it and then bail out -- the header materialization unit |
807 | // definitely doesn't need any other passes. |
808 | if (InitSymbol == MP.MachOHeaderStartSymbol && !InBootstrapPhase) { |
809 | Config.PostAllocationPasses.push_back(x: [this, &MR](LinkGraph &G) { |
810 | return associateJITDylibHeaderSymbol(G, MR); |
811 | }); |
812 | return; |
813 | } |
814 | |
815 | // If the object contains an init symbol other than the header start symbol |
816 | // then add passes to preserve, process and register the init |
817 | // sections/symbols. |
818 | Config.PrePrunePasses.push_back(x: [this, &MR](LinkGraph &G) { |
819 | if (auto Err = preserveImportantSections(G, MR)) |
820 | return Err; |
821 | return processObjCImageInfo(G, MR); |
822 | }); |
823 | Config.PostPrunePasses.push_back( |
824 | x: [this](LinkGraph &G) { return createObjCRuntimeObject(G); }); |
825 | Config.PostAllocationPasses.push_back( |
826 | x: [this, &MR](LinkGraph &G) { return populateObjCRuntimeObject(G, MR); }); |
827 | } |
828 | |
829 | // Insert TLV lowering at the start of the PostPrunePasses, since we want |
830 | // it to run before GOT/PLT lowering. |
831 | Config.PostPrunePasses.insert( |
832 | position: Config.PostPrunePasses.begin(), |
833 | x: [this, &JD = MR.getTargetJITDylib()](LinkGraph &G) { |
834 | return fixTLVSectionsAndEdges(G, JD); |
835 | }); |
836 | |
837 | // Add symbol table prepare and register passes: These will add strings for |
838 | // all symbols to the c-strings section, and build a symbol table registration |
839 | // call. |
840 | auto JITSymTabInfo = std::make_shared<JITSymTabVector>(); |
841 | Config.PostPrunePasses.push_back(x: [this, JITSymTabInfo](LinkGraph &G) { |
842 | return prepareSymbolTableRegistration(G, JITSymTabInfo&: *JITSymTabInfo); |
843 | }); |
844 | Config.PostFixupPasses.push_back(x: [this, &MR, JITSymTabInfo, |
845 | InBootstrapPhase](LinkGraph &G) { |
846 | return addSymbolTableRegistration(G, MR, JITSymTabInfo&: *JITSymTabInfo, InBootstrapPhase); |
847 | }); |
848 | |
849 | // Add a pass to register the final addresses of any special sections in the |
850 | // object with the runtime. |
851 | Config.PostAllocationPasses.push_back( |
852 | x: [this, &JD = MR.getTargetJITDylib(), InBootstrapPhase](LinkGraph &G) { |
853 | return registerObjectPlatformSections(G, JD, InBootstrapPhase); |
854 | }); |
855 | |
856 | // If we're in the bootstrap phase then steal allocation actions and then |
857 | // decrement the active graphs. |
858 | if (InBootstrapPhase) |
859 | Config.PostFixupPasses.push_back( |
860 | x: [this](LinkGraph &G) { return bootstrapPipelineEnd(G); }); |
861 | } |
862 | |
863 | ObjectLinkingLayer::Plugin::SyntheticSymbolDependenciesMap |
864 | MachOPlatform::MachOPlatformPlugin::getSyntheticSymbolDependencies( |
865 | MaterializationResponsibility &MR) { |
866 | std::lock_guard<std::mutex> Lock(PluginMutex); |
867 | auto I = InitSymbolDeps.find(Val: &MR); |
868 | if (I != InitSymbolDeps.end()) { |
869 | SyntheticSymbolDependenciesMap Result; |
870 | Result[MR.getInitializerSymbol()] = std::move(I->second); |
871 | InitSymbolDeps.erase(Val: &MR); |
872 | return Result; |
873 | } |
874 | return SyntheticSymbolDependenciesMap(); |
875 | } |
876 | |
877 | Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineStart( |
878 | jitlink::LinkGraph &G) { |
879 | // Increment the active graphs count in BootstrapInfo. |
880 | std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); |
881 | ++MP.Bootstrap.load()->ActiveGraphs; |
882 | return Error::success(); |
883 | } |
884 | |
885 | Error MachOPlatform::MachOPlatformPlugin:: |
886 | bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G) { |
887 | // Record bootstrap function names. |
888 | std::pair<StringRef, ExecutorAddr *> RuntimeSymbols[] = { |
889 | {*MP.MachOHeaderStartSymbol, &MP.Bootstrap.load()->MachOHeaderAddr}, |
890 | {*MP.PlatformBootstrap.Name, &MP.PlatformBootstrap.Addr}, |
891 | {*MP.PlatformShutdown.Name, &MP.PlatformShutdown.Addr}, |
892 | {*MP.RegisterJITDylib.Name, &MP.RegisterJITDylib.Addr}, |
893 | {*MP.DeregisterJITDylib.Name, &MP.DeregisterJITDylib.Addr}, |
894 | {*MP.RegisterObjectSymbolTable.Name, &MP.RegisterObjectSymbolTable.Addr}, |
895 | {*MP.DeregisterObjectSymbolTable.Name, |
896 | &MP.DeregisterObjectSymbolTable.Addr}, |
897 | {*MP.RegisterObjectPlatformSections.Name, |
898 | &MP.RegisterObjectPlatformSections.Addr}, |
899 | {*MP.DeregisterObjectPlatformSections.Name, |
900 | &MP.DeregisterObjectPlatformSections.Addr}, |
901 | {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}, |
902 | {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr}, |
903 | {*MP.DeregisterObjCRuntimeObject.Name, |
904 | &MP.DeregisterObjCRuntimeObject.Addr}}; |
905 | |
906 | bool = false; |
907 | |
908 | for (auto *Sym : G.defined_symbols()) { |
909 | for (auto &RTSym : RuntimeSymbols) { |
910 | if (Sym->hasName() && Sym->getName() == RTSym.first) { |
911 | if (*RTSym.second) |
912 | return make_error<StringError>( |
913 | Args: "Duplicate " + RTSym.first + |
914 | " detected during MachOPlatform bootstrap" , |
915 | Args: inconvertibleErrorCode()); |
916 | |
917 | if (Sym->getName() == *MP.MachOHeaderStartSymbol) |
918 | RegisterMachOHeader = true; |
919 | |
920 | *RTSym.second = Sym->getAddress(); |
921 | } |
922 | } |
923 | } |
924 | |
925 | if (RegisterMachOHeader) { |
926 | // If this graph defines the macho header symbol then create the internal |
927 | // mapping between it and PlatformJD. |
928 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); |
929 | MP.JITDylibToHeaderAddr[&MP.PlatformJD] = |
930 | MP.Bootstrap.load()->MachOHeaderAddr; |
931 | MP.HeaderAddrToJITDylib[MP.Bootstrap.load()->MachOHeaderAddr] = |
932 | &MP.PlatformJD; |
933 | } |
934 | |
935 | return Error::success(); |
936 | } |
937 | |
938 | Error MachOPlatform::MachOPlatformPlugin::bootstrapPipelineEnd( |
939 | jitlink::LinkGraph &G) { |
940 | std::lock_guard<std::mutex> Lock(MP.Bootstrap.load()->Mutex); |
941 | assert(MP.Bootstrap && "DeferredAAs reset before bootstrap completed" ); |
942 | --MP.Bootstrap.load()->ActiveGraphs; |
943 | // Notify Bootstrap->CV while holding the mutex because the mutex is |
944 | // also keeping Bootstrap->CV alive. |
945 | if (MP.Bootstrap.load()->ActiveGraphs == 0) |
946 | MP.Bootstrap.load()->CV.notify_all(); |
947 | return Error::success(); |
948 | } |
949 | |
950 | Error MachOPlatform::MachOPlatformPlugin::( |
951 | jitlink::LinkGraph &G, MaterializationResponsibility &MR) { |
952 | auto I = llvm::find_if(Range: G.defined_symbols(), P: [this](jitlink::Symbol *Sym) { |
953 | return Sym->getName() == *MP.MachOHeaderStartSymbol; |
954 | }); |
955 | assert(I != G.defined_symbols().end() && "Missing MachO header start symbol" ); |
956 | |
957 | auto &JD = MR.getTargetJITDylib(); |
958 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); |
959 | auto = (*I)->getAddress(); |
960 | MP.JITDylibToHeaderAddr[&JD] = HeaderAddr; |
961 | MP.HeaderAddrToJITDylib[HeaderAddr] = &JD; |
962 | // We can unconditionally add these actions to the Graph because this pass |
963 | // isn't used during bootstrap. |
964 | G.allocActions().push_back( |
965 | x: {.Finalize: cantFail( |
966 | ValOrErr: WrapperFunctionCall::Create<SPSArgList<SPSString, SPSExecutorAddr>>( |
967 | FnAddr: MP.RegisterJITDylib.Addr, Args: JD.getName(), Args: HeaderAddr)), |
968 | .Dealloc: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( |
969 | FnAddr: MP.DeregisterJITDylib.Addr, Args: HeaderAddr))}); |
970 | return Error::success(); |
971 | } |
972 | |
973 | Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections( |
974 | jitlink::LinkGraph &G, MaterializationResponsibility &MR) { |
975 | // __objc_imageinfo is "important": we want to preserve it and record its |
976 | // address in the first graph that it appears in, then verify and discard it |
977 | // in all subsequent graphs. In this pass we preserve unconditionally -- we'll |
978 | // manually throw it away in the processObjCImageInfo pass. |
979 | if (auto *ObjCImageInfoSec = |
980 | G.findSectionByName(Name: MachOObjCImageInfoSectionName)) { |
981 | if (ObjCImageInfoSec->blocks_size() != 1) |
982 | return make_error<StringError>( |
983 | Args: "In " + G.getName() + |
984 | "__DATA,__objc_imageinfo contains multiple blocks" , |
985 | Args: inconvertibleErrorCode()); |
986 | G.addAnonymousSymbol(Content&: **ObjCImageInfoSec->blocks().begin(), Offset: 0, Size: 0, IsCallable: false, |
987 | IsLive: true); |
988 | |
989 | for (auto *B : ObjCImageInfoSec->blocks()) |
990 | if (!B->edges_empty()) |
991 | return make_error<StringError>(Args: "In " + G.getName() + ", " + |
992 | MachOObjCImageInfoSectionName + |
993 | " contains references to symbols" , |
994 | Args: inconvertibleErrorCode()); |
995 | } |
996 | |
997 | // Init sections are important: We need to preserve them and so that their |
998 | // addresses can be captured and reported to the ORC runtime in |
999 | // registerObjectPlatformSections. |
1000 | JITLinkSymbolSet InitSectionSymbols; |
1001 | for (auto &InitSectionName : MachOInitSectionNames) { |
1002 | // Skip ObjCImageInfo -- this shouldn't have any dependencies, and we may |
1003 | // remove it later. |
1004 | if (InitSectionName == MachOObjCImageInfoSectionName) |
1005 | continue; |
1006 | |
1007 | // Skip non-init sections. |
1008 | auto *InitSection = G.findSectionByName(Name: InitSectionName); |
1009 | if (!InitSection) |
1010 | continue; |
1011 | |
1012 | // Make a pass over live symbols in the section: those blocks are already |
1013 | // preserved. |
1014 | DenseSet<jitlink::Block *> AlreadyLiveBlocks; |
1015 | for (auto &Sym : InitSection->symbols()) { |
1016 | auto &B = Sym->getBlock(); |
1017 | if (Sym->isLive() && Sym->getOffset() == 0 && |
1018 | Sym->getSize() == B.getSize() && !AlreadyLiveBlocks.count(V: &B)) { |
1019 | InitSectionSymbols.insert(V: Sym); |
1020 | AlreadyLiveBlocks.insert(V: &B); |
1021 | } |
1022 | } |
1023 | |
1024 | // Add anonymous symbols to preserve any not-already-preserved blocks. |
1025 | for (auto *B : InitSection->blocks()) |
1026 | if (!AlreadyLiveBlocks.count(V: B)) |
1027 | InitSectionSymbols.insert( |
1028 | V: &G.addAnonymousSymbol(Content&: *B, Offset: 0, Size: B->getSize(), IsCallable: false, IsLive: true)); |
1029 | } |
1030 | |
1031 | if (!InitSectionSymbols.empty()) { |
1032 | std::lock_guard<std::mutex> Lock(PluginMutex); |
1033 | InitSymbolDeps[&MR] = std::move(InitSectionSymbols); |
1034 | } |
1035 | |
1036 | return Error::success(); |
1037 | } |
1038 | |
1039 | Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo( |
1040 | jitlink::LinkGraph &G, MaterializationResponsibility &MR) { |
1041 | |
1042 | // If there's an ObjC imagine info then either |
1043 | // (1) It's the first __objc_imageinfo we've seen in this JITDylib. In |
1044 | // this case we name and record it. |
1045 | // OR |
1046 | // (2) We already have a recorded __objc_imageinfo for this JITDylib, |
1047 | // in which case we just verify it. |
1048 | auto *ObjCImageInfo = G.findSectionByName(Name: MachOObjCImageInfoSectionName); |
1049 | if (!ObjCImageInfo) |
1050 | return Error::success(); |
1051 | |
1052 | auto ObjCImageInfoBlocks = ObjCImageInfo->blocks(); |
1053 | |
1054 | // Check that the section is not empty if present. |
1055 | if (ObjCImageInfoBlocks.empty()) |
1056 | return make_error<StringError>(Args: "Empty " + MachOObjCImageInfoSectionName + |
1057 | " section in " + G.getName(), |
1058 | Args: inconvertibleErrorCode()); |
1059 | |
1060 | // Check that there's only one block in the section. |
1061 | if (std::next(x: ObjCImageInfoBlocks.begin()) != ObjCImageInfoBlocks.end()) |
1062 | return make_error<StringError>(Args: "Multiple blocks in " + |
1063 | MachOObjCImageInfoSectionName + |
1064 | " section in " + G.getName(), |
1065 | Args: inconvertibleErrorCode()); |
1066 | |
1067 | // Check that the __objc_imageinfo section is unreferenced. |
1068 | // FIXME: We could optimize this check if Symbols had a ref-count. |
1069 | for (auto &Sec : G.sections()) { |
1070 | if (&Sec != ObjCImageInfo) |
1071 | for (auto *B : Sec.blocks()) |
1072 | for (auto &E : B->edges()) |
1073 | if (E.getTarget().isDefined() && |
1074 | &E.getTarget().getBlock().getSection() == ObjCImageInfo) |
1075 | return make_error<StringError>(Args: MachOObjCImageInfoSectionName + |
1076 | " is referenced within file " + |
1077 | G.getName(), |
1078 | Args: inconvertibleErrorCode()); |
1079 | } |
1080 | |
1081 | auto &ObjCImageInfoBlock = **ObjCImageInfoBlocks.begin(); |
1082 | auto *ObjCImageInfoData = ObjCImageInfoBlock.getContent().data(); |
1083 | auto Version = support::endian::read32(P: ObjCImageInfoData, E: G.getEndianness()); |
1084 | auto Flags = |
1085 | support::endian::read32(P: ObjCImageInfoData + 4, E: G.getEndianness()); |
1086 | |
1087 | // Lock the mutex while we verify / update the ObjCImageInfos map. |
1088 | std::lock_guard<std::mutex> Lock(PluginMutex); |
1089 | |
1090 | auto ObjCImageInfoItr = ObjCImageInfos.find(Val: &MR.getTargetJITDylib()); |
1091 | if (ObjCImageInfoItr != ObjCImageInfos.end()) { |
1092 | // We've already registered an __objc_imageinfo section. Verify the |
1093 | // content of this new section matches, then delete it. |
1094 | if (ObjCImageInfoItr->second.Version != Version) |
1095 | return make_error<StringError>( |
1096 | Args: "ObjC version in " + G.getName() + |
1097 | " does not match first registered version" , |
1098 | Args: inconvertibleErrorCode()); |
1099 | if (ObjCImageInfoItr->second.Flags != Flags) |
1100 | if (Error E = mergeImageInfoFlags(G, MR, Info&: ObjCImageInfoItr->second, NewFlags: Flags)) |
1101 | return E; |
1102 | |
1103 | // __objc_imageinfo is valid. Delete the block. |
1104 | for (auto *S : ObjCImageInfo->symbols()) |
1105 | G.removeDefinedSymbol(Sym&: *S); |
1106 | G.removeBlock(B&: ObjCImageInfoBlock); |
1107 | } else { |
1108 | LLVM_DEBUG({ |
1109 | dbgs() << "MachOPlatform: Registered __objc_imageinfo for " |
1110 | << MR.getTargetJITDylib().getName() << " in " << G.getName() |
1111 | << "; flags = " << formatv("{0:x4}" , Flags) << "\n" ; |
1112 | }); |
1113 | // We haven't registered an __objc_imageinfo section yet. Register and |
1114 | // move on. The section should already be marked no-dead-strip. |
1115 | G.addDefinedSymbol(Content&: ObjCImageInfoBlock, Offset: 0, Name: ObjCImageInfoSymbolName, |
1116 | Size: ObjCImageInfoBlock.getSize(), L: jitlink::Linkage::Strong, |
1117 | S: jitlink::Scope::Hidden, IsCallable: false, IsLive: true); |
1118 | if (auto Err = MR.defineMaterializing( |
1119 | SymbolFlags: {{MR.getExecutionSession().intern(SymName: ObjCImageInfoSymbolName), |
1120 | JITSymbolFlags()}})) |
1121 | return Err; |
1122 | ObjCImageInfos[&MR.getTargetJITDylib()] = {.Version: Version, .Flags: Flags, .Finalized: false}; |
1123 | } |
1124 | |
1125 | return Error::success(); |
1126 | } |
1127 | |
1128 | Error MachOPlatform::MachOPlatformPlugin::mergeImageInfoFlags( |
1129 | jitlink::LinkGraph &G, MaterializationResponsibility &MR, |
1130 | ObjCImageInfo &Info, uint32_t NewFlags) { |
1131 | if (Info.Flags == NewFlags) |
1132 | return Error::success(); |
1133 | |
1134 | ObjCImageInfoFlags Old(Info.Flags); |
1135 | ObjCImageInfoFlags New(NewFlags); |
1136 | |
1137 | // Check for incompatible flags. |
1138 | if (Old.SwiftABIVersion && New.SwiftABIVersion && |
1139 | Old.SwiftABIVersion != New.SwiftABIVersion) |
1140 | return make_error<StringError>(Args: "Swift ABI version in " + G.getName() + |
1141 | " does not match first registered flags" , |
1142 | Args: inconvertibleErrorCode()); |
1143 | |
1144 | // HasCategoryClassProperties and HasSignedObjCClassROs can be disabled before |
1145 | // they are registered, if necessary, but once they are in use must be |
1146 | // supported by subsequent objects. |
1147 | if (Info.Finalized && Old.HasCategoryClassProperties && |
1148 | !New.HasCategoryClassProperties) |
1149 | return make_error<StringError>(Args: "ObjC category class property support in " + |
1150 | G.getName() + |
1151 | " does not match first registered flags" , |
1152 | Args: inconvertibleErrorCode()); |
1153 | if (Info.Finalized && Old.HasSignedObjCClassROs && !New.HasSignedObjCClassROs) |
1154 | return make_error<StringError>(Args: "ObjC class_ro_t pointer signing in " + |
1155 | G.getName() + |
1156 | " does not match first registered flags" , |
1157 | Args: inconvertibleErrorCode()); |
1158 | |
1159 | // If we cannot change the flags, ignore any remaining differences. Adding |
1160 | // Swift or changing its version are unlikely to cause problems in practice. |
1161 | if (Info.Finalized) |
1162 | return Error::success(); |
1163 | |
1164 | // Use the minimum Swift version. |
1165 | if (Old.SwiftVersion && New.SwiftVersion) |
1166 | New.SwiftVersion = std::min(a: Old.SwiftVersion, b: New.SwiftVersion); |
1167 | else if (Old.SwiftVersion) |
1168 | New.SwiftVersion = Old.SwiftVersion; |
1169 | // Add a Swift ABI version if it was pure objc before. |
1170 | if (!New.SwiftABIVersion) |
1171 | New.SwiftABIVersion = Old.SwiftABIVersion; |
1172 | // Disable class properties if any object does not support it. |
1173 | if (Old.HasCategoryClassProperties != New.HasCategoryClassProperties) |
1174 | New.HasCategoryClassProperties = false; |
1175 | // Disable signed class ro data if any object does not support it. |
1176 | if (Old.HasSignedObjCClassROs != New.HasSignedObjCClassROs) |
1177 | New.HasSignedObjCClassROs = false; |
1178 | |
1179 | LLVM_DEBUG({ |
1180 | dbgs() << "MachOPlatform: Merging __objc_imageinfo flags for " |
1181 | << MR.getTargetJITDylib().getName() << " (was " |
1182 | << formatv("{0:x4}" , Old.rawFlags()) << ")" |
1183 | << " with " << G.getName() << " (" << formatv("{0:x4}" , NewFlags) |
1184 | << ")" |
1185 | << " -> " << formatv("{0:x4}" , New.rawFlags()) << "\n" ; |
1186 | }); |
1187 | |
1188 | Info.Flags = New.rawFlags(); |
1189 | return Error::success(); |
1190 | } |
1191 | |
1192 | Error MachOPlatform::MachOPlatformPlugin::fixTLVSectionsAndEdges( |
1193 | jitlink::LinkGraph &G, JITDylib &JD) { |
1194 | |
1195 | // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr. |
1196 | for (auto *Sym : G.external_symbols()) |
1197 | if (Sym->getName() == "__tlv_bootstrap" ) { |
1198 | Sym->setName("___orc_rt_macho_tlv_get_addr" ); |
1199 | break; |
1200 | } |
1201 | |
1202 | // Store key in __thread_vars struct fields. |
1203 | if (auto *ThreadDataSec = G.findSectionByName(Name: MachOThreadVarsSectionName)) { |
1204 | std::optional<uint64_t> Key; |
1205 | { |
1206 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); |
1207 | auto I = MP.JITDylibToPThreadKey.find(Val: &JD); |
1208 | if (I != MP.JITDylibToPThreadKey.end()) |
1209 | Key = I->second; |
1210 | } |
1211 | |
1212 | if (!Key) { |
1213 | if (auto KeyOrErr = MP.createPThreadKey()) |
1214 | Key = *KeyOrErr; |
1215 | else |
1216 | return KeyOrErr.takeError(); |
1217 | } |
1218 | |
1219 | uint64_t PlatformKeyBits = |
1220 | support::endian::byte_swap(value: *Key, endian: G.getEndianness()); |
1221 | |
1222 | for (auto *B : ThreadDataSec->blocks()) { |
1223 | if (B->getSize() != 3 * G.getPointerSize()) |
1224 | return make_error<StringError>(Args: "__thread_vars block at " + |
1225 | formatv(Fmt: "{0:x}" , Vals: B->getAddress()) + |
1226 | " has unexpected size" , |
1227 | Args: inconvertibleErrorCode()); |
1228 | |
1229 | auto NewBlockContent = G.allocateBuffer(Size: B->getSize()); |
1230 | llvm::copy(Range: B->getContent(), Out: NewBlockContent.data()); |
1231 | memcpy(dest: NewBlockContent.data() + G.getPointerSize(), src: &PlatformKeyBits, |
1232 | n: G.getPointerSize()); |
1233 | B->setContent(NewBlockContent); |
1234 | } |
1235 | } |
1236 | |
1237 | // Transform any TLV edges into GOT edges. |
1238 | for (auto *B : G.blocks()) |
1239 | for (auto &E : B->edges()) |
1240 | if (E.getKind() == |
1241 | jitlink::x86_64::RequestTLVPAndTransformToPCRel32TLVPLoadREXRelaxable) |
1242 | E.setKind(jitlink::x86_64:: |
1243 | RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable); |
1244 | |
1245 | return Error::success(); |
1246 | } |
1247 | |
1248 | std::optional<MachOPlatform::MachOPlatformPlugin::UnwindSections> |
1249 | MachOPlatform::MachOPlatformPlugin::findUnwindSectionInfo( |
1250 | jitlink::LinkGraph &G) { |
1251 | using namespace jitlink; |
1252 | |
1253 | UnwindSections US; |
1254 | |
1255 | // ScanSection records a section range and adds any executable blocks that |
1256 | // that section points to to the CodeBlocks vector. |
1257 | SmallVector<Block *> CodeBlocks; |
1258 | auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) { |
1259 | if (Sec.blocks().empty()) |
1260 | return; |
1261 | SecRange = (*Sec.blocks().begin())->getRange(); |
1262 | for (auto *B : Sec.blocks()) { |
1263 | auto R = B->getRange(); |
1264 | SecRange.Start = std::min(a: SecRange.Start, b: R.Start); |
1265 | SecRange.End = std::max(a: SecRange.End, b: R.End); |
1266 | for (auto &E : B->edges()) { |
1267 | if (!E.getTarget().isDefined()) |
1268 | continue; |
1269 | auto &TargetBlock = E.getTarget().getBlock(); |
1270 | auto &TargetSection = TargetBlock.getSection(); |
1271 | if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec) |
1272 | CodeBlocks.push_back(Elt: &TargetBlock); |
1273 | } |
1274 | } |
1275 | }; |
1276 | |
1277 | if (Section *EHFrameSec = G.findSectionByName(Name: MachOEHFrameSectionName)) |
1278 | ScanUnwindInfoSection(*EHFrameSec, US.DwarfSection); |
1279 | |
1280 | if (Section *CUInfoSec = |
1281 | G.findSectionByName(Name: MachOCompactUnwindInfoSectionName)) |
1282 | ScanUnwindInfoSection(*CUInfoSec, US.CompactUnwindSection); |
1283 | |
1284 | // If we didn't find any pointed-to code-blocks then there's no need to |
1285 | // register any info. |
1286 | if (CodeBlocks.empty()) |
1287 | return std::nullopt; |
1288 | |
1289 | // We have info to register. Sort the code blocks into address order and |
1290 | // build a list of contiguous address ranges covering them all. |
1291 | llvm::sort(C&: CodeBlocks, Comp: [](const Block *LHS, const Block *RHS) { |
1292 | return LHS->getAddress() < RHS->getAddress(); |
1293 | }); |
1294 | for (auto *B : CodeBlocks) { |
1295 | if (US.CodeRanges.empty() || US.CodeRanges.back().End != B->getAddress()) |
1296 | US.CodeRanges.push_back(Elt: B->getRange()); |
1297 | else |
1298 | US.CodeRanges.back().End = B->getRange().End; |
1299 | } |
1300 | |
1301 | LLVM_DEBUG({ |
1302 | dbgs() << "MachOPlatform identified unwind info in " << G.getName() << ":\n" |
1303 | << " DWARF: " ; |
1304 | if (US.DwarfSection.Start) |
1305 | dbgs() << US.DwarfSection << "\n" ; |
1306 | else |
1307 | dbgs() << "none\n" ; |
1308 | dbgs() << " Compact-unwind: " ; |
1309 | if (US.CompactUnwindSection.Start) |
1310 | dbgs() << US.CompactUnwindSection << "\n" ; |
1311 | else |
1312 | dbgs() << "none\n" |
1313 | << "for code ranges:\n" ; |
1314 | for (auto &CR : US.CodeRanges) |
1315 | dbgs() << " " << CR << "\n" ; |
1316 | if (US.CodeRanges.size() >= G.sections_size()) |
1317 | dbgs() << "WARNING: High number of discontiguous code ranges! " |
1318 | "Padding may be interfering with coalescing.\n" ; |
1319 | }); |
1320 | |
1321 | return US; |
1322 | } |
1323 | |
1324 | Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections( |
1325 | jitlink::LinkGraph &G, JITDylib &JD, bool InBootstrapPhase) { |
1326 | |
1327 | // Get a pointer to the thread data section if there is one. It will be used |
1328 | // below. |
1329 | jitlink::Section *ThreadDataSection = |
1330 | G.findSectionByName(Name: MachOThreadDataSectionName); |
1331 | |
1332 | // Handle thread BSS section if there is one. |
1333 | if (auto *ThreadBSSSection = G.findSectionByName(Name: MachOThreadBSSSectionName)) { |
1334 | // If there's already a thread data section in this graph then merge the |
1335 | // thread BSS section content into it, otherwise just treat the thread |
1336 | // BSS section as the thread data section. |
1337 | if (ThreadDataSection) |
1338 | G.mergeSections(DstSection&: *ThreadDataSection, SrcSection&: *ThreadBSSSection); |
1339 | else |
1340 | ThreadDataSection = ThreadBSSSection; |
1341 | } |
1342 | |
1343 | SmallVector<std::pair<StringRef, ExecutorAddrRange>, 8> MachOPlatformSecs; |
1344 | |
1345 | // Collect data sections to register. |
1346 | StringRef DataSections[] = {MachODataDataSectionName, |
1347 | MachODataCommonSectionName, |
1348 | MachOEHFrameSectionName}; |
1349 | for (auto &SecName : DataSections) { |
1350 | if (auto *Sec = G.findSectionByName(Name: SecName)) { |
1351 | jitlink::SectionRange R(*Sec); |
1352 | if (!R.empty()) |
1353 | MachOPlatformSecs.push_back(Elt: {SecName, R.getRange()}); |
1354 | } |
1355 | } |
1356 | |
1357 | // Having merged thread BSS (if present) and thread data (if present), |
1358 | // record the resulting section range. |
1359 | if (ThreadDataSection) { |
1360 | jitlink::SectionRange R(*ThreadDataSection); |
1361 | if (!R.empty()) |
1362 | MachOPlatformSecs.push_back(Elt: {MachOThreadDataSectionName, R.getRange()}); |
1363 | } |
1364 | |
1365 | // If any platform sections were found then add an allocation action to call |
1366 | // the registration function. |
1367 | StringRef PlatformSections[] = {MachOModInitFuncSectionName, |
1368 | ObjCRuntimeObjectSectionName}; |
1369 | |
1370 | for (auto &SecName : PlatformSections) { |
1371 | auto *Sec = G.findSectionByName(Name: SecName); |
1372 | if (!Sec) |
1373 | continue; |
1374 | jitlink::SectionRange R(*Sec); |
1375 | if (R.empty()) |
1376 | continue; |
1377 | |
1378 | MachOPlatformSecs.push_back(Elt: {SecName, R.getRange()}); |
1379 | } |
1380 | |
1381 | std::optional<std::tuple<SmallVector<ExecutorAddrRange>, ExecutorAddrRange, |
1382 | ExecutorAddrRange>> |
1383 | UnwindInfo; |
1384 | if (auto UI = findUnwindSectionInfo(G)) |
1385 | UnwindInfo = std::make_tuple(args: std::move(UI->CodeRanges), args&: UI->DwarfSection, |
1386 | args&: UI->CompactUnwindSection); |
1387 | |
1388 | if (!MachOPlatformSecs.empty() || UnwindInfo) { |
1389 | // Dump the scraped inits. |
1390 | LLVM_DEBUG({ |
1391 | dbgs() << "MachOPlatform: Scraped " << G.getName() << " init sections:\n" ; |
1392 | for (auto &KV : MachOPlatformSecs) |
1393 | dbgs() << " " << KV.first << ": " << KV.second << "\n" ; |
1394 | }); |
1395 | |
1396 | using SPSRegisterObjectPlatformSectionsArgs = SPSArgList< |
1397 | SPSExecutorAddr, |
1398 | SPSOptional<SPSTuple<SPSSequence<SPSExecutorAddrRange>, |
1399 | SPSExecutorAddrRange, SPSExecutorAddrRange>>, |
1400 | SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>>; |
1401 | |
1402 | shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase) |
1403 | ? G.allocActions() |
1404 | : MP.Bootstrap.load()->DeferredAAs; |
1405 | |
1406 | ExecutorAddr ; |
1407 | { |
1408 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); |
1409 | auto I = MP.JITDylibToHeaderAddr.find(Val: &JD); |
1410 | assert(I != MP.JITDylibToHeaderAddr.end() && |
1411 | "No header registered for JD" ); |
1412 | assert(I->second && "Null header registered for JD" ); |
1413 | HeaderAddr = I->second; |
1414 | } |
1415 | allocActions.push_back( |
1416 | x: {.Finalize: cantFail( |
1417 | ValOrErr: WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( |
1418 | FnAddr: MP.RegisterObjectPlatformSections.Addr, Args: HeaderAddr, Args: UnwindInfo, |
1419 | Args: MachOPlatformSecs)), |
1420 | .Dealloc: cantFail( |
1421 | ValOrErr: WrapperFunctionCall::Create<SPSRegisterObjectPlatformSectionsArgs>( |
1422 | FnAddr: MP.DeregisterObjectPlatformSections.Addr, Args: HeaderAddr, |
1423 | Args: UnwindInfo, Args: MachOPlatformSecs))}); |
1424 | } |
1425 | |
1426 | return Error::success(); |
1427 | } |
1428 | |
1429 | Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject( |
1430 | jitlink::LinkGraph &G) { |
1431 | |
1432 | bool NeedTextSegment = false; |
1433 | size_t NumRuntimeSections = 0; |
1434 | |
1435 | for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) |
1436 | if (G.findSectionByName(Name: ObjCRuntimeSectionName)) |
1437 | ++NumRuntimeSections; |
1438 | |
1439 | for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) { |
1440 | if (G.findSectionByName(Name: ObjCRuntimeSectionName)) { |
1441 | ++NumRuntimeSections; |
1442 | NeedTextSegment = true; |
1443 | } |
1444 | } |
1445 | |
1446 | // Early out for no runtime sections. |
1447 | if (NumRuntimeSections == 0) |
1448 | return Error::success(); |
1449 | |
1450 | // If there were any runtime sections then we need to add an __objc_imageinfo |
1451 | // section. |
1452 | ++NumRuntimeSections; |
1453 | |
1454 | size_t MachOSize = sizeof(MachO::mach_header_64) + |
1455 | (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) + |
1456 | NumRuntimeSections * sizeof(MachO::section_64); |
1457 | |
1458 | auto &Sec = G.createSection(Name: ObjCRuntimeObjectSectionName, |
1459 | Prot: MemProt::Read | MemProt::Write); |
1460 | G.createMutableContentBlock(Parent&: Sec, ContentSize: MachOSize, Address: ExecutorAddr(), Alignment: 16, AlignmentOffset: 0, ZeroInitialize: true); |
1461 | |
1462 | return Error::success(); |
1463 | } |
1464 | |
1465 | Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject( |
1466 | jitlink::LinkGraph &G, MaterializationResponsibility &MR) { |
1467 | |
1468 | auto *ObjCRuntimeObjectSec = |
1469 | G.findSectionByName(Name: ObjCRuntimeObjectSectionName); |
1470 | |
1471 | if (!ObjCRuntimeObjectSec) |
1472 | return Error::success(); |
1473 | |
1474 | switch (G.getTargetTriple().getArch()) { |
1475 | case Triple::aarch64: |
1476 | case Triple::x86_64: |
1477 | // Supported. |
1478 | break; |
1479 | default: |
1480 | return make_error<StringError>(Args: "Unrecognized MachO arch in triple " + |
1481 | G.getTargetTriple().str(), |
1482 | Args: inconvertibleErrorCode()); |
1483 | } |
1484 | |
1485 | auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin(); |
1486 | |
1487 | struct SecDesc { |
1488 | MachO::section_64 Sec; |
1489 | unique_function<void(size_t RecordOffset)> AddFixups; |
1490 | }; |
1491 | |
1492 | std::vector<SecDesc> TextSections, DataSections; |
1493 | auto AddSection = [&](SecDesc &SD, jitlink::Section &GraphSec) { |
1494 | jitlink::SectionRange SR(GraphSec); |
1495 | StringRef FQName = GraphSec.getName(); |
1496 | memset(s: &SD.Sec, c: 0, n: sizeof(MachO::section_64)); |
1497 | memcpy(dest: SD.Sec.sectname, src: FQName.drop_front(N: 7).data(), n: FQName.size() - 7); |
1498 | memcpy(dest: SD.Sec.segname, src: FQName.data(), n: 6); |
1499 | SD.Sec.addr = SR.getStart() - SecBlock.getAddress(); |
1500 | SD.Sec.size = SR.getSize(); |
1501 | SD.Sec.flags = MachO::S_REGULAR; |
1502 | }; |
1503 | |
1504 | // Add the __objc_imageinfo section. |
1505 | { |
1506 | DataSections.push_back(x: {}); |
1507 | auto &SD = DataSections.back(); |
1508 | memset(s: &SD.Sec, c: 0, n: sizeof(SD.Sec)); |
1509 | memcpy(dest: SD.Sec.sectname, src: "__objc_imageinfo" , n: 16); |
1510 | strcpy(dest: SD.Sec.segname, src: "__DATA" ); |
1511 | SD.Sec.size = 8; |
1512 | SD.AddFixups = [&](size_t RecordOffset) { |
1513 | auto PointerEdge = getPointerEdgeKind(G); |
1514 | |
1515 | // Look for an existing __objc_imageinfo symbol. |
1516 | jitlink::Symbol *ObjCImageInfoSym = nullptr; |
1517 | for (auto *Sym : G.external_symbols()) |
1518 | if (Sym->getName() == ObjCImageInfoSymbolName) { |
1519 | ObjCImageInfoSym = Sym; |
1520 | break; |
1521 | } |
1522 | if (!ObjCImageInfoSym) |
1523 | for (auto *Sym : G.absolute_symbols()) |
1524 | if (Sym->getName() == ObjCImageInfoSymbolName) { |
1525 | ObjCImageInfoSym = Sym; |
1526 | break; |
1527 | } |
1528 | if (!ObjCImageInfoSym) |
1529 | for (auto *Sym : G.defined_symbols()) |
1530 | if (Sym->hasName() && Sym->getName() == ObjCImageInfoSymbolName) { |
1531 | ObjCImageInfoSym = Sym; |
1532 | std::optional<uint32_t> Flags; |
1533 | { |
1534 | std::lock_guard<std::mutex> Lock(PluginMutex); |
1535 | auto It = ObjCImageInfos.find(Val: &MR.getTargetJITDylib()); |
1536 | if (It != ObjCImageInfos.end()) { |
1537 | It->second.Finalized = true; |
1538 | Flags = It->second.Flags; |
1539 | } |
1540 | } |
1541 | |
1542 | if (Flags) { |
1543 | // We own the definition of __objc_image_info; write the final |
1544 | // merged flags value. |
1545 | auto Content = Sym->getBlock().getMutableContent(G); |
1546 | assert(Content.size() == 8 && |
1547 | "__objc_image_info size should have been verified already" ); |
1548 | support::endian::write32(P: &Content[4], V: *Flags, E: G.getEndianness()); |
1549 | } |
1550 | break; |
1551 | } |
1552 | if (!ObjCImageInfoSym) |
1553 | ObjCImageInfoSym = |
1554 | &G.addExternalSymbol(Name: ObjCImageInfoSymbolName, Size: 8, IsWeaklyReferenced: false); |
1555 | |
1556 | SecBlock.addEdge(K: PointerEdge, |
1557 | Offset: RecordOffset + ((char *)&SD.Sec.addr - (char *)&SD.Sec), |
1558 | Target&: *ObjCImageInfoSym, Addend: -SecBlock.getAddress().getValue()); |
1559 | }; |
1560 | } |
1561 | |
1562 | for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) { |
1563 | if (auto *GraphSec = G.findSectionByName(Name: ObjCRuntimeSectionName)) { |
1564 | DataSections.push_back(x: {}); |
1565 | AddSection(DataSections.back(), *GraphSec); |
1566 | } |
1567 | } |
1568 | |
1569 | for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) { |
1570 | if (auto *GraphSec = G.findSectionByName(Name: ObjCRuntimeSectionName)) { |
1571 | TextSections.push_back(x: {}); |
1572 | AddSection(TextSections.back(), *GraphSec); |
1573 | } |
1574 | } |
1575 | |
1576 | assert(ObjCRuntimeObjectSec->blocks_size() == 1 && |
1577 | "Unexpected number of blocks in runtime sections object" ); |
1578 | |
1579 | // Build the header struct up-front. This also gives us a chance to check |
1580 | // that the triple is supported, which we'll assume below. |
1581 | MachO::mach_header_64 Hdr; |
1582 | Hdr.magic = MachO::MH_MAGIC_64; |
1583 | switch (G.getTargetTriple().getArch()) { |
1584 | case Triple::aarch64: |
1585 | Hdr.cputype = MachO::CPU_TYPE_ARM64; |
1586 | Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL; |
1587 | break; |
1588 | case Triple::x86_64: |
1589 | Hdr.cputype = MachO::CPU_TYPE_X86_64; |
1590 | Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL; |
1591 | break; |
1592 | default: |
1593 | llvm_unreachable("Unsupported architecture" ); |
1594 | } |
1595 | |
1596 | Hdr.filetype = MachO::MH_DYLIB; |
1597 | Hdr.ncmds = 1 + !TextSections.empty(); |
1598 | Hdr.sizeofcmds = |
1599 | Hdr.ncmds * sizeof(MachO::segment_command_64) + |
1600 | (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64); |
1601 | Hdr.flags = 0; |
1602 | Hdr.reserved = 0; |
1603 | |
1604 | auto SecContent = SecBlock.getAlreadyMutableContent(); |
1605 | char *P = SecContent.data(); |
1606 | auto WriteMachOStruct = [&](auto S) { |
1607 | if (G.getEndianness() != llvm::endianness::native) |
1608 | MachO::swapStruct(S); |
1609 | memcpy(P, &S, sizeof(S)); |
1610 | P += sizeof(S); |
1611 | }; |
1612 | |
1613 | auto WriteSegment = [&](StringRef Name, std::vector<SecDesc> &Secs) { |
1614 | MachO::segment_command_64 SegLC; |
1615 | memset(s: &SegLC, c: 0, n: sizeof(SegLC)); |
1616 | memcpy(dest: SegLC.segname, src: Name.data(), n: Name.size()); |
1617 | SegLC.cmd = MachO::LC_SEGMENT_64; |
1618 | SegLC.cmdsize = sizeof(MachO::segment_command_64) + |
1619 | Secs.size() * sizeof(MachO::section_64); |
1620 | SegLC.nsects = Secs.size(); |
1621 | WriteMachOStruct(SegLC); |
1622 | for (auto &SD : Secs) { |
1623 | if (SD.AddFixups) |
1624 | SD.AddFixups(P - SecContent.data()); |
1625 | WriteMachOStruct(SD.Sec); |
1626 | } |
1627 | }; |
1628 | |
1629 | WriteMachOStruct(Hdr); |
1630 | if (!TextSections.empty()) |
1631 | WriteSegment("__TEXT" , TextSections); |
1632 | if (!DataSections.empty()) |
1633 | WriteSegment("__DATA" , DataSections); |
1634 | |
1635 | assert(P == SecContent.end() && "Underflow writing ObjC runtime object" ); |
1636 | return Error::success(); |
1637 | } |
1638 | |
1639 | Error MachOPlatform::MachOPlatformPlugin::prepareSymbolTableRegistration( |
1640 | jitlink::LinkGraph &G, JITSymTabVector &JITSymTabInfo) { |
1641 | |
1642 | auto *CStringSec = G.findSectionByName(Name: MachOCStringSectionName); |
1643 | if (!CStringSec) |
1644 | CStringSec = &G.createSection(Name: MachOCStringSectionName, |
1645 | Prot: MemProt::Read | MemProt::Exec); |
1646 | |
1647 | // Make a map of existing strings so that we can re-use them: |
1648 | DenseMap<StringRef, jitlink::Symbol *> ExistingStrings; |
1649 | for (auto *Sym : CStringSec->symbols()) { |
1650 | |
1651 | // The LinkGraph builder should have created single strings blocks, and all |
1652 | // plugins should have maintained this invariant. |
1653 | auto Content = Sym->getBlock().getContent(); |
1654 | ExistingStrings.insert( |
1655 | KV: std::make_pair(x: StringRef(Content.data(), Content.size()), y&: Sym)); |
1656 | } |
1657 | |
1658 | // Add all symbol names to the string section, and record the symbols for |
1659 | // those names. |
1660 | { |
1661 | SmallVector<jitlink::Symbol *> SymsToProcess; |
1662 | for (auto *Sym : G.defined_symbols()) |
1663 | SymsToProcess.push_back(Elt: Sym); |
1664 | for (auto *Sym : G.absolute_symbols()) |
1665 | SymsToProcess.push_back(Elt: Sym); |
1666 | |
1667 | for (auto *Sym : SymsToProcess) { |
1668 | if (!Sym->hasName()) |
1669 | continue; |
1670 | |
1671 | auto I = ExistingStrings.find(Val: Sym->getName()); |
1672 | if (I == ExistingStrings.end()) { |
1673 | auto &NameBlock = G.createMutableContentBlock( |
1674 | Parent&: *CStringSec, MutableContent: G.allocateCString(Source: Sym->getName()), Address: orc::ExecutorAddr(), |
1675 | Alignment: 1, AlignmentOffset: 0); |
1676 | auto &SymbolNameSym = G.addAnonymousSymbol( |
1677 | Content&: NameBlock, Offset: 0, Size: NameBlock.getSize(), IsCallable: false, IsLive: true); |
1678 | JITSymTabInfo.push_back(Elt: {.OriginalSym: Sym, .NameSym: &SymbolNameSym}); |
1679 | } else |
1680 | JITSymTabInfo.push_back(Elt: {.OriginalSym: Sym, .NameSym: I->second}); |
1681 | } |
1682 | } |
1683 | |
1684 | return Error::success(); |
1685 | } |
1686 | |
1687 | Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration( |
1688 | jitlink::LinkGraph &G, MaterializationResponsibility &MR, |
1689 | JITSymTabVector &JITSymTabInfo, bool InBootstrapPhase) { |
1690 | |
1691 | ExecutorAddr ; |
1692 | { |
1693 | std::lock_guard<std::mutex> Lock(MP.PlatformMutex); |
1694 | auto I = MP.JITDylibToHeaderAddr.find(Val: &MR.getTargetJITDylib()); |
1695 | assert(I != MP.JITDylibToHeaderAddr.end() && "No header registered for JD" ); |
1696 | assert(I->second && "Null header registered for JD" ); |
1697 | HeaderAddr = I->second; |
1698 | } |
1699 | |
1700 | SymbolTableVector LocalSymTab; |
1701 | auto &SymTab = LLVM_LIKELY(!InBootstrapPhase) ? LocalSymTab |
1702 | : MP.Bootstrap.load()->SymTab; |
1703 | for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo) |
1704 | SymTab.push_back(Elt: {NameSym->getAddress(), OriginalSymbol->getAddress(), |
1705 | flagsForSymbol(Sym&: *OriginalSymbol)}); |
1706 | |
1707 | // Bail out if we're in the bootstrap phase -- registration of thees symbols |
1708 | // will be attached to the bootstrap graph. |
1709 | if (LLVM_UNLIKELY(InBootstrapPhase)) |
1710 | return Error::success(); |
1711 | |
1712 | shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase) |
1713 | ? G.allocActions() |
1714 | : MP.Bootstrap.load()->DeferredAAs; |
1715 | allocActions.push_back( |
1716 | x: {.Finalize: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( |
1717 | FnAddr: MP.RegisterObjectSymbolTable.Addr, Args: HeaderAddr, Args: SymTab)), |
1718 | .Dealloc: cantFail(ValOrErr: WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>( |
1719 | FnAddr: MP.DeregisterObjectSymbolTable.Addr, Args: HeaderAddr, Args: SymTab))}); |
1720 | |
1721 | return Error::success(); |
1722 | } |
1723 | |
1724 | template <typename MachOTraits> |
1725 | jitlink::Block &(MachOPlatform &MOP, |
1726 | const MachOPlatform::HeaderOptions &Opts, |
1727 | JITDylib &JD, jitlink::LinkGraph &G, |
1728 | jitlink::Section &) { |
1729 | auto HdrInfo = |
1730 | getMachOHeaderInfoFromTriple(TT: MOP.getExecutionSession().getTargetTriple()); |
1731 | MachOBuilder<MachOTraits> B(HdrInfo.PageSize); |
1732 | |
1733 | B.Header.filetype = MachO::MH_DYLIB; |
1734 | B.Header.cputype = HdrInfo.CPUType; |
1735 | B.Header.cpusubtype = HdrInfo.CPUSubType; |
1736 | |
1737 | if (Opts.IDDylib) |
1738 | B.template addLoadCommand<MachO::LC_ID_DYLIB>( |
1739 | Opts.IDDylib->Name, Opts.IDDylib->Timestamp, |
1740 | Opts.IDDylib->CurrentVersion, Opts.IDDylib->CompatibilityVersion); |
1741 | else |
1742 | B.template addLoadCommand<MachO::LC_ID_DYLIB>(JD.getName(), 0, 0, 0); |
1743 | |
1744 | for (auto &BV : Opts.BuildVersions) |
1745 | B.template addLoadCommand<MachO::LC_BUILD_VERSION>( |
1746 | BV.Platform, BV.MinOS, BV.SDK, static_cast<uint32_t>(0)); |
1747 | for (auto &D : Opts.LoadDylibs) |
1748 | B.template addLoadCommand<MachO::LC_LOAD_DYLIB>( |
1749 | D.Name, D.Timestamp, D.CurrentVersion, D.CompatibilityVersion); |
1750 | for (auto &P : Opts.RPaths) |
1751 | B.template addLoadCommand<MachO::LC_RPATH>(P); |
1752 | |
1753 | auto = G.allocateBuffer(Size: B.layout()); |
1754 | B.write(HeaderContent); |
1755 | |
1756 | return G.createContentBlock(Parent&: HeaderSection, Content: HeaderContent, Address: ExecutorAddr(), Alignment: 8, |
1757 | AlignmentOffset: 0); |
1758 | } |
1759 | |
1760 | SimpleMachOHeaderMU::(MachOPlatform &MOP, |
1761 | SymbolStringPtr , |
1762 | MachOPlatform::HeaderOptions Opts) |
1763 | : MaterializationUnit( |
1764 | createHeaderInterface(MOP, HeaderStartSymbol: std::move(HeaderStartSymbol))), |
1765 | MOP(MOP), Opts(std::move(Opts)) {} |
1766 | |
1767 | void SimpleMachOHeaderMU::( |
1768 | std::unique_ptr<MaterializationResponsibility> R) { |
1769 | auto G = createPlatformGraph(MOP, Name: "<MachOHeaderMU>" ); |
1770 | addMachOHeader(JD&: R->getTargetJITDylib(), G&: *G, InitializerSymbol: R->getInitializerSymbol()); |
1771 | MOP.getObjectLinkingLayer().emit(R: std::move(R), G: std::move(G)); |
1772 | } |
1773 | |
1774 | void SimpleMachOHeaderMU::(const JITDylib &JD, |
1775 | const SymbolStringPtr &Sym) {} |
1776 | |
1777 | void SimpleMachOHeaderMU::( |
1778 | JITDylib &JD, jitlink::LinkGraph &G, |
1779 | const SymbolStringPtr &InitializerSymbol) { |
1780 | auto & = G.createSection(Name: "__header" , Prot: MemProt::Read); |
1781 | auto & = createHeaderBlock(JD, G, HeaderSection); |
1782 | |
1783 | // Init symbol is header-start symbol. |
1784 | G.addDefinedSymbol(Content&: HeaderBlock, Offset: 0, Name: *InitializerSymbol, Size: HeaderBlock.getSize(), |
1785 | L: jitlink::Linkage::Strong, S: jitlink::Scope::Default, IsCallable: false, |
1786 | IsLive: true); |
1787 | for (auto &HS : AdditionalHeaderSymbols) |
1788 | G.addDefinedSymbol(Content&: HeaderBlock, Offset: HS.Offset, Name: HS.Name, Size: HeaderBlock.getSize(), |
1789 | L: jitlink::Linkage::Strong, S: jitlink::Scope::Default, IsCallable: false, |
1790 | IsLive: true); |
1791 | } |
1792 | |
1793 | jitlink::Block & |
1794 | SimpleMachOHeaderMU::(JITDylib &JD, jitlink::LinkGraph &G, |
1795 | jitlink::Section &) { |
1796 | switch (MOP.getExecutionSession().getTargetTriple().getArch()) { |
1797 | case Triple::aarch64: |
1798 | case Triple::x86_64: |
1799 | return ::createHeaderBlock<MachO64LE>(MOP, Opts, JD, G, HeaderSection); |
1800 | default: |
1801 | llvm_unreachable("Unsupported architecture" ); |
1802 | } |
1803 | } |
1804 | |
1805 | MaterializationUnit::Interface SimpleMachOHeaderMU::( |
1806 | MachOPlatform &MOP, const SymbolStringPtr &) { |
1807 | SymbolFlagsMap ; |
1808 | |
1809 | HeaderSymbolFlags[HeaderStartSymbol] = JITSymbolFlags::Exported; |
1810 | for (auto &HS : AdditionalHeaderSymbols) |
1811 | HeaderSymbolFlags[MOP.getExecutionSession().intern(SymName: HS.Name)] = |
1812 | JITSymbolFlags::Exported; |
1813 | |
1814 | return MaterializationUnit::Interface(std::move(HeaderSymbolFlags), |
1815 | HeaderStartSymbol); |
1816 | } |
1817 | |
1818 | MachOHeaderInfo (const Triple &TT) { |
1819 | switch (TT.getArch()) { |
1820 | case Triple::aarch64: |
1821 | return {/* PageSize = */ 16 * 1024, |
1822 | /* CPUType = */ MachO::CPU_TYPE_ARM64, |
1823 | /* CPUSubType = */ MachO::CPU_SUBTYPE_ARM64_ALL}; |
1824 | case Triple::x86_64: |
1825 | return {/* PageSize = */ 4 * 1024, |
1826 | /* CPUType = */ MachO::CPU_TYPE_X86_64, |
1827 | /* CPUSubType = */ MachO::CPU_SUBTYPE_X86_64_ALL}; |
1828 | default: |
1829 | llvm_unreachable("Unrecognized architecture" ); |
1830 | } |
1831 | } |
1832 | |
1833 | } // End namespace orc. |
1834 | } // End namespace llvm. |
1835 | |