MaskRay created this revision.
MaskRay added reviewers: Sanitizers, jdoerfert, joerg, nickdesaulniers, rnk.
Herald added subscribers: dexonsmith, hiraditya.
MaskRay requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

On ELF targets, if a function has uwtable or personality, or does not have
nounwind (`needsUnwindTableEntry`), it marks that `.eh_frame` is needed in the 
module.

Then, a function gets `.eh_frame` if `needsUnwindTableEntry` or `-g[123]` is 
specified.
(i.e. If -g[123], every function gets `.eh_frame`.
This behavior is strange but that is the status quo on GCC and Clang.)

Let's take asan as an example. Other sanitizers are similar.
`asan.module_[cd]tor` has no attribute. `needsUnwindTableEntry` returns true,
so every function gets `.eh_frame` if `-g[123]` is specified.
This is the root cause that
`-fno-exceptions -fno-asynchronous-unwind-tables -g` produces .debug_frame
while
`-fno-exceptions -fno-asynchronous-unwind-tables -g -fsanitize=address` 
produces .eh_frame.

This patch

- sets the nounwind attribute on sanitizer module ctor/dtor.
- let Clang emit a module flag metadata "uwtable" for 
-fasynchronous-unwind-tables. If "uwtable" is set, sanitizer module ctor/dtor 
additionally get the uwtable attribute.

The "uwtable" mechanism is generic: synthesized functions not cloned/specialized
from existing ones should consider `Function::createWithDefaultAttr` instead of
`Function::create` if they want to get some default attributes which
have more of module semantics.

Other candidates: "frame-pointer" 
(https://github.com/ClangBuiltLinux/linux/issues/955
https://github.com/ClangBuiltLinux/linux/issues/1238), dso_local, etc.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100251

Files:
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/test/CodeGen/asan-globals.cpp
  clang/test/CodeGen/asan-new-pm.ll
  clang/test/CodeGen/asan-no-globals-no-comdat.cpp
  llvm/include/llvm/IR/Function.h
  llvm/include/llvm/IR/Module.h
  llvm/lib/IR/Function.cpp
  llvm/lib/IR/Module.cpp
  llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
  llvm/lib/Transforms/Utils/ModuleUtils.cpp
  llvm/test/Instrumentation/AddressSanitizer/basic.ll
  llvm/test/Instrumentation/AddressSanitizer/no-globals.ll
  llvm/test/Instrumentation/AddressSanitizer/uwtable.ll
  llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
  llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
  llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll
  
llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-8bit-counters.ll
  llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll
  llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll

Index: llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll
===================================================================
--- llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll
+++ llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard.ll
@@ -60,5 +60,7 @@
   ret void
 }
 
