[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