Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -1677,6 +1677,27 @@ on ELF targets when using the integrated assembler. This flag currently only has an effect on ELF targets. +**-f[no]-unique-internal-linkage-names** + + Controls whether Clang emits a unique (best-effort) symbol name for internal + linkage symbols. When this option is set, compiler hashes the main source + file path from the command line and appends it to all internal symbols. If a + program contains multiple objects compiled with the same command-line source + file path, the symbols are not guaranteed to be unique. This option is + particularly useful in attributing profile information to the correct + function when multiple functions with the same private linkage name exist + in the binary. + + It should be noted that this option cannot guarantee uniqueness and the + following is an example where it is not unique when two modules contain + symbols with the same private linkage name: + + .. code-block:: console + + $ cd $P/foo && clang -c -funique-internal-linkage-names name_conflict.c + $ cd $P/bar && clang -c -funique-internal-linkage-names name_conflict.c + $ cd $P && clang foo/name_conflict.o && bar/name_conflict.o + Profile Guided Optimization --------------------------- Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -161,6 +161,7 @@ CODEGENOPT(NoTrappingMath , 1, 0) ///< Set when -fno-trapping-math is enabled. CODEGENOPT(NoNaNsFPMath , 1, 0) ///< Assume FP arguments, results not NaN. CODEGENOPT(CorrectlyRoundedDivSqrt, 1, 0) ///< -cl-fp32-correctly-rounded-divide-sqrt +CODEGENOPT(UniqueInternalLinkageNames, 1, 0) ///< Internal Linkage symbols get unique names. /// When false, this attempts to generate code as if the result of an /// overflowing conversion matches the overflowing behavior of a target's native Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1985,6 +1985,12 @@ def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">, Group, Flags<[CC1Option]>; +def funique_internal_linkage_names : Flag <["-"], "funique-internal-linkage-names">, + Group, Flags<[CC1Option]>, + HelpText<"Uniqueify Internal Linkage Symbol Names by appending the MD5 hash of the module path">; +def fno_unique_internal_linkage_names : Flag <["-"], "fno-unique-internal-linkage-names">, + Group; + def fstrict_return : Flag<["-"], "fstrict-return">, Group, Flags<[CC1Option]>, HelpText<"Always treat control flow paths that fall off the end of a " Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -28,6 +28,7 @@ #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/XRayLists.h" +#include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -72,7 +73,6 @@ class LangOptions; class CodeGenOptions; class HeaderSearchOptions; -class PreprocessorOptions; class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; @@ -307,6 +307,7 @@ const TargetInfo &Target; std::unique_ptr ABI; llvm::LLVMContext &VMContext; + std::string ModuleNameHash = ""; std::unique_ptr TBAA; @@ -578,6 +579,8 @@ /// Return true iff an Objective-C runtime has been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } + const std::string &getModuleNameHash() const { return ModuleNameHash; } + /// Return a reference to the configured OpenCL runtime. CGOpenCLRuntime &getOpenCLRuntime() { assert(OpenCLRuntime != nullptr); Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -176,6 +176,25 @@ // CoverageMappingModuleGen object. if (CodeGenOpts.CoverageMapping) CoverageMapping.reset(new CoverageMappingModuleGen(*this, *CoverageInfo)); + + // Generate the module name hash here if needed. + if (CodeGenOpts.UniqueInternalLinkageNames && + !getModule().getSourceFileName().empty()) { + std::string Path = getModule().getSourceFileName(); + // Check if a path substitution is needed from the MacroPrefixMap. + for (const auto &Entry : PPO.MacroPrefixMap) + if (Path.rfind(Entry.first, 0) != std::string::npos) { + Path = Entry.second + Path.substr(Entry.first.size()); + break; + } + llvm::MD5 Md5; + Md5.update(Path); + llvm::MD5::MD5Result R; + Md5.final(R); + SmallString<32> Str; + llvm::MD5::stringifyResult(R, Str); + ModuleNameHash = ("." + Str).str(); + } } CodeGenModule::~CodeGenModule() {} @@ -1046,7 +1065,7 @@ } } -static std::string getMangledNameImpl(const CodeGenModule &CGM, GlobalDecl GD, +static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, const NamedDecl *ND, bool OmitMultiVersionMangling = false) { SmallString<256> Buffer; @@ -1070,6 +1089,19 @@ } } + // Check if the module name hash should be appended for internal linkage + // symbols. + const Decl *D = GD.getDecl(); + if (!CGM.getModuleNameHash().empty() && + ((isa(D) && + CGM.getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage) || + (isa(D) && CGM.getContext().GetGVALinkageForVariable( + cast(D)) == GVA_Internal))) { + assert(CGM.getCodeGenOpts().UniqueInternalLinkageNames && + "Hash computed when not explicitly requested"); + Out << CGM.getModuleNameHash(); + } + if (const auto *FD = dyn_cast(ND)) if (FD->isMultiVersion() && !OmitMultiVersionMangling) { switch (FD->getMultiVersionKind()) { Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4254,6 +4254,8 @@ options::OPT_fno_function_sections, options::OPT_fdata_sections, options::OPT_fno_data_sections, + options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names, options::OPT_funique_section_names, options::OPT_fno_unique_section_names, options::OPT_mrestrict_it, @@ -4861,6 +4863,10 @@ options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); + if (Args.hasFlag(options::OPT_funique_internal_linkage_names, + options::OPT_fno_unique_internal_linkage_names, false)) + CmdArgs.push_back("-funique-internal-linkage-names"); + Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_function_entry_bare); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -958,6 +958,8 @@ Opts.DataSections = Args.hasArg(OPT_fdata_sections); Opts.StackSizeSection = Args.hasArg(OPT_fstack_size_section); Opts.UniqueSectionNames = !Args.hasArg(OPT_fno_unique_section_names); + Opts.UniqueInternalLinkageNames = + Args.hasArg(OPT_funique_internal_linkage_names); Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); Index: clang/test/CodeGen/unique-internal-linkage-names.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/unique-internal-linkage-names.cpp @@ -0,0 +1,68 @@ +// This test checks if internal linkage symbols get unique names with +// -funique-internal-linkage-names option. +// RUN: %clang_cc1 -triple x86_64 -x c++ -S -emit-llvm -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64 -x c++ -S -emit-llvm -funique-internal-linkage-names -o - < %s | FileCheck %s --check-prefix=UNIQUE + +static int glob; +static int foo() { + return 0; +} + +int (*bar())() { + return foo; +} + +int getGlob() { + return glob; +} + +// Function local static variable and anonymous namespace namespace variable. +namespace { +int anon_m; +int getM() { + return anon_m; +} +} // namespace + +int retAnonM() { + static int fGlob; + return getM() + fGlob; +} + +// Multiversioning symbols +__attribute__((target("default"))) static int mver() { + return 0; +} + +__attribute__((target("sse4.2"))) static int mver() { + return 1; +} + +int mver_call() { + return mver(); +} + +// PLAIN: @_ZL4glob = internal global +// PLAIN: @_ZL3foov() +// PLAIN: @_ZN12_GLOBAL__N_14getMEv +// PLAIN: @_ZZ8retAnonMvE5fGlob +// PLAIN: @_ZN12_GLOBAL__N_16anon_mE +// PLAIN: @_ZL4mverv.resolver() +// PLAIN: @_ZL4mverv() +// PLAIN: @_ZL4mverv.sse4.2() +// UNIQUE-NOT: @_ZL4glob = internal global +// UNIQUE-NOT: @_ZL3foov() +// UNIQUE-NOT: @_ZN12_GLOBAL__N_14getMEv +// UNIQUE-NOT: @_ZZ8retAnonMvE5fGlob +// UNIQUE-NOT: @_ZN12_GLOBAL__N_16anon_mE +// UNIQUE-NOT: @_ZL4mverv.resolver() +// UNIQUE-NOT: @_ZL4mverv() +// UNIQUE-NOT: @_ZL4mverv.sse4.2() +// UNIQUE: @_ZL4glob.{{[0-9a-f]+}} = internal global +// UNIQUE: @_ZL3foov.{{[0-9a-f]+}}() +// UNIQUE: @_ZN12_GLOBAL__N_14getMEv.{{[0-9a-f]+}} +// UNIQUE: @_ZZ8retAnonMvE5fGlob.{{[0-9a-f]+}} +// UNIQUE: @_ZN12_GLOBAL__N_16anon_mE.{{[0-9a-f]+}} +// UNIQUE: @_ZL4mverv.{{[0-9a-f]+}}.resolver() +// UNIQUE: @_ZL4mverv.{{[0-9a-f]+}}() +// UNIQUE: @_ZL4mverv.{{[0-9a-f]+}}.sse4.2() Index: clang/test/CodeGen/unique-internal-linkage-names2.c =================================================================== --- /dev/null +++ clang/test/CodeGen/unique-internal-linkage-names2.c @@ -0,0 +1,15 @@ +// This test checks if -funique-internal-linkage-names uses the right +// path when -ffile-prefix-map= (-fmacro-prefix-map=) is enabled. +// With -fmacro-prefix-map=%p=NEW, this file must be referenced as: +// NEW/unique-internal-linkage-names2.c +// MD5 hash of "NEW/unique-internal-linkage-names2.c" : +// $ echo -n NEW/unique-internal-linkage-names2.c | md5sum +// bd816b262f03c98ffb082cde0847804c +// RUN: %clang_cc1 -triple x86_64 -funique-internal-linkage-names -fmacro-prefix-map=%p=NEW -x c -S -emit-llvm -o - %s | FileCheck %s +static int glob; + +int getGlob() { + return glob; +} + +// CHECK: glob.bd816b262f03c98ffb082cde0847804c = internal global Index: clang/test/Driver/funique-internal-linkage-names.c =================================================================== --- /dev/null +++ clang/test/Driver/funique-internal-linkage-names.c @@ -0,0 +1,4 @@ +// RUN: %clang -### -funique-internal-linkage-names %s -c 2>&1 | FileCheck -check-prefix=CHECK-OPT %s +// RUN: %clang -### -funique-internal-linkage-names -fno-unique-internal-linkage-names %s -c 2>&1 | FileCheck -check-prefix=CHECK-NOOPT %s +// CHECK-OPT: "-funique-internal-linkage-names" +// CHECK-NOOPT-NOT: "-funique-internal-linkage-names"