-; ELF-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() comdat {
-; MACHO-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() {
+; ELF-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() #2 comdat {
+; MACHO-LABEL: define internal void @sancov.module_ctor_trace_pc_guard() #2 {
+
+; CHECK: attributes #2 = { nounwind }
Index: llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll
===================================================================
--- llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll
+++ llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-bool-flag.ll
@@ -4,8 +4,8 @@
 ; Module ctors should have stable names across modules, not something like
 ; @sancov.module_ctor.3 that may cause duplicate ctors after linked together.
 
-; CHECK: define internal void @sancov.module_ctor_trace_pc_guard() comdat {
-; CHECK: define internal void @sancov.module_ctor_bool_flag() comdat {
+; CHECK: define internal void @sancov.module_ctor_trace_pc_guard() #[[#]] comdat {
+; CHECK: define internal void @sancov.module_ctor_bool_flag() #[[#]] comdat {
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 target triple = "x86_64-unknown-linux-gnu"
Index: llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-8bit-counters.ll
===================================================================
--- llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-8bit-counters.ll
+++ llvm/test/Instrumentation/SanitizerCoverage/trace-pc-guard-inline-8bit-counters.ll
@@ -4,8 +4,8 @@
 ; Module ctors should have stable names across modules, not something like
 ; @sancov.module_ctor.3 that may cause duplicate ctors after linked together.
 
-; CHECK: define internal void @sancov.module_ctor_trace_pc_guard() comdat {
-; CHECK: define internal void @sancov.module_ctor_8bit_counters() comdat {
+; CHECK: define internal void @sancov.module_ctor_trace_pc_guard() #[[#]] comdat {
+; CHECK: define internal void @sancov.module_ctor_8bit_counters() #[[#]] comdat {
 
 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
 target triple = "x86_64-unknown-linux-gnu"
Index: llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll
===================================================================
--- llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll
+++ llvm/test/Instrumentation/MemorySanitizer/msan_basic.ll
@@ -1013,7 +1013,7 @@
 ; CHECK-NEXT: ret i8*
 
 
-; CHECK-LABEL: define internal void @msan.module_ctor() {
+; CHECK-LABEL: define internal void @msan.module_ctor() #[[#ATTR:]] {
 ; CHECK: call void @__msan_init()
 
 ; CHECK-CALLS: declare void @__msan_maybe_warning_1(i8 zeroext, i32 zeroext)
@@ -1024,3 +1024,5 @@
 ; CHECK-CALLS: declare void @__msan_maybe_store_origin_4(i32 zeroext, i8*, i32 zeroext)
 ; CHECK-CALLS: declare void @__msan_maybe_warning_8(i64 zeroext, i32 zeroext)
 ; CHECK-CALLS: declare void @__msan_maybe_store_origin_8(i64 zeroext, i8*, i32 zeroext)
+
+; CHECK:       attributes #[[#ATTR]] = { nounwind }
Index: llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
===================================================================
--- llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
+++ llvm/test/Instrumentation/HWAddressSanitizer/with-calls.ll
@@ -197,7 +197,7 @@
 
 ; CHECK: declare void @__hwasan_init()
 
-; CHECK:      define internal void @hwasan.module_ctor() comdat {
+; CHECK:      define internal void @hwasan.module_ctor() #[[#]] comdat {
 ; CHECK-NEXT:   call void @__hwasan_init()
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
Index: llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
===================================================================
--- llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
+++ llvm/test/Instrumentation/HWAddressSanitizer/basic.ll
@@ -406,7 +406,9 @@
 
 ; CHECK: declare void @__hwasan_init()
 
-; CHECK:      define internal void @hwasan.module_ctor() comdat {
+; CHECK:      define internal void @hwasan.module_ctor() #[[#ATTR:]] comdat {
 ; CHECK-NEXT:   call void @__hwasan_init()
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: }
+
+; CHECK:      attributes #[[#ATTR]] = { nounwind }
Index: llvm/test/Instrumentation/AddressSanitizer/uwtable.ll
===================================================================
--- /dev/null
+++ llvm/test/Instrumentation/AddressSanitizer/uwtable.ll
@@ -0,0 +1,21 @@
+; RUN: opt < %s -passes='asan-pipeline' -S | FileCheck %s
+
+target triple = "x86_64-unknown-linux-gnu"
+
+@g = dso_local global i32 0, align 4
+
+define i32 @test_load() sanitize_address {
+entry:
+  %tmp = load i32, i32* @g, align 4
+  ret i32 %tmp
+}
+
+!llvm.module.flags = !{!0}
+
+;; Due to -fasynchronous-unwind-tables.
+!0 = !{i32 7, !"uwtable", i32 1}
+
+;; Set the uwtable attribute on ctor/dtor.
+; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]]
+; CHECK: define internal void @asan.module_dtor() #[[#ATTR]]
+; CHECK: attributes #[[#ATTR]] = { nounwind uwtable }
Index: llvm/test/Instrumentation/AddressSanitizer/no-globals.ll
===================================================================
--- llvm/test/Instrumentation/AddressSanitizer/no-globals.ll
+++ llvm/test/Instrumentation/AddressSanitizer/no-globals.ll
@@ -9,5 +9,5 @@
 ; CHECK-NOT: @llvm.global_dtors
 ; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* bitcast (void ()* @asan.module_ctor to i8*) }]
 ; CHECK-NOT: @llvm.global_dtors
-; CHECK: define internal void @asan.module_ctor() comdat
+; CHECK: define internal void @asan.module_ctor() #[[#]] comdat
 ; CHECK-NOT: @llvm.global_dtors
Index: llvm/test/Instrumentation/AddressSanitizer/basic.ll
===================================================================
--- llvm/test/Instrumentation/AddressSanitizer/basic.ll
+++ llvm/test/Instrumentation/AddressSanitizer/basic.ll
@@ -225,8 +225,12 @@
   ret void
 }
 
-; CHECK: define internal void @asan.module_ctor()
+;; ctor/dtor have the nounwind attribute. See uwtable.ll, they additionally have
+;; the uwtable attribute with the module flag "uwtable".
+; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]] {{(comdat )?}}{
 ; CHECK: call void @__asan_init()
 
+; CHECK: attributes #[[#ATTR]] = { nounwind }
+
 ; PROF
 ; CHECK: ![[PROF]] = !{!"branch_weights", i32 1, i32 100000}
Index: llvm/lib/Transforms/Utils/ModuleUtils.cpp
===================================================================
--- llvm/lib/Transforms/Utils/ModuleUtils.cpp
+++ llvm/lib/Transforms/Utils/ModuleUtils.cpp
@@ -122,9 +122,10 @@
 }
 
 Function *llvm::createSanitizerCtor(Module &M, StringRef CtorName) {
-  Function *Ctor = Function::Create(
+  Function *Ctor = Function::createWithDefaultAttr(
       FunctionType::get(Type::getVoidTy(M.getContext()), false),
-      GlobalValue::InternalLinkage, CtorName, &M);
+      GlobalValue::InternalLinkage, 0, CtorName, &M);
+  Ctor->addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind);
   BasicBlock *CtorBB = BasicBlock::Create(M.getContext(), "", Ctor);
   ReturnInst::Create(M.getContext(), CtorBB);
   return Ctor;
Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -2077,9 +2077,11 @@
 }
 
 Instruction *ModuleAddressSanitizer::CreateAsanModuleDtor(Module &M) {
-  AsanDtorFunction =
-      Function::Create(FunctionType::get(Type::getVoidTy(*C), false),
-                       GlobalValue::InternalLinkage, kAsanModuleDtorName, &M);
+  AsanDtorFunction = Function::createWithDefaultAttr(
+      FunctionType::get(Type::getVoidTy(*C), false),
+      GlobalValue::InternalLinkage, 0, kAsanModuleDtorName, &M);
+  AsanDtorFunction->addAttribute(AttributeList::FunctionIndex,
+                                 Attribute::NoUnwind);
   BasicBlock *AsanDtorBB = BasicBlock::Create(*C, "", AsanDtorFunction);
 
   return ReturnInst::Create(*C, AsanDtorBB);
Index: llvm/lib/IR/Module.cpp
===================================================================
--- llvm/lib/IR/Module.cpp
+++ llvm/lib/IR/Module.cpp
@@ -669,6 +669,13 @@
   addModuleFlag(ModFlagBehavior::Max, "RtLibUseGOT", 1);
 }
 
