[llvm] c5b3de6 - [COFF] Emit embedded -exclude-symbols: directives for hidden visibility for MinGW

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 11 02:01:39 PDT 2022


Author: Martin Storsjö
Date: 2022-08-11T12:00:08+03:00
New Revision: c5b3de6745c37dd991430b9b88ff97c35b6fc455

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

LOG: [COFF] Emit embedded -exclude-symbols: directives for hidden visibility for MinGW

This works with the automatic export of all symbols; in MinGW mode,
when a DLL has no explicit dllexports, it exports all symbols (except
for some that are hardcoded to be excluded, including some toolchain
libraries).

By hooking up the hidden visibility to the -exclude-symbols: directive,
the automatic export of all symbols can be controlled in an easier
way (with a mechanism that doesn't require strict annotation of every
single symbol, but which allows gradually marking more unnecessary
symbols as hidden).

The primary use case is dylib builds of LLVM/Clang. These can be done
in MinGW mode but not in MSVC mode, as MinGW builds can export all
symbols (and the calling code can use APIs without corresponding
dllimport directives). However, as all symbols are exported, it can
easily overflow the max number of exported symbols in a DLL (65536).

In the llvm-mingw distribution, only the X86, ARM and AArch64 backends
are enabled; for the LLVM 13.0.0 release, libLLVM-13.dll ended up with
58112 exported symbols. For LLVM 14.0.0, it was 62015 symbols. Current
builds of the 15.x branch end up at around 64650 symbols - i.e. extremely
close to the limit.

The msys2 packages of LLVM have had to progressively disable more
of their backends in their builds, to be able to keep building with a
dylib.

This allows improving the current mingw dylib situation significantly,
by using the same hidden visibility options and attributes as on Unix.
With those in place, a current build of LLVM git main ends up at 35142
symbols instead of 64650.

For code using hidden visibility, this now requires linking with either
a current git lld or ld.bfd. (Older lld error out on the unknown
directives, older ld.bfd will successfully link, but will print huge
amounts of warnings.)

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

Added: 
    llvm/test/CodeGen/X86/mingw-hidden.ll

Modified: 
    llvm/docs/ReleaseNotes.rst
    llvm/lib/IR/Mangler.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index dc952ee54a625..b107b590aaab7 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -108,6 +108,14 @@ Changes to the WebAssembly Backend
 
 * ...
 
+Changes to the Windows Target
+-----------------------------
+
+* For MinGW, generate embedded ``-exclude-symbols:`` directives for symbols
+  with hidden visibility, omitting them from automatic export of all symbols.
+  This roughly makes hidden visibility work like it does for other object
+  file formats.
+
 Changes to the X86 Backend
 --------------------------
 

diff  --git a/llvm/lib/IR/Mangler.cpp b/llvm/lib/IR/Mangler.cpp
index b8e3e40e4c1d5..9011f5db6a404 100644
--- a/llvm/lib/IR/Mangler.cpp
+++ b/llvm/lib/IR/Mangler.cpp
@@ -210,18 +210,46 @@ static bool canBeUnquotedInDirective(StringRef Name) {
 
 void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV,
                                         const Triple &TT, Mangler &Mangler) {
-  if (!GV->hasDLLExportStorageClass() || GV->isDeclaration())
-    return;
+  if (GV->hasDLLExportStorageClass() && !GV->isDeclaration()) {
 
-  if (TT.isWindowsMSVCEnvironment())
-    OS << " /EXPORT:";
-  else
-    OS << " -export:";
+    if (TT.isWindowsMSVCEnvironment())
+      OS << " /EXPORT:";
+    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);
+      Mangler.getNameWithPrefix(FlagOS, GV, false);
+      FlagOS.flush();
+      if (Flag[0] == GV->getParent()->getDataLayout().getGlobalPrefix())
+        OS << Flag.substr(1);
+      else
+        OS << Flag;
+    } else {
+      Mangler.getNameWithPrefix(OS, GV, false);
+    }
+    if (NeedQuotes)
+      OS << "\"";
+
+    if (!GV->getValueType()->isFunctionTy()) {
+      if (TT.isWindowsMSVCEnvironment())
+        OS << ",DATA";
+      else
+        OS << ",data";
+    }
+  }
+  if (GV->hasHiddenVisibility() && !GV->isDeclaration() && TT.isOSCygMing()) {
+
+    OS << " -exclude-symbols:";
+
+    bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName());
+    if (NeedQuotes)
+      OS << "\"";
 
