diff --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp --- a/llvm/lib/IR/Mangler.cpp +++ b/llvm/lib/IR/Mangler.cpp @@ -184,6 +184,26 @@ getNameWithPrefix(OS, GV, CannotUsePrivateLabel); } +// Check if the name needs quotes to be safe for the linker to interpret. +static bool canBeUnquotedInDirective(char C) { + return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || + (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' || C == '@'; +} + +static bool canBeUnquotedInDirective(StringRef Name) { + if (Name.empty()) + return false; + + // If any of the characters in the string is an unacceptable character, force + // quotes. + for (char C : Name) { + if (!canBeUnquotedInDirective(C)) + return false; + } + + return true; +} + void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV, const Triple &TT, Mangler &Mangler) { if (!GV->hasDLLExportStorageClass() || GV->isDeclaration()) @@ -194,6 +214,9 @@ else OS << " -export:"; + bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName()); + if (NeedQuotes) + OS << "\""; if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) { std::string Flag; raw_string_ostream FlagOS(Flag); @@ -206,6 +229,8 @@ } else { Mangler.getNameWithPrefix(OS, GV, false); } + if (NeedQuotes) + OS << "\""; if (!GV->getValueType()->isFunctionTy()) { if (TT.isWindowsMSVCEnvironment()) @@ -221,6 +246,11 @@ return; OS << " /INCLUDE:"; + bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName()); + if (NeedQuotes) + OS << "\""; M.getNameWithPrefix(OS, GV, false); + if (NeedQuotes) + OS << "\""; } diff --git a/llvm/test/CodeGen/X86/dllexport.ll b/llvm/test/CodeGen/X86/dllexport.ll --- a/llvm/test/CodeGen/X86/dllexport.ll +++ b/llvm/test/CodeGen/X86/dllexport.ll @@ -81,6 +81,9 @@ ; CHECK: .weak _WeakVar2 @WeakVar2 = weak_odr dllexport unnamed_addr constant i32 1 +; CHECK: .globl "_complex-name" +@"complex-name" = dllexport global i32 1, align 4 + ; Verify items that should not be exported do not appear in the export table. ; We use a separate check prefix to avoid confusion between -NOT and -SAME. @@ -102,6 +105,7 @@ ; CHECK-CL: .ascii " /EXPORT:_Var3,DATA" ; CHECK-CL: .ascii " /EXPORT:_WeakVar1,DATA" ; CHECK-CL: .ascii " /EXPORT:_WeakVar2,DATA" +; CHECK-CL: .ascii " /EXPORT:\"_complex-name\",DATA" ; CHECK-CL: .ascii " /EXPORT:_alias" ; CHECK-CL: .ascii " /EXPORT:_alias2" ; CHECK-CL: .ascii " /EXPORT:_alias3" @@ -119,6 +123,7 @@ ; CHECK-GCC: .ascii " -export:Var3,data" ; CHECK-GCC: .ascii " -export:WeakVar1,data" ; CHECK-GCC: .ascii " -export:WeakVar2,data" +; CHECK-GCC: .ascii " -export:\"complex-name\",data" ; CHECK-GCC: .ascii " -export:alias" ; CHECK-GCC: .ascii " -export:alias2" ; CHECK-GCC: .ascii " -export:alias3"