[clang] 828767f - COFF/ELF: Place llvm.global_ctors elements in llvm.used if comdat is used

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 28 11:44:24 PDT 2021


Author: Fangrui Song
Date: 2021-07-28T11:44:19-07:00
New Revision: 828767f325b5dd0356c5fd90e40a1c047010853e

URL: https://github.com/llvm/llvm-project/commit/828767f325b5dd0356c5fd90e40a1c047010853e
DIFF: https://github.com/llvm/llvm-project/commit/828767f325b5dd0356c5fd90e40a1c047010853e.diff

LOG: COFF/ELF: Place llvm.global_ctors elements in llvm.used if comdat is used

On ELF, an SHT_INIT_ARRAY outside a section group is a GC root. The current
codegen abuses SHT_INIT_ARRAY in a section group to mean a GC root.

On PE/COFF, the dynamic initialization for `__declspec(selectany)` in a comdat
can be garbage collected by `-opt:ref`.

Call `addUsedGlobal` for the two cases to fix the abuse/bug.

Reviewed By: rnk

Differential Revision: https://reviews.llvm.org/D106925

Added: 
    

Modified: 
    clang/lib/CodeGen/CGDeclCXX.cpp
    clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp
    clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index d43fb99550a85..553fedebfe56b 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -555,7 +555,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
                                           PrioritizedCXXGlobalInits.size());
     PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
   } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) ||
-             getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR) {
+             getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR ||
+             D->hasAttr<SelectAnyAttr>()) {
     // C++ [basic.start.init]p2:
     //   Definitions of explicitly specialized class template static data
     //   members have ordered initialization. Other class template static data
@@ -568,17 +569,18 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
     // group with the global being initialized.  On most platforms, this is a
     // minor startup time optimization.  In the MS C++ ABI, there are no guard
     // variables, so this COMDAT key is required for correctness.
-    AddGlobalCtor(Fn, 65535, COMDATKey);
-    if (getTarget().getCXXABI().isMicrosoft() && COMDATKey) {
-      // In The MS C++, MS add template static data member in the linker
-      // drective.
-      addUsedGlobal(COMDATKey);
-    }
-  } else if (D->hasAttr<SelectAnyAttr>()) {
+    //
     // SelectAny globals will be comdat-folded. Put the initializer into a
     // COMDAT group associated with the global, so the initializers get folded
     // too.
+
     AddGlobalCtor(Fn, 65535, COMDATKey);
+    if (COMDATKey && (getTriple().isOSBinFormatELF() ||
+                      getTarget().getCXXABI().isMicrosoft())) {
+      // When COMDAT is used on ELF or in the MS C++ ABI, the key must be in
+      // llvm.used to prevent linker GC.
+      addUsedGlobal(COMDATKey);
+    }
   } else {
     I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash.
     if (I == DelayedCXXInitPosition.end()) {

diff  --git a/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp b/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp
index 3b419c18c0e23..d8d0ed3950803 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-template-static-init.cpp
@@ -88,5 +88,4 @@ int foo();
 inline int zoo = foo();
 inline static int boo = foo();
 
-
-// CHECK: @llvm.used = appending global [7 x i8*] [i8* bitcast (i32* @"?x1 at selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x@?$A at H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_ at H@@2HA" to i8*), i8* getelementptr inbounds (%struct.A, %struct.A* @"?aoo at S1@@2UA@@A", i32 0, i32 0), i8* bitcast (i32* @"?zoo@@3HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate at H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A at H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata"
+// CHECK: @llvm.used = appending global [8 x i8*] [i8* bitcast (i32* @"?x at selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x1 at selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x@?$A at H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_ at H@@2HA" to i8*), i8* getelementptr inbounds (%struct.A, %struct.A* @"?aoo at S1@@2UA@@A", i32 0, i32 0), i8* bitcast (i32* @"?zoo@@3HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate at H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A at H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata"

diff  --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
index 2bd01b301e522..13323e7efe79c 100644
--- a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
+++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
@@ -1,5 +1,20 @@
 // RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-pc-linux -emit-llvm -o - | FileCheck --check-prefix=ELF --check-prefix=ALL %s
 // RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-apple-darwin -emit-llvm -o - | FileCheck --check-prefix=MACHO --check-prefix=ALL %s
+// RUN: %clang_cc1 %s -std=c++1y -triple=x86_64-pc-linux -emit-llvm -fdeclspec -DSELECTANY -o - | FileCheck --check-prefix=ELF-SELECTANY %s
+
+#ifdef SELECTANY
+struct S {
+  S();
+  ~S();
+};
+
+int f();
+
+// ELF-SELECTANY: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init, i8* bitcast (i32* @selectany to i8*) }]
+// ELF-SELECTANY: @llvm.used = appending global [1 x i8*] [i8* bitcast (i32* @selectany to i8*)]
+int __declspec(selectany) selectany = f();
+
+#else
 
 // ALL: ; ModuleID
 
@@ -38,6 +53,9 @@ template<> int A<bool>::a = 10;
 
 // ALL:  { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }]
 
+/// llvm.used ensures SHT_INIT_ARRAY in a section group cannot be GCed.
+// ELF: @llvm.used = appending global [6 x i8*] [i8* bitcast (i32* @_ZN1AIsE1aE to i8*), i8* bitcast (i16* @_Z1xIsE to i8*), i8* bitcast (i32* @_ZN2ns1aIiE1iE to i8*), i8* bitcast (i32* @_ZN2ns1b1iIiEE to i8*), i8* bitcast (i32* @_ZN1AIvE1aE to i8*), i8* @_Z1xIcE]
+
 template int A<short>::a;  // Unordered
 int b = foo();
 int c = foo();
@@ -76,6 +94,8 @@ template<typename T> int Internal<T>::a = foo();
 }
 int *use_internal_a = &Internal<int>::a;
 
+#endif
+
 // ALL: define internal void @[[unordered1]](
 // ALL: call i32 @foo()
 // ALL: store {{.*}} @_ZN1AIsE1aE


        


More information about the cfe-commits mailing list