-  bool NeedQuotes = GV->hasName() && !canBeUnquotedInDirective(GV->getName());
-  if (NeedQuotes)
-    OS << "\"";
-  if (TT.isWindowsGNUEnvironment() || TT.isWindowsCygwinEnvironment()) {
     std::string Flag;
     raw_string_ostream FlagOS(Flag);
     Mangler.getNameWithPrefix(FlagOS, GV, false);
@@ -230,17 +258,9 @@ void llvm::emitLinkerFlagsForGlobalCOFF(raw_ostream &OS, const GlobalValue *GV,
       OS << Flag.substr(1);
     else
       OS << Flag;
-  } else {
-    Mangler.getNameWithPrefix(OS, GV, false);
-  }
-  if (NeedQuotes)
-    OS << "\"";
 
-  if (!GV->getValueType()->isFunctionTy()) {
-    if (TT.isWindowsMSVCEnvironment())
-      OS << ",DATA";
-    else
-      OS << ",data";
+    if (NeedQuotes)
+      OS << "\"";
   }
 }
 

diff  --git a/llvm/test/CodeGen/X86/mingw-hidden.ll b/llvm/test/CodeGen/X86/mingw-hidden.ll
new file mode 100644
index 0000000000000..8958458c55b6e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/mingw-hidden.ll
@@ -0,0 +1,81 @@
+; RUN: llc -mtriple i386-pc-win32 < %s \
+; RUN:    | FileCheck --check-prefixes=CHECK,CHECK-MSVC %s
+; RUN: llc -mtriple i386-pc-mingw32 < %s \
+; RUN:    | FileCheck --check-prefixes=CHECK,CHECK-MINGW %s
+; RUN: llc -mtriple i386-pc-mingw32 < %s \
+; RUN:    | FileCheck --check-prefix=NOTEXPORTED %s
+
+; CHECK: .text
+
+; CHECK: .globl _notHidden
+define void @notHidden() {
+	ret void
+}
+
+; CHECK: .globl _f1
+define hidden void @f1() {
+	ret void
+}
+
+; CHECK: .globl _f2
+define hidden void @f2() unnamed_addr {
+	ret void
+}
+
+declare hidden void @notDefined()
+
+; CHECK: .globl _stdfun at 0
+define hidden x86_stdcallcc void @stdfun() nounwind {
+	ret void
+}
+
+; CHECK: .globl _lnk1
+$lnk1 = comdat any
+
+define linkonce_odr hidden void @lnk1() comdat {
+	ret void
+}
+
+; CHECK: .globl _lnk2
+$lnk2 = comdat any
+
+define linkonce_odr hidden void @lnk2() alwaysinline comdat {
+	ret void
+}
+
+; CHECK: .data
+; CHECK: .globl _Var1
+ at Var1 = hidden global i32 1, align 4
+
+; CHECK: .rdata,"dr"
+; CHECK: .globl _Var2
+ at Var2 = hidden unnamed_addr constant i32 1
+
+; CHECK: .comm _Var3
+ at Var3 = common hidden global i32 0, align 4
+
+; CHECK: .globl "_complex-name"
+@"complex-name" = hidden global i32 1, align 4
+
+; CHECK: .globl _complex.name
+@"complex.name" = hidden global i32 1, align 4
+
+
+; Verify items that should not be marked hidden do not appear in the directives.
+; We use a separate check prefix to avoid confusion between -NOT and -SAME.
+; NOTEXPORTED: .section .drectve
+; NOTEXPORTED-NOT: :notHidden
+; NOTEXPORTED-NOT: :notDefined
+
+; CHECK-MSVC-NOT: .section .drectve
+; CHECK-MINGW: .section .drectve
+; CHECK-MINGW: .ascii " -exclude-symbols:f1"
+; CHECK-MINGW: .ascii " -exclude-symbols:f2"
+; CHECK-MINGW: .ascii " -exclude-symbols:stdfun at 0"
+; CHECK-MINGW: .ascii " -exclude-symbols:lnk1"
+; CHECK-MINGW: .ascii " -exclude-symbols:lnk2"
+; CHECK-MINGW: .ascii " -exclude-symbols:Var1"
+; CHECK-MINGW: .ascii " -exclude-symbols:Var2"
+; CHECK-MINGW: .ascii " -exclude-symbols:Var3"
+; CHECK-MINGW: .ascii " -exclude-symbols:\"complex-name\""
+; CHECK-MINGW: .ascii " -exclude-symbols:\"complex.name\""


        


More information about the llvm-commits mailing list