samitolvanen created this revision.
Herald added subscribers: ormris, jeroen.dobbelaere, dexonsmith, dang, 
steven_wu, hiraditya.
samitolvanen requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Inline assembly refererences to static functions with ThinLTO+CFI were
fixed in D104058 <https://reviews.llvm.org/D104058> by creating aliases for 
promoted functions. Creating
the aliases unconditionally resulted in an unexpected size increase in
a Chrome helper binary:

https://bugs.chromium.org/p/chromium/issues/detail?id=1261715

As promotion aliases are only required for very specific use cases,
such as compiling the Linux kernel with CFI, add a command line flag
to allow users to create these aliases only when needed.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112761

Files:
  clang/docs/ClangCommandLineReference.rst
  clang/docs/ControlFlowIntegrity.rst
  clang/docs/UsersManual.rst
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/SanitizerArgs.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/SanitizerArgs.cpp
  clang/test/CodeGen/cfi-promotion-aliases.c
  clang/test/Driver/fsanitize.c
  llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
  llvm/test/ThinLTO/X86/devirt2.ll
  llvm/test/Transforms/ThinLTOBitcodeWriter/cfi-icall-static-inline-asm.ll

Index: llvm/test/Transforms/ThinLTOBitcodeWriter/cfi-icall-static-inline-asm.ll
===================================================================
--- llvm/test/Transforms/ThinLTOBitcodeWriter/cfi-icall-static-inline-asm.ll
+++ llvm/test/Transforms/ThinLTOBitcodeWriter/cfi-icall-static-inline-asm.ll
@@ -19,4 +19,7 @@
   ret void
 }
 
+!llvm.module.flags = !{!1}
+
 !0 = !{i64 0, !"typeid1"}
+!1 = !{i32 4, !"CFI Promotion Aliases", i32 1}
Index: llvm/test/ThinLTO/X86/devirt2.ll
===================================================================
--- llvm/test/ThinLTO/X86/devirt2.ll
+++ llvm/test/ThinLTO/X86/devirt2.ll
@@ -131,12 +131,10 @@
 ; RUN:   -r=%t1.o,_ZN1D1mEi, \
 ; RUN:   -r=%t1.o,test2, \
 ; RUN:   -r=%t2.o,_ZN1A1nEi,p \
-; RUN:   -r=%t2.o,_ZN1A1nEi, \
 ; RUN:   -r=%t2.o,_ZN1B1fEi,p \
 ; RUN:   -r=%t2.o,_ZN1C1fEi,p \
 ; RUN:   -r=%t2.o,_ZN1D1mEi,p \
 ; RUN:   -r=%t2.o,_ZN1E1mEi,p \
-; RUN:   -r=%t2.o,_ZN1E1mEi, \
 ; RUN:   -r=%t2.o,_ZTV1B, \
 ; RUN:   -r=%t2.o,_ZTV1C, \
 ; RUN:   -r=%t2.o,_ZTV1D, \
@@ -169,12 +167,10 @@
 ; RUN:   -r=%t1.o,_ZN1D1mEi, \
 ; RUN:   -r=%t1.o,test2, \
 ; RUN:   -r=%t2.o,_ZN1A1nEi,p \
-; RUN:   -r=%t2.o,_ZN1A1nEi, \
 ; RUN:   -r=%t2.o,_ZN1B1fEi,p \
 ; RUN:   -r=%t2.o,_ZN1C1fEi,p \
 ; RUN:   -r=%t2.o,_ZN1D1mEi,p \
 ; RUN:   -r=%t2.o,_ZN1E1mEi,p \
-; RUN:   -r=%t2.o,_ZN1E1mEi, \
 ; RUN:   -r=%t2.o,_ZTV1B, \
 ; RUN:   -r=%t2.o,_ZTV1C, \
 ; RUN:   -r=%t2.o,_ZTV1D, \
