[compiler-rt] 981523b - [ORC-RT][ORC] Handle dynamic unwind registration for libunwind

Peter S. Housel via llvm-commits llvm-commits at lists.llvm.org
Fri May 6 14:01:12 PDT 2022


Author: Peter S. Housel
Date: 2022-05-06T14:00:29-07:00
New Revision: 981523b2e4675d4be496a333583b2f728c057d02

URL: https://github.com/llvm/llvm-project/commit/981523b2e4675d4be496a333583b2f728c057d02
DIFF: https://github.com/llvm/llvm-project/commit/981523b2e4675d4be496a333583b2f728c057d02.diff

LOG: [ORC-RT][ORC] Handle dynamic unwind registration for libunwind

This changes the ELFNix platform Orc runtime to use, when available,
the __unw_add_dynamic_eh_frame_section interface provided by libunwind
for registering .eh_frame sections loaded by JITLink. When libunwind
is not being used for unwinding, the ELFNix platform detects this and
defaults to the __register_frame interface provided by libgcc_s.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D114961

Added: 
    compiler-rt/test/orc/TestCases/FreeBSD/ehframe-default.cpp
    compiler-rt/test/orc/TestCases/FreeBSD/ehframe-libunwind.cpp
    compiler-rt/test/orc/TestCases/Linux/ehframe-default.cpp
    compiler-rt/test/orc/TestCases/Linux/ehframe-libunwind.cpp

Modified: 
    compiler-rt/lib/orc/elfnix_platform.cpp
    compiler-rt/test/orc/lit.cfg.py
    compiler-rt/test/orc/lit.site.cfg.py.in
    llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
    llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/orc/elfnix_platform.cpp b/compiler-rt/lib/orc/elfnix_platform.cpp
index 0352f6c4e8533..7800bcd7ff15a 100644
--- a/compiler-rt/lib/orc/elfnix_platform.cpp
+++ b/compiler-rt/lib/orc/elfnix_platform.cpp
@@ -29,10 +29,10 @@ ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_initializers_tag)
 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_deinitializers_tag)
 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag)
 
-// eh-frame registration functions.
-// We expect these to be available for all processes.
-extern "C" void __register_frame(const void *);
-extern "C" void __deregister_frame(const void *);
+// eh-frame registration functions, made available via aliases
+// installed by the Platform
+extern "C" void __orc_rt_register_eh_frame_section(const void *);
+extern "C" void __orc_rt_deregister_eh_frame_section(const void *);
 
 namespace {
 
@@ -172,7 +172,8 @@ void ELFNixPlatformRuntimeState::destroy() {
 Error ELFNixPlatformRuntimeState::registerObjectSections(
     ELFNixPerObjectSectionsToRegister POSR) {
   if (POSR.EHFrameSection.Start)
-    __register_frame(POSR.EHFrameSection.Start.toPtr<const char *>());
+    __orc_rt_register_eh_frame_section(
+        POSR.EHFrameSection.Start.toPtr<const char *>());
 
   if (POSR.ThreadDataSection.Start) {
     if (auto Err = registerThreadDataSection(
@@ -186,7 +187,8 @@ Error ELFNixPlatformRuntimeState::registerObjectSections(
 Error ELFNixPlatformRuntimeState::deregisterObjectSections(
     ELFNixPerObjectSectionsToRegister POSR) {
   if (POSR.EHFrameSection.Start)
-    __deregister_frame(POSR.EHFrameSection.Start.toPtr<const char *>());
+    __orc_rt_deregister_eh_frame_section(
+        POSR.EHFrameSection.Start.toPtr<const char *>());
 
   return Error::success();
 }

diff  --git a/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-default.cpp b/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-default.cpp
new file mode 100644
index 0000000000000..0f7dcec4b5a5b
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-default.cpp
@@ -0,0 +1,14 @@
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}

diff  --git a/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-libunwind.cpp b/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-libunwind.cpp
new file mode 100644
index 0000000000000..f56aa8fba950f
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/FreeBSD/ehframe-libunwind.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: libunwind-available
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: env LD_PRELOAD=%shared_libunwind %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}

diff  --git a/compiler-rt/test/orc/TestCases/Linux/ehframe-default.cpp b/compiler-rt/test/orc/TestCases/Linux/ehframe-default.cpp
new file mode 100644
index 0000000000000..0f7dcec4b5a5b
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/ehframe-default.cpp
@@ -0,0 +1,14 @@
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}

diff  --git a/compiler-rt/test/orc/TestCases/Linux/ehframe-libunwind.cpp b/compiler-rt/test/orc/TestCases/Linux/ehframe-libunwind.cpp
new file mode 100644
index 0000000000000..f56aa8fba950f
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/ehframe-libunwind.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: libunwind-available
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: env LD_PRELOAD=%shared_libunwind %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}

diff  --git a/compiler-rt/test/orc/lit.cfg.py b/compiler-rt/test/orc/lit.cfg.py
index 5ce6c8b1fa7f4..b2e97cefbf0e8 100644
--- a/compiler-rt/test/orc/lit.cfg.py
+++ b/compiler-rt/test/orc/lit.cfg.py
@@ -18,6 +18,11 @@ def build_invocation(compile_flags):
 else:
   orc_rt_path = '%s/libclang_rt.orc%s.a' % (config.compiler_rt_libdir, config.target_suffix)
 
+if config.libunwind_shared:
+  config.available_features.add('libunwind-available')
+  shared_libunwind_path = os.path.join(config.libunwind_install_dir, 'libunwind.so')
+  config.substitutions.append( ("%shared_libunwind", shared_libunwind_path) )
+
 config.substitutions.append(
     ('%clang ', build_invocation([config.target_cflags])))
 config.substitutions.append(

diff  --git a/compiler-rt/test/orc/lit.site.cfg.py.in b/compiler-rt/test/orc/lit.site.cfg.py.in
index d5bb51c9be80e..cd06712797413 100644
--- a/compiler-rt/test/orc/lit.site.cfg.py.in
+++ b/compiler-rt/test/orc/lit.site.cfg.py.in
@@ -6,6 +6,8 @@ config.orc_lit_source_dir = "@ORC_LIT_SOURCE_DIR@"
 config.target_cflags = "@ORC_TEST_TARGET_CFLAGS@"
 config.target_arch = "@ORC_TEST_TARGET_ARCH@"
 config.built_with_llvm = ("@COMPILER_RT_STANDALONE_BUILD@" != "TRUE")
+config.libunwind_shared = "@LIBUNWIND_ENABLE_SHARED@"
+config.libunwind_install_dir = "@LLVM_BINARY_DIR@/@LIBUNWIND_INSTALL_LIBRARY_DIR@"
 
 # Load common config for all compiler-rt lit tests
 lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
index 6b12fe990a8ad..3804b6dda91ff 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
@@ -109,7 +109,8 @@ class ELFNixPlatform : public Platform {
   /// Returns an AliasMap containing the default aliases for the ELFNixPlatform.
   /// This can be modified by clients when constructing the platform to add
   /// or remove aliases.
-  static SymbolAliasMap standardPlatformAliases(ExecutionSession &ES);
+  static Expected<SymbolAliasMap> standardPlatformAliases(ExecutionSession &ES,
+                                                          JITDylib &PlatformJD);
 
   /// Returns the array of required CXX aliases.
   static ArrayRef<std::pair<const char *, const char *>> requiredCXXAliases();

diff  --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index d02760703f067..c2577a9143087 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -117,8 +117,12 @@ ELFNixPlatform::Create(ExecutionSession &ES,
                                    inconvertibleErrorCode());
 
   // Create default aliases if the caller didn't supply any.
-  if (!RuntimeAliases)
-    RuntimeAliases = standardPlatformAliases(ES);
+  if (!RuntimeAliases) {
+    auto StandardRuntimeAliases = standardPlatformAliases(ES, PlatformJD);
+    if (!StandardRuntimeAliases)
+      return StandardRuntimeAliases.takeError();
+    RuntimeAliases = std::move(*StandardRuntimeAliases);
+  }
 
   // Define the aliases.
   if (auto Err = PlatformJD.define(symbolAliases(std::move(*RuntimeAliases))))
@@ -189,10 +193,53 @@ static void addAliases(ExecutionSession &ES, SymbolAliasMap &Aliases,
   }
 }
 
-SymbolAliasMap ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES) {
+Expected<SymbolAliasMap>
+ELFNixPlatform::standardPlatformAliases(ExecutionSession &ES,
+                                        JITDylib &PlatformJD) {
   SymbolAliasMap Aliases;
   addAliases(ES, Aliases, requiredCXXAliases());
   addAliases(ES, Aliases, standardRuntimeUtilityAliases());
+
+  // Determine whether or not the libunwind extended-API function for
+  // dynamically registering an entire .eh_frame section is available.
+  // If it is not, we assume that libgcc_s is being used, and alias to
+  // its __register_frame with the same functionality.
+  auto RTRegisterFrame = ES.intern("__orc_rt_register_eh_frame_section");
+  auto LibUnwindRegisterFrame = ES.intern("__unw_add_dynamic_eh_frame_section");
+  auto RTDeregisterFrame = ES.intern("__orc_rt_deregister_eh_frame_section");
+  auto LibUnwindDeregisterFrame =
+      ES.intern("__unw_remove_dynamic_eh_frame_section");
+  auto SM = ES.lookup(makeJITDylibSearchOrder(&PlatformJD),
+                      SymbolLookupSet()
+                          .add(LibUnwindRegisterFrame,
+                               SymbolLookupFlags::WeaklyReferencedSymbol)
+                          .add(LibUnwindDeregisterFrame,
+                               SymbolLookupFlags::WeaklyReferencedSymbol));
+  if (!SM) { // Weak-ref means no "missing symbol" errors, so this must be
+             // something more serious that we should report.
+    return SM.takeError();
+  } else if (SM->size() == 2) {
+    LLVM_DEBUG({
+      dbgs() << "Using libunwind " << LibUnwindRegisterFrame
+             << " for unwind info registration\n";
+    });
+    Aliases[std::move(RTRegisterFrame)] = {LibUnwindRegisterFrame,
+                                           JITSymbolFlags::Exported};
+    Aliases[std::move(RTDeregisterFrame)] = {LibUnwindDeregisterFrame,
+                                             JITSymbolFlags::Exported};
+  } else {
+    // Since LLVM libunwind is not present, we assume that unwinding
+    // is provided by libgcc
+    LLVM_DEBUG({
+      dbgs() << "Using libgcc __register_frame"
+             << " for unwind info registration\n";
+    });
+    Aliases[std::move(RTRegisterFrame)] = {ES.intern("__register_frame"),
+                                           JITSymbolFlags::Exported};
+    Aliases[std::move(RTDeregisterFrame)] = {ES.intern("__deregister_frame"),
+                                             JITSymbolFlags::Exported};
+  }
+
   return Aliases;
 }
 


        


More information about the llvm-commits mailing list