+bool Module::getUwtable() const {
+  auto *Val = cast_or_null<ConstantAsMetadata>(getModuleFlag("uwtable"));
+  return Val && (cast<ConstantInt>(Val->getValue())->getZExtValue() > 0);
+}
+
+void Module::setUwtable() { addModuleFlag(ModFlagBehavior::Max, "uwtable", 1); }
+
 void Module::setSDKVersion(const VersionTuple &V) {
   SmallVector<unsigned, 3> Entries;
   Entries.push_back(V.getMajor());
Index: llvm/lib/IR/Function.cpp
===================================================================
--- llvm/lib/IR/Function.cpp
+++ llvm/lib/IR/Function.cpp
@@ -326,6 +326,16 @@
   return Create(Ty, Linkage, M.getDataLayout().getProgramAddressSpace(), N, &M);
 }
 
+Function *Function::createWithDefaultAttr(FunctionType *Ty,
+                                          LinkageTypes Linkage,
+                                          unsigned AddrSpace, const Twine &N,
+                                          Module *M) {
+  auto *F = new Function(Ty, Linkage, AddrSpace, N, M);
+  if (M->getUwtable())
+    F->addAttribute(AttributeList::FunctionIndex, Attribute::UWTable);
+  return F;
+}
+
 void Function::removeFromParent() {
   getParent()->getFunctionList().remove(getIterator());
 }
Index: llvm/include/llvm/IR/Module.h
===================================================================
--- llvm/include/llvm/IR/Module.h
+++ llvm/include/llvm/IR/Module.h
@@ -881,6 +881,10 @@
   /// Set that PLT should be avoid for RTLib calls.
   void setRtLibUseGOT();
 
+  /// Get/set whether synthesized functions should get the uwtable attribute.
+  bool getUwtable() const;
+  void setUwtable();
+
   /// @name Utility functions for querying and setting the build SDK version
   /// @{
 
Index: llvm/include/llvm/IR/Function.h
===================================================================
--- llvm/include/llvm/IR/Function.h
+++ llvm/include/llvm/IR/Function.h
@@ -153,6 +153,11 @@
   static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
                           const Twine &N, Module &M);
 
+  static Function *createWithDefaultAttr(FunctionType *Ty, LinkageTypes Linkage,
+                                         unsigned AddrSpace,
+                                         const Twine &N = "",
+                                         Module *M = nullptr);
+
   // Provide fast operand accessors.
   DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
 
