Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -353,7 +353,7 @@ /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables /// by default. - virtual bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const; + virtual bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const; /// \brief Test whether this toolchain defaults to PIC. virtual bool isPICDefault() const = 0; Index: lib/Driver/ToolChain.cpp =================================================================== --- lib/Driver/ToolChain.cpp +++ lib/Driver/ToolChain.cpp @@ -220,7 +220,7 @@ } } -bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +bool ToolChain::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { return false; } Index: lib/Driver/ToolChains/Arch/ARM.h =================================================================== --- lib/Driver/ToolChains/Arch/ARM.h +++ lib/Driver/ToolChains/Arch/ARM.h @@ -52,6 +52,8 @@ int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); +bool ARMNeedUnwindTable(const llvm::opt::ArgList &Args, bool isCXX); + } // end namespace arm } // end namespace tools } // end namespace driver Index: lib/Driver/ToolChains/Arch/ARM.cpp =================================================================== --- lib/Driver/ToolChains/Arch/ARM.cpp +++ lib/Driver/ToolChains/Arch/ARM.cpp @@ -565,3 +565,10 @@ if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) CmdArgs.push_back("--be8"); } + +bool arm::ARMNeedUnwindTable(const llvm::opt::ArgList &Args, bool isCXX) { + // Unwind tables are emitted for C++ or if -fno-exceptions is supplied. + // We cannot rely on noThrow attribute because we still need the .exidx section + // even if the function does not throw. (Excepted for NetBSD that uses DwarfCFI). + return Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, isCXX); +} Index: lib/Driver/ToolChains/BareMetal.h =================================================================== --- lib/Driver/ToolChains/BareMetal.h +++ lib/Driver/ToolChains/BareMetal.h @@ -32,6 +32,7 @@ public: bool useIntegratedAs() const override { return true; } + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } bool isPIEDefault() const override { return false; } Index: lib/Driver/ToolChains/BareMetal.cpp =================================================================== --- lib/Driver/ToolChains/BareMetal.cpp +++ lib/Driver/ToolChains/BareMetal.cpp @@ -13,6 +13,7 @@ #include "InputInfo.h" #include "Gnu.h" +#include "Arch/ARM.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -57,6 +58,18 @@ return true; } +bool BareMetal::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return tools::arm::ARMNeedUnwindTable(Args, isCXX); + default: + return false; + } +} + bool BareMetal::handlesTarget(const llvm::Triple &Triple) { return isARMBareMetal(Triple); } Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -3409,13 +3409,15 @@ CmdArgs.push_back("-mpie-copy-relocations"); } + bool isCXX = C.getDriver().CCCIsCXX() || types::isCXX(Input.getType()); + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. bool AsynchronousUnwindTables = Args.hasFlag(options::OPT_fasynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables, - (getToolChain().IsUnwindTablesDefault(Args) || + (getToolChain().IsUnwindTablesDefault(Args, isCXX) || getToolChain().getSanitizerArgs().needsUnwindTables()) && !KernelOrKext); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, Index: lib/Driver/ToolChains/CrossWindows.h =================================================================== --- lib/Driver/ToolChains/CrossWindows.h +++ lib/Driver/ToolChains/CrossWindows.h @@ -56,7 +56,7 @@ const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; Index: lib/Driver/ToolChains/CrossWindows.cpp =================================================================== --- lib/Driver/ToolChains/CrossWindows.cpp +++ lib/Driver/ToolChains/CrossWindows.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "CrossWindows.h" +#include "Arch/ARM.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -218,10 +219,20 @@ } } -bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does // not know how to emit them. - return getArch() == llvm::Triple::x86_64; + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return tools::arm::ARMNeedUnwindTable(Args, isCXX); + case llvm::Triple::x86_64: + return true; + default: + return false; + } } bool CrossWindowsToolChain::isPICDefault() const { Index: lib/Driver/ToolChains/Darwin.h =================================================================== --- lib/Driver/ToolChains/Darwin.h +++ lib/Driver/ToolChains/Darwin.h @@ -214,7 +214,7 @@ bool UseObjCMixedDispatch() const override { return true; } - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; Index: lib/Driver/ToolChains/Darwin.cpp =================================================================== --- lib/Driver/ToolChains/Darwin.cpp +++ lib/Driver/ToolChains/Darwin.cpp @@ -1837,7 +1837,7 @@ return DAL; } -bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { +bool MachO::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { // Unwind tables are not emitted if -fno-exceptions is supplied (except when // targeting x86_64). return getArch() == llvm::Triple::x86_64 || Index: lib/Driver/ToolChains/Gnu.h =================================================================== --- lib/Driver/ToolChains/Gnu.h +++ lib/Driver/ToolChains/Gnu.h @@ -284,7 +284,7 @@ void printVerboseInfo(raw_ostream &OS) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -2175,8 +2175,22 @@ CudaInstallation.print(OS); } -bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { - return getArch() == llvm::Triple::x86_64; +bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { + + // Unwind tables are emitted when targeting x86_64 and ARM for C++ or -fexceptions only). + // For ARM we cannot just use UWTable because we still need the .exidx section + // even if the function does not throw. + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return tools::arm::ARMNeedUnwindTable(Args, isCXX); + case llvm::Triple::x86_64: + return true; + default: + return false; + } } bool Generic_GCC::isPICDefault() const { Index: lib/Driver/ToolChains/MSVC.h =================================================================== --- lib/Driver/ToolChains/MSVC.h +++ lib/Driver/ToolChains/MSVC.h @@ -73,7 +73,7 @@ Action::OffloadKind DeviceOffloadKind) const override; bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; Index: lib/Driver/ToolChains/MSVC.cpp =================================================================== --- lib/Driver/ToolChains/MSVC.cpp +++ lib/Driver/ToolChains/MSVC.cpp @@ -10,6 +10,7 @@ #include "MSVC.h" #include "CommonArgs.h" #include "Darwin.h" +#include "Arch/ARM.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Version.h" #include "clang/Driver/Compilation.h" @@ -707,7 +708,7 @@ return true; } -bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { +bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { // Emit unwind tables by default on Win64. All non-x86_32 Windows platforms // such as ARM and PPC actually require unwind tables, but LLVM doesn't know // how to generate them yet. @@ -716,7 +717,17 @@ if (getTriple().isOSBinFormatMachO()) return false; - return getArch() == llvm::Triple::x86_64; + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return tools::arm::ARMNeedUnwindTable(Args, isCXX); + case llvm::Triple::x86_64: + return true; + default: + return false; + } } bool MSVCToolChain::isPICDefault() const { Index: lib/Driver/ToolChains/MinGW.h =================================================================== --- lib/Driver/ToolChains/MinGW.h +++ lib/Driver/ToolChains/MinGW.h @@ -60,7 +60,7 @@ const llvm::opt::ArgList &Args); bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override; bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; Index: lib/Driver/ToolChains/MinGW.cpp =================================================================== --- lib/Driver/ToolChains/MinGW.cpp +++ lib/Driver/ToolChains/MinGW.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MinGW.h" +#include "Arch/ARM.h" #include "InputInfo.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" @@ -358,8 +359,19 @@ return new tools::MinGW::Linker(*this); } -bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { - return getArch() == llvm::Triple::x86_64; +bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args, bool isCXX) const { + // Unwind tables are emitted when targeting x86_64 and ARM for C++ or -fexceptions). + switch (getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return tools::arm::ARMNeedUnwindTable(Args, isCXX); + case llvm::Triple::x86_64: + return true; + default: + return false; + } } bool toolchains::MinGW::isPICDefault() const { Index: lib/Driver/ToolChains/NetBSD.h =================================================================== --- lib/Driver/ToolChains/NetBSD.h +++ lib/Driver/ToolChains/NetBSD.h @@ -65,7 +65,7 @@ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args, bool isCXX) const override { return true; } Index: test/Driver/arm-unwind.c =================================================================== --- /dev/null +++ test/Driver/arm-unwind.c @@ -0,0 +1,9 @@ +// Do not add function attribute "uwtable" for arm ehabi targets for C mode. + +// RUN: %clang -target arm-none-eabi -### -S %s -o %t.s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-EABI %s +// CHECK-EABI-NOT: -munwind-tables + +// RUN: %clang -target arm--linux-gnueabihf -### -S %s -o %t.s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-GNU %s +// CHECK-GNU-NOT: -munwind-tables Index: test/Driver/arm-unwind.cpp =================================================================== --- /dev/null +++ test/Driver/arm-unwind.cpp @@ -0,0 +1,9 @@ +// Add function attribute "uwtable" for arm ehabi targets in C++. + +// RUN: %clang -target arm-none-eabi -### -S %s -o %t.s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-EABI %s +// CHECK-EABI: -munwind-tables + +// RUN: %clang -target arm-none-eabi -### -S %s -o %t.s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-GNU %s +// CHECK-GNU: -munwind-tables