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@selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.A, %struct.A* @"?aoo@S1@@2UA@@A", i32 0, i32 0), i8* bitcast (i32* @"?zoo@@3HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A@H@implicit_template_instantiation@@2HA" to i8*)], section "llvm.metadata" +// CHECK: @llvm.used = appending global [8 x i8*] [i8* bitcast (i32* @"?x@selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x1@selectany_init@@3HA" to i8*), i8* bitcast (i32* @"?x@?$A@H@explicit_template_instantiation@@2HA" to i8*), i8* bitcast (i32* @"?ioo@?$X_@H@@2HA" to i8*), i8* getelementptr inbounds (%struct.A, %struct.A* @"?aoo@S1@@2UA@@A", i32 0, i32 0), i8* bitcast (i32* @"?zoo@@3HA" to i8*), i8* getelementptr inbounds (%struct.S, %struct.S* @"?s@?$ExportedTemplate@H@@2US@@A", i32 0, i32 0), i8* bitcast (i32* @"?x@?$A@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits