diff --git a/compiler-rt/lib/orc/elfnix_platform.cpp b/compiler-rt/lib/orc/elfnix_platform.cpp index 0352f6c4e85336..7800bcd7ff15a2 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()); + __orc_rt_register_eh_frame_section( + POSR.EHFrameSection.Start.toPtr()); 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()); + __orc_rt_deregister_eh_frame_section( + POSR.EHFrameSection.Start.toPtr()); 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 00000000000000..0f7dcec4b5a5b5 --- /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 00000000000000..f56aa8fba950f9 --- /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 00000000000000..0f7dcec4b5a5b5 --- /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 00000000000000..f56aa8fba950f9 --- /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 5ce6c8b1fa7f40..b2e97cefbf0e82 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 d5bb51c9be80e4..cd06712797413d 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 6b12fe990a8ad3..3804b6dda91ff0 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 standardPlatformAliases(ExecutionSession &ES, + JITDylib &PlatformJD); /// Returns the array of required CXX aliases. static ArrayRef> requiredCXXAliases(); diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index d02760703f0678..c2577a91430875 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 +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; }