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