Index: clang/test/CodeGen/asan-no-globals-no-comdat.cpp
===================================================================
--- clang/test/CodeGen/asan-no-globals-no-comdat.cpp
+++ clang/test/CodeGen/asan-no-globals-no-comdat.cpp
@@ -7,5 +7,5 @@
 // RUN: %clang_cc1 -fsanitize=address -fsanitize-address-globals-dead-stripping -fno-integrated-as -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
 // RUN: %clang_cc1 -fsanitize=address -fdata-sections -emit-llvm -o - -triple x86_64-linux %s | FileCheck %s --check-prefix=WITHOUT-GC
 
-// WITH-GC: define internal void @asan.module_ctor() comdat {
-// WITHOUT-GC: define internal void @asan.module_ctor() {
+// WITH-GC: define internal void @asan.module_ctor() #[[#]] comdat {
+// WITHOUT-GC: define internal void @asan.module_ctor() #[[#]] {
Index: clang/test/CodeGen/asan-new-pm.ll
===================================================================
--- clang/test/CodeGen/asan-new-pm.ll
+++ clang/test/CodeGen/asan-new-pm.ll
@@ -12,7 +12,7 @@
 
 ; CHECK: __asan_init
 
-; CHECK-DAG: define internal void @asan.module_ctor() {
+; CHECK-DAG: define internal void @asan.module_ctor() #[[#]] {
 ; CHECK:       {{.*}} call void @__asan_init()
 ; CHECK:       {{.*}} call void @__asan_version_mismatch_check_v8()
 ; CHECK:       ret void
Index: clang/test/CodeGen/asan-globals.cpp
===================================================================
--- clang/test/CodeGen/asan-globals.cpp
+++ clang/test/CodeGen/asan-globals.cpp
@@ -27,7 +27,8 @@
 // ASAN: @__special_global{{.*}} global { i32, [60 x i8] }{{.*}}, align 32
 // KASAN: @__special_global{{.*}} global i32
 
-// CHECK-LABEL: define internal void @asan.module_ctor
+/// Without -fasynchronous-unwind-tables, ctor and dtor get the uwtable attribute.
+// CHECK-LABEL: define internal void @asan.module_ctor() #[[#ATTR:]] {
 // ASAN-NEXT: call void @__asan_init
 // ASAN-NEXT: call void @__asan_version_mismatch_check
 // KASAN-NOT: call void @__asan_init
@@ -36,10 +37,19 @@
 // KASAN-NEXT: call void @__asan_register_globals({{.*}}, i{{32|64}} 5)
 // CHECK-NEXT: ret void
 
-// CHECK-LABEL: define internal void @asan.module_dtor
+// CHECK:      define internal void @asan.module_dtor() #[[#ATTR]] {
 // CHECK-NEXT: call void @__asan_unregister_globals
 // CHECK-NEXT: ret void
 
+// CHECK: attributes #[[#ATTR]] = { nounwind }
+
+/// If -fasynchronous-unwind-tables, set the module flag "uwtable". ctor/dtor
+/// will thus get the uwtable attribute.
+// RUN: %clang_cc1 -emit-llvm -fsanitize=address -munwind-tables -o - %s | FileCheck %s --check-prefixes=UWTABLE
+// UWTABLE: define internal void @asan.module_dtor() #[[#ATTR:]] {
+// UWTABLE: attributes #[[#ATTR]] = { nounwind uwtable }
+// UWTABLE: ![[#]] = !{i32 7, !"uwtable", i32 1}
+
 // CHECK: !llvm.asan.globals = !{![[EXTRA_GLOBAL:[0-9]+]], ![[GLOBAL:[0-9]+]], ![[DYN_INIT_GLOBAL:[0-9]+]], ![[ATTR_GLOBAL:[0-9]+]], ![[BLACKLISTED_GLOBAL:[0-9]+]], ![[SECTIONED_GLOBAL:[0-9]+]], ![[SPECIAL_GLOBAL:[0-9]+]], ![[STATIC_VAR:[0-9]+]], ![[LITERAL:[0-9]+]]}
 // CHECK: ![[EXTRA_GLOBAL]] = !{{{.*}} ![[EXTRA_GLOBAL_LOC:[0-9]+]], !"extra_global", i1 false, i1 false}
 // CHECK: ![[EXTRA_GLOBAL_LOC]] = !{!"{{.*}}extra-source.cpp", i32 1, i32 5}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -741,6 +741,8 @@
 
   if (CodeGenOpts.NoPLT)
     getModule().setRtLibUseGOT();
+  if (CodeGenOpts.UnwindTables)
+    getModule().setUwtable();
 
   SimplifyPersonality();
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to