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