11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " macho_platform.h"
14
+ #include " bitmask_enum.h"
14
15
#include " common.h"
15
16
#include " debug.h"
16
17
#include " error.h"
@@ -34,7 +35,7 @@ using namespace __orc_rt::macho;
34
35
35
36
// Declare function tags for functions in the JIT process.
36
37
ORC_RT_JIT_DISPATCH_TAG (__orc_rt_macho_push_initializers_tag)
37
- ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag )
38
+ ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_symbols_tag )
38
39
39
40
struct objc_image_info;
40
41
struct mach_header ;
@@ -148,6 +149,16 @@ struct TLVDescriptor {
148
149
};
149
150
150
151
class MachOPlatformRuntimeState {
152
+ public:
153
+ // Used internally by MachOPlatformRuntimeState, but made public to enable
154
+ // serialization.
155
+ enum class MachOExecutorSymbolFlags : uint8_t {
156
+ None = 0 ,
157
+ Weak = 1U << 0 ,
158
+ Callable = 1U << 1 ,
159
+ ORC_RT_MARK_AS_BITMASK_ENUM (/* LargestValue = */ Callable)
160
+ };
161
+
151
162
private:
152
163
struct AtExitEntry {
153
164
void (*Func)(void *);
@@ -256,11 +267,17 @@ class MachOPlatformRuntimeState {
256
267
IntervalMap<char *, UnwindSections, IntervalCoalescing::Disabled>;
257
268
258
269
struct JITDylibState {
270
+
271
+ using SymbolTableMap =
272
+ std::unordered_map<std::string_view,
273
+ std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>;
274
+
259
275
std::string Name;
260
276
void *Header = nullptr ;
261
277
bool Sealed = false ;
262
278
size_t LinkedAgainstRefCount = 0 ;
263
279
size_t DlRefCount = 0 ;
280
+ SymbolTableMap SymbolTable;
264
281
std::vector<JITDylibState *> Deps;
265
282
AtExitsVector AtExits;
266
283
const objc_image_info *ObjCImageInfo = nullptr ;
@@ -296,6 +313,14 @@ class MachOPlatformRuntimeState {
296
313
Error deregisterJITDylib (void *Header);
297
314
Error registerThreadDataSection (span<const char > ThreadDataSection);
298
315
Error deregisterThreadDataSection (span<const char > ThreadDataSection);
316
+ Error registerObjectSymbolTable (
317
+ ExecutorAddr HeaderAddr,
318
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
319
+ MachOExecutorSymbolFlags>> &Entries);
320
+ Error deregisterObjectSymbolTable (
321
+ ExecutorAddr HeaderAddr,
322
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
323
+ MachOExecutorSymbolFlags>> &Entries);
299
324
Error registerObjectPlatformSections (
300
325
ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
301
326
std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
@@ -306,7 +331,7 @@ class MachOPlatformRuntimeState {
306
331
const char *dlerror ();
307
332
void *dlopen (std::string_view Name, int Mode);
308
333
int dlclose (void *DSOHandle);
309
- void *dlsym (void *DSOHandle, std::string_view Symbol);
334
+ void *dlsym (void *DSOHandle, const char * Symbol);
310
335
311
336
int registerAtExit (void (*F)(void *), void *Arg, void *DSOHandle);
312
337
void runAtExits (std::unique_lock<std::mutex> &JDStatesLock,
@@ -321,8 +346,42 @@ class MachOPlatformRuntimeState {
321
346
JITDylibState *getJITDylibStateByHeader (void *DSOHandle);
322
347
JITDylibState *getJITDylibStateByName (std::string_view Path);
323
348
324
- Expected<ExecutorAddr> lookupSymbolInJITDylib (void *DSOHandle,
325
- std::string_view Symbol);
349
+ // / Requests materialization of the given symbols. For each pair, the bool
350
+ // / element indicates whether the symbol is required (true) or weakly
351
+ // / referenced (false).
352
+ Error requestPushSymbols (JITDylibState &JDS,
353
+ span<std::pair<std::string_view, bool >> Symbols);
354
+
355
+ // / Visits the symbol table for the JITDylib associated with DSOHandle.
356
+ // / Visitor should be callable as
357
+ // /
358
+ // / void (size_t,
359
+ // / std::optional<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>)
360
+ // /
361
+ // / The visitor function will be called for each element of the Symbols, but
362
+ // / in an arbitrary order. The first argument of the callback will indicate
363
+ // / the index of the result. The second argument will be std::nullopt (if the
364
+ // / symbol at the given index was not present in the symbol table), or a
365
+ // / pair containing the symbol's address and flags.
366
+ // /
367
+ // / This function will remove all elements of Symbols that are found, leaving
368
+ // / only the symbols that were not. This allows it to dovetail with
369
+ // / requestPushSymbols, enabling the following idiom:
370
+ // /
371
+ // / ...
372
+ // / visitSymbolAddrs(DSO, Symbols);
373
+ // / if (!Symbols.empty()) {
374
+ // / requestPushSymbols(DSO, Symbols);
375
+ // / visitSymbolAddrs(DSO, Symbols);
376
+ // / for (auto &Sym : Symbols) {
377
+ // / -- handle symbols that were not found --
378
+ // / }
379
+ // / }
380
+ // /
381
+ template <typename VisitorFn>
382
+ void visitSymbolAddrs (JITDylibState &JDS,
383
+ std::vector<std::pair<std::string_view, bool >> &Symbols,
384
+ VisitorFn &&Visit);
326
385
327
386
bool lookupUnwindSections (void *Addr, unw_dynamic_unwind_sections &Info);
328
387
@@ -366,6 +425,47 @@ class MachOPlatformRuntimeState {
366
425
std::map<const char *, size_t > ThreadDataSections;
367
426
};
368
427
428
+ } // anonymous namespace
429
+
430
+ namespace __orc_rt {
431
+
432
+ class SPSMachOExecutorSymbolFlags ;
433
+
434
+ template <>
435
+ class SPSSerializationTraits <
436
+ SPSMachOExecutorSymbolFlags,
437
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags> {
438
+ private:
439
+ using UT = std::underlying_type_t <
440
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>;
441
+
442
+ public:
443
+ static size_t
444
+ size (const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
445
+ return sizeof (UT);
446
+ }
447
+
448
+ static bool
449
+ serialize (SPSOutputBuffer &OB,
450
+ const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
451
+ return SPSArgList<UT>::serialize (OB, static_cast <UT>(SF));
452
+ }
453
+
454
+ static bool
455
+ deserialize (SPSInputBuffer &IB,
456
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
457
+ UT Tmp;
458
+ if (!SPSArgList<UT>::deserialize (IB, Tmp))
459
+ return false ;
460
+ SF = static_cast <MachOPlatformRuntimeState::MachOExecutorSymbolFlags>(Tmp);
461
+ return true ;
462
+ }
463
+ };
464
+
465
+ } // namespace __orc_rt
466
+
467
+ namespace {
468
+
369
469
MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr ;
370
470
371
471
Error MachOPlatformRuntimeState::create () {
@@ -492,6 +592,48 @@ Error MachOPlatformRuntimeState::deregisterThreadDataSection(
492
592
return Error::success ();
493
593
}
494
594
595
+ Error MachOPlatformRuntimeState::registerObjectSymbolTable (
596
+ ExecutorAddr HeaderAddr,
597
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
598
+ MachOExecutorSymbolFlags>> &Entries) {
599
+
600
+ std::lock_guard<std::mutex> Lock (JDStatesMutex);
601
+ auto *JDS = getJITDylibStateByHeader (HeaderAddr.toPtr <void *>());
602
+ if (!JDS) {
603
+ std::ostringstream ErrStream;
604
+ ErrStream << " Could not register object platform sections for "
605
+ " unrecognized header "
606
+ << HeaderAddr.toPtr <void *>();
607
+ return make_error<StringError>(ErrStream.str ());
608
+ }
609
+
610
+ for (auto &[NameAddr, SymAddr, Flags] : Entries)
611
+ JDS->SymbolTable [NameAddr.toPtr <const char *>()] = {SymAddr, Flags};
612
+
613
+ return Error::success ();
614
+ }
615
+
616
+ Error MachOPlatformRuntimeState::deregisterObjectSymbolTable (
617
+ ExecutorAddr HeaderAddr,
618
+ const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
619
+ MachOExecutorSymbolFlags>> &Entries) {
620
+
621
+ std::lock_guard<std::mutex> Lock (JDStatesMutex);
622
+ auto *JDS = getJITDylibStateByHeader (HeaderAddr.toPtr <void *>());
623
+ if (!JDS) {
624
+ std::ostringstream ErrStream;
625
+ ErrStream << " Could not register object platform sections for "
626
+ " unrecognized header "
627
+ << HeaderAddr.toPtr <void *>();
628
+ return make_error<StringError>(ErrStream.str ());
629
+ }
630
+
631
+ for (auto &[NameAddr, SymAddr, Flags] : Entries)
632
+ JDS->SymbolTable .erase (NameAddr.toPtr <const char *>());
633
+
634
+ return Error::success ();
635
+ }
636
+
495
637
Error MachOPlatformRuntimeState::registerObjectPlatformSections (
496
638
ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
497
639
std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
@@ -687,15 +829,51 @@ int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
687
829
return 0 ;
688
830
}
689
831
690
- void *MachOPlatformRuntimeState::dlsym (void *DSOHandle,
691
- std::string_view Symbol) {
692
- auto Addr = lookupSymbolInJITDylib (DSOHandle, Symbol);
693
- if (!Addr) {
694
- DLFcnError = toString (Addr.takeError ());
695
- return 0 ;
832
+ void *MachOPlatformRuntimeState::dlsym (void *DSOHandle, const char *Symbol) {
833
+ std::lock_guard<std::mutex> Lock (JDStatesMutex);
834
+ auto *JDS = getJITDylibStateByHeader (DSOHandle);
835
+ if (!JDS) {
836
+ std::ostringstream ErrStream;
837
+ ErrStream << " In call to dlsym, unrecognized header address " << DSOHandle;
838
+ DLFcnError = ErrStream.str ();
839
+ return nullptr ;
840
+ }
841
+
842
+ std::string MangledName (" _" );
843
+ MangledName += Symbol;
844
+ std::vector<std::pair<std::string_view, bool >> Symbols;
845
+ Symbols.push_back ({MangledName, false });
846
+
847
+ ExecutorAddr Result;
848
+ using ElemResult =
849
+ std::optional<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>;
850
+
851
+ // Try to resolve the symbol in the local symbol tables.
852
+ visitSymbolAddrs (*JDS, Symbols, [&](size_t Idx, ElemResult E) {
853
+ if (E)
854
+ Result = E->first ;
855
+ });
856
+
857
+ // Return early if we found it.
858
+ if (Symbols.empty ())
859
+ return Result.toPtr <void *>();
860
+
861
+ // Otherwise call back to the controller to try to request that the symbol
862
+ // be materialized.
863
+ if (auto Err = requestPushSymbols (*JDS, {Symbols.data (), Symbols.size ()})) {
864
+ DLFcnError = toString (std::move (Err));
865
+ return nullptr ;
696
866
}
697
867
698
- return Addr->toPtr <void *>();
868
+ // Try another local resolution.
869
+ visitSymbolAddrs (*JDS, Symbols, [&](size_t Idx, ElemResult E) {
870
+ if (E)
871
+ Result = E->first ;
872
+ });
873
+
874
+ // At this point Result has either been set (if we found the symbol) or is
875
+ // still null (if we didn't). Either way it's the right value.
876
+ return Result.toPtr <void *>();
699
877
}
700
878
701
879
int MachOPlatformRuntimeState::registerAtExit (void (*F)(void *), void *Arg,
@@ -774,17 +952,35 @@ MachOPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
774
952
return nullptr ;
775
953
}
776
954
777
- Expected<ExecutorAddr>
778
- MachOPlatformRuntimeState::lookupSymbolInJITDylib (void *DSOHandle,
779
- std::string_view Sym) {
780
- Expected<ExecutorAddr> Result ((ExecutorAddr ()));
781
- if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(
782
- SPSExecutorAddr, SPSString)>::call (&__orc_rt_macho_symbol_lookup_tag,
783
- Result,
784
- ExecutorAddr::fromPtr (DSOHandle),
785
- Sym))
955
+ Error MachOPlatformRuntimeState::requestPushSymbols (
956
+ JITDylibState &JDS, span<std::pair<std::string_view, bool >> Symbols) {
957
+ Error OpErr = Error::success ();
958
+ if (auto Err = WrapperFunction<SPSError (
959
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool >>)>::
960
+ call (&__orc_rt_macho_push_symbols_tag, OpErr,
961
+ ExecutorAddr::fromPtr (JDS.Header ), Symbols)) {
962
+ cantFail (std::move (OpErr));
786
963
return std::move (Err);
787
- return Result;
964
+ }
965
+ return OpErr;
966
+ }
967
+
968
+ template <typename VisitorFn>
969
+ void MachOPlatformRuntimeState::visitSymbolAddrs (
970
+ JITDylibState &JDS, std::vector<std::pair<std::string_view, bool >> &Symbols,
971
+ VisitorFn &&Visit) {
972
+
973
+ std::vector<std::pair<std::string_view, bool >> RemainingSymbols;
974
+
975
+ for (size_t Idx = 0 ; Idx != Symbols.size (); ++Idx) {
976
+ auto I = JDS.SymbolTable .find (Symbols[Idx].first );
977
+ if (I != JDS.SymbolTable .end ())
978
+ Visit (Idx, I->second );
979
+ else
980
+ RemainingSymbols.push_back (Symbols[Idx]);
981
+ }
982
+
983
+ Symbols = std::move (RemainingSymbols);
788
984
}
789
985
790
986
// eh-frame registration functions.
@@ -1193,6 +1389,38 @@ __orc_rt_macho_register_object_platform_sections(char *ArgData,
1193
1389
.release ();
1194
1390
}
1195
1391
1392
+ ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1393
+ __orc_rt_macho_register_object_symbol_table (char *ArgData, size_t ArgSize) {
1394
+ using SymtabContainer = std::vector<
1395
+ std::tuple<ExecutorAddr, ExecutorAddr,
1396
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
1397
+ return WrapperFunction<SPSError (
1398
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
1399
+ SPSMachOExecutorSymbolFlags>>)>::
1400
+ handle (ArgData, ArgSize,
1401
+ [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
1402
+ return MachOPlatformRuntimeState::get ()
1403
+ .registerObjectSymbolTable (HeaderAddr, Symbols);
1404
+ })
1405
+ .release ();
1406
+ }
1407
+
1408
+ ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1409
+ __orc_rt_macho_deregister_object_symbol_table (char *ArgData, size_t ArgSize) {
1410
+ using SymtabContainer = std::vector<
1411
+ std::tuple<ExecutorAddr, ExecutorAddr,
1412
+ MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
1413
+ return WrapperFunction<SPSError (
1414
+ SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
1415
+ SPSMachOExecutorSymbolFlags>>)>::
1416
+ handle (ArgData, ArgSize,
1417
+ [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
1418
+ return MachOPlatformRuntimeState::get ()
1419
+ .deregisterObjectSymbolTable (HeaderAddr, Symbols);
1420
+ })
1421
+ .release ();
1422
+ }
1423
+
1196
1424
ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1197
1425
__orc_rt_macho_deregister_object_platform_sections (char *ArgData,
1198
1426
size_t ArgSize) {
0 commit comments