Skip to content

Commit 93509b4

Browse files
committed
[ORC-RT][ORC][MachO] Fix some issues with executor-side symbol tables.
1. Prevent deadlock by unlocking JDStatesMutex when calling back to the controller to request a push of new symbols. (If JDStatesMutex is locked then the push operation can't register the new symbols, and so can't complete). 2. Record MachOPlatform runtime symbols during bootstrap and attach their registration to the bootstrap-completion graph, similar to the way that deferred allocation actions are handled. We can't register the symbols the normal way during bootstrap since the symbol registration function is itself in the process of being materialized. 3. Add dlsym testcases to exercise these fixes.
1 parent 9d3aec5 commit 93509b4

File tree

7 files changed

+154
-18
lines changed

7 files changed

+154
-18
lines changed

compiler-rt/lib/orc/macho_platform.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
830830
}
831831

832832
void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, const char *Symbol) {
833-
std::lock_guard<std::mutex> Lock(JDStatesMutex);
833+
std::unique_lock<std::mutex> Lock(JDStatesMutex);
834834
auto *JDS = getJITDylibStateByHeader(DSOHandle);
835835
if (!JDS) {
836836
std::ostringstream ErrStream;
@@ -860,10 +860,12 @@ void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, const char *Symbol) {
860860

861861
// Otherwise call back to the controller to try to request that the symbol
862862
// be materialized.
863+
Lock.unlock();
863864
if (auto Err = requestPushSymbols(*JDS, {Symbols.data(), Symbols.size()})) {
864865
DLFcnError = toString(std::move(Err));
865866
return nullptr;
866867
}
868+
Lock.lock();
867869

868870
// Try another local resolution.
869871
visitSymbolAddrs(*JDS, Symbols, [&](size_t Idx, ElemResult E) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.section __TEXT,__text,regular,pure_instructions
2+
.build_version macos, 14, 0 sdk_version 14, 4
3+
.globl _ret_self
4+
.p2align 2
5+
_ret_self:
6+
adrp x0, _ret_self@PAGE
7+
add x0, x0, _ret_self@PAGEOFF
8+
ret
9+
10+
.subsections_via_symbols
11+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Test that __orc_rt_macho_jit_dlsym works as expected.
2+
//
3+
// RUN: %clang -c -o %t.sym.o %p/Inputs/ret_self.S
4+
// RUN: %clang -c -o %t.test.o %s
5+
// RUN: %llvm_jitlink \
6+
// RUN: -alias Platform:_dlopen=___orc_rt_macho_jit_dlopen \
7+
// RUN: -alias Platform:_dlsym=___orc_rt_macho_jit_dlsym \
8+
// RUN: -alias Platform:_dlclose=___orc_rt_macho_jit_dlclose \
9+
// RUN: %t.test.o -lextra_sym -jd extra_sym %t.sym.o | FileCheck %s
10+
11+
// CHECK: entering main
12+
// CHECK-NEXT: found "ret_self" at
13+
// CHECK-NEXT: address of "ret_self" is consistent
14+
// CHECK-NEXT: leaving main
15+
16+
int printf(const char *restrict format, ...);
17+
void *dlopen(const char *path, int mode);
18+
void *dlsym(void *handle, const char *symbol);
19+
int dlclose(void *handle);
20+
21+
int main(int argc, char *argv[]) {
22+
printf("entering main\n");
23+
void *H = dlopen("extra_sym", 0);
24+
if (!H) {
25+
printf("failed\n");
26+
return -1;
27+
}
28+
29+
void *(*ret_self)(void) = (void *(*)(void))dlsym(H, "ret_self");
30+
if (ret_self)
31+
printf("found \"ret_self\" at %p\n", ret_self);
32+
else
33+
printf("failed to find \"ret_self\" via dlsym\n");
34+
35+
printf("address of \"ret_self\" is %s\n",
36+
ret_self() == ret_self ? "consistent" : "inconsistent");
37+
38+
if (dlclose(H) == -1) {
39+
printf("failed\n");
40+
return -1;
41+
}
42+
printf("leaving main\n");
43+
return 0;
44+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// A function that returns its own address. Handy for testing whether JIT'd code
2+
// and JIT symbol tables agree on addresses.
3+
4+
.section __TEXT,__text,regular,pure_instructions
5+
.build_version macos, 14, 0
6+
.globl _ret_self
7+
.p2align 4, 0x90
8+
_ret_self:
9+
leaq _ret_self(%rip), %rax
10+
retq
11+
12+
.subsections_via_symbols
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Test that __orc_rt_macho_jit_dlsym works as expected.
2+
//
3+
// RUN: %clang -c -o %t.sym.o %p/Inputs/ret_self.S
4+
// RUN: %clang -c -o %t.test.o %s
5+
// RUN: %llvm_jitlink \
6+
// RUN: -alias Platform:_dlopen=___orc_rt_macho_jit_dlopen \
7+
// RUN: -alias Platform:_dlsym=___orc_rt_macho_jit_dlsym \
8+
// RUN: -alias Platform:_dlclose=___orc_rt_macho_jit_dlclose \
9+
// RUN: %t.test.o -lextra_sym -jd extra_sym %t.sym.o | FileCheck %s
10+
11+
// CHECK: entering main
12+
// CHECK-NEXT: found "ret_self" at
13+
// CHECK-NEXT: address of "ret_self" is consistent
14+
// CHECK-NEXT: leaving main
15+
16+
int printf(const char *restrict format, ...);
17+
void *dlopen(const char *path, int mode);
18+
void *dlsym(void *handle, const char *symbol);
19+
int dlclose(void *handle);
20+
21+
int main(int argc, char *argv[]) {
22+
printf("entering main\n");
23+
void *H = dlopen("extra_sym", 0);
24+
if (!H) {
25+
printf("failed\n");
26+
return -1;
27+
}
28+
29+
void *(*ret_self)(void) = (void *(*)(void))dlsym(H, "ret_self");
30+
if (ret_self)
31+
printf("found \"ret_self\" at %p\n", ret_self);
32+
else
33+
printf("failed to find \"ret_self\" via dlsym\n");
34+
35+
printf("address of \"ret_self\" is %s\n",
36+
ret_self() == ret_self ? "consistent" : "inconsistent");
37+
38+
if (dlclose(H) == -1) {
39+
printf("failed\n");
40+
return -1;
41+
}
42+
printf("leaving main\n");
43+
return 0;
44+
}

llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,17 @@ class MachOPlatform : public Platform {
118118
standardRuntimeUtilityAliases();
119119

120120
private:
121+
using SymbolTableVector = SmallVector<
122+
std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>;
123+
121124
// Data needed for bootstrap only.
122125
struct BootstrapInfo {
123126
std::mutex Mutex;
124127
std::condition_variable CV;
125128
size_t ActiveGraphs = 0;
126129
shared::AllocActions DeferredAAs;
127130
ExecutorAddr MachOHeaderAddr;
131+
SymbolTableVector SymTab;
128132
};
129133

130134
// The MachOPlatformPlugin scans/modifies LinkGraphs to support MachO

llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ class SPSSerializationTraits<SPSMachOExecutorSymbolFlags,
8989

9090
namespace {
9191

92+
using SPSRegisterSymbolsArgs =
93+
SPSArgList<SPSExecutorAddr,
94+
SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
95+
SPSMachOExecutorSymbolFlags>>>;
96+
9297
std::unique_ptr<jitlink::LinkGraph> createPlatformGraph(MachOPlatform &MOP,
9398
std::string Name) {
9499
unsigned PointerSize;
@@ -208,24 +213,28 @@ constexpr MachOHeaderMaterializationUnit::HeaderSymbol
208213
class MachOPlatformCompleteBootstrapMaterializationUnit
209214
: public MaterializationUnit {
210215
public:
216+
using SymbolTableVector =
217+
SmallVector<std::tuple<ExecutorAddr, ExecutorAddr,
218+
MachOPlatform::MachOExecutorSymbolFlags>>;
219+
211220
MachOPlatformCompleteBootstrapMaterializationUnit(
212221
MachOPlatform &MOP, StringRef PlatformJDName,
213-
SymbolStringPtr CompleteBootstrapSymbol, shared::AllocActions DeferredAAs,
222+
SymbolStringPtr CompleteBootstrapSymbol, SymbolTableVector SymTab,
223+
shared::AllocActions DeferredAAs, ExecutorAddr MachOHeaderAddr,
214224
ExecutorAddr PlatformBootstrap, ExecutorAddr PlatformShutdown,
215225
ExecutorAddr RegisterJITDylib, ExecutorAddr DeregisterJITDylib,
216226
ExecutorAddr RegisterObjectSymbolTable,
217-
ExecutorAddr DeregisterObjectSymbolTable, ExecutorAddr MachOHeaderAddr)
227+
ExecutorAddr DeregisterObjectSymbolTable)
218228
: MaterializationUnit(
219229
{{{CompleteBootstrapSymbol, JITSymbolFlags::None}}, nullptr}),
220230
MOP(MOP), PlatformJDName(PlatformJDName),
221231
CompleteBootstrapSymbol(std::move(CompleteBootstrapSymbol)),
222-
DeferredAAs(std::move(DeferredAAs)),
223-
PlatformBootstrap(PlatformBootstrap),
232+
SymTab(std::move(SymTab)), DeferredAAs(std::move(DeferredAAs)),
233+
MachOHeaderAddr(MachOHeaderAddr), PlatformBootstrap(PlatformBootstrap),
224234
PlatformShutdown(PlatformShutdown), RegisterJITDylib(RegisterJITDylib),
225235
DeregisterJITDylib(DeregisterJITDylib),
226236
RegisterObjectSymbolTable(RegisterObjectSymbolTable),
227-
DeregisterObjectSymbolTable(DeregisterObjectSymbolTable),
228-
MachOHeaderAddr(MachOHeaderAddr) {}
237+
DeregisterObjectSymbolTable(DeregisterObjectSymbolTable) {}
229238

230239
StringRef getName() const override {
231240
return "MachOPlatformCompleteBootstrap";
@@ -242,7 +251,7 @@ class MachOPlatformCompleteBootstrapMaterializationUnit
242251
Linkage::Strong, Scope::Hidden, false, true);
243252

244253
// Reserve space for the stolen actions, plus two extras.
245-
G->allocActions().reserve(DeferredAAs.size() + 2);
254+
G->allocActions().reserve(DeferredAAs.size() + 3);
246255

247256
// 1. Bootstrap the platform support code.
248257
G->allocActions().push_back(
@@ -258,7 +267,14 @@ class MachOPlatformCompleteBootstrapMaterializationUnit
258267
cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
259268
DeregisterJITDylib, MachOHeaderAddr))});
260269

261-
// 3. Add the deferred actions to the graph.
270+
// 3. Register deferred symbols.
271+
G->allocActions().push_back(
272+
{cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
273+
RegisterObjectSymbolTable, MachOHeaderAddr, SymTab)),
274+
cantFail(WrapperFunctionCall::Create<SPSRegisterSymbolsArgs>(
275+
DeregisterObjectSymbolTable, MachOHeaderAddr, SymTab))});
276+
277+
// 4. Add the deferred actions to the graph.
262278
std::move(DeferredAAs.begin(), DeferredAAs.end(),
263279
std::back_inserter(G->allocActions()));
264280

@@ -271,14 +287,15 @@ class MachOPlatformCompleteBootstrapMaterializationUnit
271287
MachOPlatform &MOP;
272288
StringRef PlatformJDName;
273289
SymbolStringPtr CompleteBootstrapSymbol;
290+
SymbolTableVector SymTab;
274291
shared::AllocActions DeferredAAs;
292+
ExecutorAddr MachOHeaderAddr;
275293
ExecutorAddr PlatformBootstrap;
276294
ExecutorAddr PlatformShutdown;
277295
ExecutorAddr RegisterJITDylib;
278296
ExecutorAddr DeregisterJITDylib;
279297
ExecutorAddr RegisterObjectSymbolTable;
280298
ExecutorAddr DeregisterObjectSymbolTable;
281-
ExecutorAddr MachOHeaderAddr;
282299
};
283300

284301
static StringRef ObjCRuntimeObjectSectionsData[] = {
@@ -601,10 +618,11 @@ MachOPlatform::MachOPlatform(
601618
if ((Err = PlatformJD.define(
602619
std::make_unique<MachOPlatformCompleteBootstrapMaterializationUnit>(
603620
*this, PlatformJD.getName(), BootstrapCompleteSymbol,
604-
std::move(BI.DeferredAAs), PlatformBootstrap.Addr,
621+
std::move(BI.SymTab), std::move(BI.DeferredAAs),
622+
BI.MachOHeaderAddr, PlatformBootstrap.Addr,
605623
PlatformShutdown.Addr, RegisterJITDylib.Addr,
606624
DeregisterJITDylib.Addr, RegisterObjectSymbolTable.Addr,
607-
DeregisterObjectSymbolTable.Addr, BI.MachOHeaderAddr))))
625+
DeregisterObjectSymbolTable.Addr))))
608626
return;
609627
if ((Err = ES.lookup(makeJITDylibSearchOrder(
610628
&PlatformJD, JITDylibLookupFlags::MatchAllSymbols),
@@ -1714,16 +1732,17 @@ Error MachOPlatform::MachOPlatformPlugin::addSymbolTableRegistration(
17141732
HeaderAddr = I->second;
17151733
}
17161734

1717-
SmallVector<std::tuple<ExecutorAddr, ExecutorAddr, MachOExecutorSymbolFlags>>
1718-
SymTab;
1735+
SymbolTableVector LocalSymTab;
1736+
auto &SymTab = LLVM_LIKELY(!InBootstrapPhase) ? LocalSymTab
1737+
: MP.Bootstrap.load()->SymTab;
17191738
for (auto &[OriginalSymbol, NameSym] : JITSymTabInfo)
17201739
SymTab.push_back({NameSym->getAddress(), OriginalSymbol->getAddress(),
17211740
flagsForSymbol(*OriginalSymbol)});
17221741

1723-
using SPSRegisterSymbolsArgs =
1724-
SPSArgList<SPSExecutorAddr,
1725-
SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
1726-
SPSMachOExecutorSymbolFlags>>>;
1742+
// Bail out if we're in the bootstrap phase -- registration of thees symbols
1743+
// will be attached to the bootstrap graph.
1744+
if (LLVM_UNLIKELY(InBootstrapPhase))
1745+
return Error::success();
17271746

17281747
shared::AllocActions &allocActions = LLVM_LIKELY(!InBootstrapPhase)
17291748
? G.allocActions()

0 commit comments

Comments
 (0)