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