[llvm] [orc-rt] Strip leading '_' in NativeDylibAPIs on Darwin. (PR #203170)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 21:51:03 PDT 2026
https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/203170
>From b8c12b074e4742b35e45e2c7d9f3ff4bb75b7a7b Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 11 Jun 2026 13:32:37 +1000
Subject: [PATCH 1/2] [orc-rt] Strip leading '_' in NativeDylibAPIs on Darwin.
NativeDylibAPIs::lookup takes linker-mangled names. On Darwin, linker-mangling
adds an '_' to the front of C symbol names. We need to strip this off again
before calling dlsym (which expects a C name).
Linker mangled names that don't start with an '_' are treated as missing,
since dlsym could never find an address for such a symbol.
---
orc-rt/lib/executor/Unix/NativeDylibAPIs.inc | 12 +++++++++-
.../unittests/NativeDylibManagerSPSCITest.cpp | 23 +++++++++++++------
orc-rt/unittests/NativeDylibManagerTest.cpp | 23 +++++++++++++------
3 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/orc-rt/lib/executor/Unix/NativeDylibAPIs.inc b/orc-rt/lib/executor/Unix/NativeDylibAPIs.inc
index 39929ba79bf82..e16292efc86a4 100644
--- a/orc-rt/lib/executor/Unix/NativeDylibAPIs.inc
+++ b/orc-rt/lib/executor/Unix/NativeDylibAPIs.inc
@@ -48,7 +48,17 @@ hostOSLibraryLookup(void *Handle, const std::vector<std::string> &Names) {
// symbol isn't in the library" via per-iteration dlerror() checks.
dlerror();
for (const auto &Name : Names) {
- if (void *Addr = dlsym(Handle, Name.c_str()))
+#if defined(__APPLE__)
+ if (Name.empty() || Name[0] != '_') {
+ Result.push_back(std::nullopt);
+ continue;
+ }
+ const char *LookupName = Name.c_str() + 1;
+#else
+ const char *LookupName = Name.c_str();
+#endif // defined(__APPLE__)
+
+ if (void *Addr = dlsym(Handle, LookupName))
Result.push_back(Addr);
else if (dlerror() == nullptr)
Result.push_back(nullptr);
diff --git a/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp b/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
index 4ce65f8daaae2..1480bba38acad 100644
--- a/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
+++ b/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
@@ -58,6 +58,15 @@ constexpr auto Req = NativeDylibManager::RequiredSymbol;
constexpr auto Weak = NativeDylibManager::WeaklyReferencedSymbol;
} // namespace
+// Wrap a symbol-name string literal in the platform's linker-mangling.
+// NativeDylibManager::lookup takes linker-mangled names; on Darwin the
+// linker prefixes C names with '_'.
+#if defined(__APPLE__)
+#define MANGLED(name) "_" name
+#else
+#define MANGLED(name) name
+#endif
+
#ifndef NDM_TEST_LIB_PATH
#error \
"NDM_TEST_LIB_PATH must be defined to the path of the test shared library"
@@ -130,7 +139,7 @@ TEST_F(NativeDylibManagerSPSCITest, LoadEmptyPathReturnsGlobalHandle) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
- spsLookup(waitFor(LookupResult), Handle, {{"malloc", Req}});
+ spsLookup(waitFor(LookupResult), Handle, {{MANGLED("malloc"), Req}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 1U);
ASSERT_TRUE(Addrs[0].has_value())
@@ -146,7 +155,7 @@ TEST_F(NativeDylibManagerSPSCITest, LookupSingleSymbol) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
spsLookup(waitFor(LookupResult), Handle,
- {{"NativeDylibManagerTestFunc", Req}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 1U);
ASSERT_TRUE(Addrs[0].has_value());
@@ -164,8 +173,8 @@ TEST_F(NativeDylibManagerSPSCITest, LookupMultipleSymbols) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
spsLookup(waitFor(LookupResult), Handle,
- {{"NativeDylibManagerTestFunc", Req},
- {"NativeDylibManagerTestFunc2", Req}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req},
+ {MANGLED("NativeDylibManagerTestFunc2"), Req}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 2U);
ASSERT_TRUE(Addrs[0].has_value());
@@ -186,7 +195,7 @@ TEST_F(NativeDylibManagerSPSCITest, LookupWeakMissingSymbol) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
- spsLookup(waitFor(LookupResult), Handle, {{"no_such_symbol", Weak}});
+ spsLookup(waitFor(LookupResult), Handle, {{MANGLED("no_such_symbol"), Weak}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 1U);
ASSERT_TRUE(Addrs[0].has_value())
@@ -201,7 +210,7 @@ TEST_F(NativeDylibManagerSPSCITest, LookupRequiredMissingSymbol) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
- spsLookup(waitFor(LookupResult), Handle, {{"no_such_symbol", Req}});
+ spsLookup(waitFor(LookupResult), Handle, {{MANGLED("no_such_symbol"), Req}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 1U);
EXPECT_FALSE(Addrs[0].has_value())
@@ -216,7 +225,7 @@ TEST_F(NativeDylibManagerSPSCITest, LookupMixedRequiredAndWeak) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
spsLookup(waitFor(LookupResult), Handle,
- {{"NativeDylibManagerTestFunc", Req}, {"no_such_symbol", Weak}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req}, {MANGLED("no_such_symbol"), Weak}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 2U);
ASSERT_TRUE(Addrs[0].has_value());
diff --git a/orc-rt/unittests/NativeDylibManagerTest.cpp b/orc-rt/unittests/NativeDylibManagerTest.cpp
index a846c56fb42d4..8febefe85e3bb 100644
--- a/orc-rt/unittests/NativeDylibManagerTest.cpp
+++ b/orc-rt/unittests/NativeDylibManagerTest.cpp
@@ -27,6 +27,15 @@ constexpr auto Req = NativeDylibManager::RequiredSymbol;
constexpr auto Weak = NativeDylibManager::WeaklyReferencedSymbol;
} // namespace
+// Wrap a symbol-name string literal in the platform's linker-mangling.
+// NativeDylibManager::lookup takes linker-mangled names; on Darwin the
+// linker prefixes C names with '_'.
+#if defined(__APPLE__)
+#define MANGLED(name) "_" name
+#else
+#define MANGLED(name) name
+#endif
+
#ifndef NDM_TEST_LIB_PATH
#error \
"NDM_TEST_LIB_PATH must be defined to the path of the test shared library"
@@ -94,7 +103,7 @@ TEST(NativeDylibManagerTest, LoadEmptyPathReturnsGlobalHandle) {
ASSERT_TRUE(!!LoadResult) << toString(LoadResult.takeError());
void *Handle = *LoadResult;
- auto Result = syncLookup(*NDM, Handle, {{"malloc", Req}});
+ auto Result = syncLookup(*NDM, Handle, {{MANGLED("malloc"), Req}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 1U);
ASSERT_TRUE((*Result)[0].has_value())
@@ -110,7 +119,7 @@ TEST(NativeDylibManagerTest, LookupSingleSymbol) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
- auto Result = syncLookup(*NDM, Handle, {{"NativeDylibManagerTestFunc", Req}});
+ auto Result = syncLookup(*NDM, Handle, {{MANGLED("NativeDylibManagerTestFunc"), Req}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 1U);
ASSERT_TRUE((*Result)[0].has_value());
@@ -130,8 +139,8 @@ TEST(NativeDylibManagerTest, LookupMultipleSymbols) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
auto Result = syncLookup(*NDM, Handle,
- {{"NativeDylibManagerTestFunc", Req},
- {"NativeDylibManagerTestFunc2", Req}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req},
+ {MANGLED("NativeDylibManagerTestFunc2"), Req}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 2U);
ASSERT_TRUE((*Result)[0].has_value());
@@ -153,7 +162,7 @@ TEST(NativeDylibManagerTest, LookupWeakMissingSymbol) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
- auto Result = syncLookup(*NDM, Handle, {{"no_such_symbol", Weak}});
+ auto Result = syncLookup(*NDM, Handle, {{MANGLED("no_such_symbol"), Weak}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 1U);
ASSERT_TRUE((*Result)[0].has_value())
@@ -169,7 +178,7 @@ TEST(NativeDylibManagerTest, LookupRequiredMissingSymbol) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
- auto Result = syncLookup(*NDM, Handle, {{"no_such_symbol", Req}});
+ auto Result = syncLookup(*NDM, Handle, {{MANGLED("no_such_symbol"), Req}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 1U);
EXPECT_FALSE((*Result)[0].has_value())
@@ -186,7 +195,7 @@ TEST(NativeDylibManagerTest, LookupMixedRequiredAndWeak) {
auto Result = syncLookup(
*NDM, Handle,
- {{"NativeDylibManagerTestFunc", Req}, {"no_such_symbol", Weak}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req}, {MANGLED("no_such_symbol"), Weak}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 2U);
ASSERT_TRUE((*Result)[0].has_value());
>From 0c99519ce6cb2632d4d67d0399761b449b699c01 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Thu, 11 Jun 2026 14:50:46 +1000
Subject: [PATCH 2/2] clang-format
---
orc-rt/unittests/NativeDylibManagerSPSCITest.cpp | 3 ++-
orc-rt/unittests/NativeDylibManagerTest.cpp | 9 +++++----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp b/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
index 1480bba38acad..7ecda766ef01f 100644
--- a/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
+++ b/orc-rt/unittests/NativeDylibManagerSPSCITest.cpp
@@ -225,7 +225,8 @@ TEST_F(NativeDylibManagerSPSCITest, LookupMixedRequiredAndWeak) {
std::future<Expected<Expected<std::vector<std::optional<void *>>>>>
LookupResult;
spsLookup(waitFor(LookupResult), Handle,
- {{MANGLED("NativeDylibManagerTestFunc"), Req}, {MANGLED("no_such_symbol"), Weak}});
+ {{MANGLED("NativeDylibManagerTestFunc"), Req},
+ {MANGLED("no_such_symbol"), Weak}});
auto Addrs = cantFail(cantFail(LookupResult.get()));
ASSERT_EQ(Addrs.size(), 2U);
ASSERT_TRUE(Addrs[0].has_value());
diff --git a/orc-rt/unittests/NativeDylibManagerTest.cpp b/orc-rt/unittests/NativeDylibManagerTest.cpp
index 8febefe85e3bb..367b8b8600834 100644
--- a/orc-rt/unittests/NativeDylibManagerTest.cpp
+++ b/orc-rt/unittests/NativeDylibManagerTest.cpp
@@ -119,7 +119,8 @@ TEST(NativeDylibManagerTest, LookupSingleSymbol) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
- auto Result = syncLookup(*NDM, Handle, {{MANGLED("NativeDylibManagerTestFunc"), Req}});
+ auto Result =
+ syncLookup(*NDM, Handle, {{MANGLED("NativeDylibManagerTestFunc"), Req}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 1U);
ASSERT_TRUE((*Result)[0].has_value());
@@ -193,9 +194,9 @@ TEST(NativeDylibManagerTest, LookupMixedRequiredAndWeak) {
void *Handle = cantFail(syncLoad(*NDM, NDM_TEST_LIB_PATH));
- auto Result = syncLookup(
- *NDM, Handle,
- {{MANGLED("NativeDylibManagerTestFunc"), Req}, {MANGLED("no_such_symbol"), Weak}});
+ auto Result = syncLookup(*NDM, Handle,
+ {{MANGLED("NativeDylibManagerTestFunc"), Req},
+ {MANGLED("no_such_symbol"), Weak}});
ASSERT_TRUE(!!Result) << toString(Result.takeError());
ASSERT_EQ(Result->size(), 2U);
ASSERT_TRUE((*Result)[0].has_value());
More information about the llvm-commits
mailing list