https://github.com/aganea created 
https://github.com/llvm/llvm-project/pull/146699

This is a workaround for
https://github.com/llvm/llvm-project/issues/82050 by skipping the `DllMain` 
symbol if seen in aimport library. If this situation occurs, after this commit 
a warning will also be displayed. The warning can be silenced with 
`/ignore:exporteddllmain`

>From cb11f22699cc5cf4761f7ef426721ef0496030f5 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <alex_tor...@yahoo.fr>
Date: Wed, 2 Jul 2025 08:53:18 -0400
Subject: [PATCH] [LLD][COFF] Disallow importing DllMain from import libraries
 (#146610)

This is a workaround for
https://github.com/llvm/llvm-project/issues/82050 by skipping the `DllMain` 
symbol if seen in aimport library. If this situation occurs, after this commit 
a warning will also be displayed. The warning can be silenced with 
`/ignore:exporteddllmain`
---
 lld/COFF/Config.h                   |  1 +
 lld/COFF/Driver.cpp                 |  2 +
 lld/COFF/InputFiles.cpp             | 40 +++++++++++++++++++-
 lld/test/COFF/exported-dllmain.test | 57 +++++++++++++++++++++++++++++
 4 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 lld/test/COFF/exported-dllmain.test

diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 0c7c4e91402f1..424e9578395b3 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -313,6 +313,7 @@ struct Configuration {
   bool warnDebugInfoUnusable = true;
   bool warnLongSectionNames = true;
   bool warnStdcallFixup = true;
+  bool warnExportedDllMain = true;
   bool incremental = true;
   bool integrityCheck = false;
   bool killAt = false;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index a669b7e9296f6..8b2fc9f23178f 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -1625,6 +1625,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> 
argsArr) {
         config->warnLocallyDefinedImported = false;
       else if (s == "longsections")
         config->warnLongSectionNames = false;
+      else if (s == "exporteddllmain")
+        config->warnExportedDllMain = false;
       // Other warning numbers are ignored.
     }
   }
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 7b105fb4c17a2..b470b2a8d9080 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -117,6 +117,35 @@ static coff_symbol_generic *cloneSymbol(COFFSymbolRef sym) 
{
   }
 }
 
+// Skip importing DllMain thunks from import libraries.
+static bool fixupDllMain(COFFLinkerContext &ctx, llvm::object::Archive *file,
+                         const Archive::Symbol &sym, bool &skipDllMain) {
+  if (skipDllMain)
+    return true;
+  const Archive::Child &c =
+      CHECK(sym.getMember(), file->getFileName() +
+                                 ": could not get the member for symbol " +
+                                 toCOFFString(ctx, sym));
+  MemoryBufferRef mb =
+      CHECK(c.getMemoryBufferRef(),
+            file->getFileName() +
+                ": could not get the buffer for a child buffer of the 
archive");
+  if (identify_magic(mb.getBuffer()) == file_magic::coff_import_library) {
+    if (ctx.config.warnExportedDllMain) {
+      // We won't place DllMain symbols in the symbol table if they are
+      // coming from a import library. This message can be ignored with the 
flag
+      // '/ignore:exporteddllmain'
+      Warn(ctx)
+          << file->getFileName()
+          << ": skipping exported DllMain symbol [exporteddllmain]\nNOTE: this 
"
+             "might be a mistake when the DLL/library was produced.";
+    }
+    skipDllMain = true;
+    return true;
+  }
+  return false;
+}
+
 ArchiveFile::ArchiveFile(COFFLinkerContext &ctx, MemoryBufferRef m)
     : InputFile(ctx.symtab, ArchiveKind, m) {}
 
@@ -140,8 +169,17 @@ void ArchiveFile::parse() {
   }
 
   // Read the symbol table to construct Lazy objects.
-  for (const Archive::Symbol &sym : file->symbols())
+  bool skipDllMain = false;
+  for (const Archive::Symbol &sym : file->symbols()) {
+    // If the DllMain symbol was exported by mistake, skip importing it
+    // otherwise we might end up with a import thunk in the final binary which
+    // is wrong.
+    if (sym.getName() == "__imp_DllMain" || sym.getName() == "DllMain") {
+      if (fixupDllMain(ctx, file.get(), sym, skipDllMain))
+        continue;
+    }
     ctx.symtab.addLazyArchive(this, sym);
+  }
 }
 
 // Returns a buffer pointing to a member file containing a given symbol.
diff --git a/lld/test/COFF/exported-dllmain.test 
b/lld/test/COFF/exported-dllmain.test
new file mode 100644
index 0000000000000..fcf6ed1005379
--- /dev/null
+++ b/lld/test/COFF/exported-dllmain.test
@@ -0,0 +1,57 @@
+REQUIRES: x86
+RUN: split-file %s %t.dir && cd %t.dir
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows a.s -o a.obj
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows b1.s -o b1.obj
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows b2.s -o b2.obj
+
+### This is the line where our problem occurs. Here, we export the DllMain 
symbol which shouldn't happen normally.
+RUN: lld-link b1.obj b2.obj -out:b.dll -dll -implib:b.lib -entry:DllMain 
-export:bar -export:DllMain
+
+RUN: llvm-mc -filetype=obj -triple=x86_64-windows c.s -o c.obj
+RUN: lld-link -lib c.obj -out:c.lib
+
+### Later, if b.lib is provided before other libs/objs that export DllMain 
statically, we previously were using the dllimported DllMain from b.lib, which 
is wrong.
+RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain 2>&1 | 
FileCheck -check-prefix=WARN %s
+RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain 
-ignore:exporteddllmain 2>&1 | FileCheck -check-prefix=IGNORED --allow-empty %s
+RUN: llvm-objdump --private-headers -d out.dll | FileCheck 
-check-prefix=DISASM %s
+
+WARN: lld-link: warning: b.lib: skipping exported DllMain symbol 
[exporteddllmain]
+IGNORED-NOT: lld-link: warning: b.lib: skipping exported DllMain symbol 
[exporteddllmain]
+
+DISASM: The Import Tables:
+DISASM: DLL Name: b.dll
+DISASM-NOT: DllMain
+DISASM: bar
+DISASM: Disassembly of section .text:
+DISASM-EMPTY:
+DISASM:      b8 01 00 00 00               movl    $0x1, %eax
+DISASM-NEXT: c3                           retq
+
+#--- a.s
+        .text
+        .globl foo
+foo:
+        call *__imp_bar(%rip)
+        ret
+
+#--- b1.s
+        .text
+        .globl bar
+bar:
+        ret
+
+#--- b2.s
+        .text
+        .globl DllMain
+DllMain:
+        xor %eax, %eax
+        ret
+
+#--- c.s
+        .text
+        .globl DllMain
+DllMain:
+        movl $1, %eax
+        ret

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to