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