Index: llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
===================================================================
--- llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
+++ llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
@@ -33,6 +33,13 @@
 
 namespace {
 
+// Determine if promotion aliases should be created for a module.
+static bool createPromotionAliases(Module &M) {
+  auto *CI = mdconst::extract_or_null<ConstantInt>(
+      M.getModuleFlag("CFI Promotion Aliases"));
+  return (CI && CI->getZExtValue() != 0);
+}
+
 // Determine if a promotion alias should be created for a symbol name.
 static bool allowPromotionAlias(const std::string &Name) {
   // Promotion aliases are used only in inline assembly. It's safe to
@@ -51,6 +58,8 @@
 void promoteInternals(Module &ExportM, Module &ImportM, StringRef ModuleId,
                       SetVector<GlobalValue *> &PromoteExtra) {
   DenseMap<const Comdat *, Comdat *> RenamedComdats;
+  bool CreateAliases = createPromotionAliases(ExportM);
+
   for (auto &ExportGV : ExportM.global_values()) {
     if (!ExportGV.hasLocalLinkage())
       continue;
@@ -84,7 +93,8 @@
       ImportGV->setVisibility(GlobalValue::HiddenVisibility);
     }
 
-    if (isa<Function>(&ExportGV) && allowPromotionAlias(OldName)) {
+    if (CreateAliases && isa<Function>(&ExportGV) &&
+        allowPromotionAlias(OldName)) {
       // Create a local alias with the original name to avoid breaking
       // references from inline assembly.
       std::string Alias = ".set " + OldName + "," + NewName + "\n";
Index: clang/test/Driver/fsanitize.c
===================================================================
--- clang/test/Driver/fsanitize.c
+++ clang/test/Driver/fsanitize.c
@@ -654,6 +654,11 @@
 // CHECK-CFI-GENERALIZE-POINTERS: -fsanitize-cfi-icall-generalize-pointers
 // CHECK-NO-CFI-GENERALIZE-POINTERS-NOT: -fsanitize-cfi-icall-generalize-pointers
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-promotion-aliases -fvisibility=hidden -flto=thin -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-PROMOTION-ALIASES
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fvisibility=hidden -flto=thin -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CFI-PROMOTION-ALIASES
+// CHECK-CFI-PROMOTION-ALIASES: -fsanitize-cfi-promotion-aliases
+// CHECK-NO-CFI-PROMOTION-ALIASES-NOT: -fsanitize-cfi-promotion-aliases
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fsanitize-cfi-cross-dso -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-AND-CROSS-DSO
 // CHECK-CFI-GENERALIZE-AND-CROSS-DSO: error: invalid argument '-fsanitize-cfi-cross-dso' not allowed with '-fsanitize-cfi-icall-generalize-pointers'
 
Index: clang/test/CodeGen/cfi-promotion-aliases.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/cfi-promotion-aliases.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefixes=NOALIASES %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-cfi-promotion-aliases -emit-llvm -o - %s | FileCheck --check-prefixes=ALIASES %s
+
+void a(void) {}
+
+// NOALIASES: !{i32 4, !"CFI Promotion Aliases", i32 0}
+// ALIASES: !{i32 4, !"CFI Promotion Aliases", i32 1}
Index: clang/lib/Driver/SanitizerArgs.cpp
===================================================================
--- clang/lib/Driver/SanitizerArgs.cpp
+++ clang/lib/Driver/SanitizerArgs.cpp
@@ -651,6 +651,9 @@
     CfiCanonicalJumpTables =
         Args.hasFlag(options::OPT_fsanitize_cfi_canonical_jump_tables,
                      options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
+
+    CfiPromotionAliases =
+        Args.hasArg(options::OPT_fsanitize_cfi_promotion_aliases);
   }
 
   Stats = Args.hasFlag(options::OPT_fsanitize_stats,
@@ -1089,6 +1092,9 @@
   if (CfiICallGeneralizePointers)
     CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
 
+  if (CfiPromotionAliases)
+    CmdArgs.push_back("-fsanitize-cfi-promotion-aliases");
+
   if (CfiCanonicalJumpTables)
     CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -672,6 +672,9 @@
     getModule().addModuleFlag(llvm::Module::Override,
                               "CFI Canonical Jump Tables",
                               CodeGenOpts.SanitizeCfiCanonicalJumpTables);
+    getModule().addModuleFlag(llvm::Module::Override,
+                              "CFI Promotion Aliases",
+                              CodeGenOpts.SanitizeCfiPromotionAliases);
   }
 
   if (CodeGenOpts.CFProtectionReturn &&
Index: clang/include/clang/Driver/SanitizerArgs.h
===================================================================
--- clang/include/clang/Driver/SanitizerArgs.h
+++ clang/include/clang/Driver/SanitizerArgs.h
@@ -36,6 +36,7 @@
   bool CfiCrossDso = false;
   bool CfiICallGeneralizePointers = false;
   bool CfiCanonicalJumpTables = false;
+  bool CfiPromotionAliases = false;
   int AsanFieldPadding = 0;
   bool SharedRuntime = false;
   bool AsanUseAfterScope = true;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1714,6 +1714,10 @@
                                               Group<f_clang_Group>,
                                               HelpText<"Generalize pointers in CFI indirect call type signature checks">,
                                               MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallGeneralizePointers">>;
+def fsanitize_cfi_promotion_aliases : Flag<["-"], "fsanitize-cfi-promotion-aliases">,
+                                      Group<f_clang_Group>,
+                                      HelpText<"Generate aliases for promoted static functions for inline assembly">,
+                                      MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiPromotionAliases">>;
 defm sanitize_cfi_canonical_jump_tables : BoolOption<"f", "sanitize-cfi-canonical-jump-tables",
   CodeGenOpts<"SanitizeCfiCanonicalJumpTables">, DefaultFalse,
   PosFlag<SetTrue, [], "Make">, NegFlag<SetFalse, [CoreOption, NoXarchOption], "Do not make">,
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -236,6 +236,8 @@
                                          ///< diagnostics.
 CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
                                                      ///< CFI icall function signatures
+CODEGENOPT(SanitizeCfiPromotionAliases, 1, 0) ///< Create aliases for promoted local functions
+                                              ///< for inline assembly
 CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
                                                  ///< instead of creating a local jump table.
 CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -1689,6 +1689,12 @@
    checked by Control Flow Integrity indirect call checking. See
    :doc:`ControlFlowIntegrity` for more details.
 
+.. option:: -fsanitize-cfi-promotion-aliases
+
+   Create aliases with the original name for local functions that are renamed
+   when they are promoted to global visibility, so they can be referenced from
+   inline assembly.
+
 .. option:: -fstrict-vtable-pointers
 
    Enable optimizations based on the strict rules for overwriting polymorphic
Index: clang/docs/ControlFlowIntegrity.rst
===================================================================
--- clang/docs/ControlFlowIntegrity.rst
+++ clang/docs/ControlFlowIntegrity.rst
@@ -285,6 +285,15 @@
 the jump table entry of a specific function canonical so that the external
 code will end up taking an address for the function that will pass CFI checks.
 
+``-fsanitize-cfi-promotion-aliases``
+--------------------------------------------
+
+With ``-flto=thin`` and CFI, static functions are renamed when they are promoted
+to global visibility, which breaks references to them from inline assembly. With
+``-fsanitize-cfi-promotion-aliases`` the compiler creates local aliases with the
+original name to allow static functions to be referenced from inline assembly.
+
+
 ``-fsanitize=cfi-icall`` and ``-fsanitize=function``
 ----------------------------------------------------
 
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -929,6 +929,10 @@
 
 Generalize pointers in CFI indirect call type signature checks
 
+.. option:: -fsanitize-cfi-promotion-aliases
+
+Create aliases for promoted static functions to allow them to be referenced from inline assembly
+
 .. option:: -fsanitize-coverage-allowlist=<arg>, -fsanitize-coverage-whitelist=<arg>
 
 Restrict sanitizer coverage instrumentation exclusively to modules and functions that match the provided special case list, except the blocked ones
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D112761: cfi-i... Sami Tolvanen via Phabricator via cfe-commits

Reply via email to