diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 79b63e5b7236f..9220c847f356d 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -307,7 +307,7 @@ struct Configuration { bool warnDebugInfoUnusable = true; bool warnLongSectionNames = true; bool warnStdcallFixup = true; - bool warnExportedDllMain = true; + bool warnImportedDllMain = true; bool incremental = true; bool integrityCheck = false; bool killAt = false; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 283aeed1a19cd..0f649ff1cf4f8 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1643,8 +1643,8 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { config->warnLocallyDefinedImported = false; else if (s == "longsections") config->warnLongSectionNames = false; - else if (s == "exporteddllmain") - config->warnExportedDllMain = false; + else if (s == "importeddllmain") + config->warnImportedDllMain = false; // Other warning numbers are ignored. } } diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index 0b7dbea8cdd99..2a6b63cbacca1 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -117,8 +117,6 @@ 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 " + @@ -128,13 +126,13 @@ static bool fixupDllMain(COFFLinkerContext &ctx, llvm::object::Archive *file, 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) { + if (ctx.config.warnImportedDllMain) { // 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' + // '/ignore:importeddllmain' Warn(ctx) << file->getFileName() - << ": skipping exported DllMain symbol [exporteddllmain]\nNOTE: this " + << ": skipping imported DllMain symbol [importeddllmain]\nNOTE: this " "might be a mistake when the DLL/library was produced."; } skipDllMain = true; @@ -204,14 +202,24 @@ void ArchiveFile::parse() { } } - // Read the symbol table to construct Lazy objects. bool skipDllMain = false; + StringRef mangledDllMain, impMangledDllMain; + + // The calls below will fail if we haven't set the machine type yet. Instead + // of failing, it is preferable to skip this "imported DllMain" check if we + // don't know the machine type at this point. + if (!file->isEmpty() && ctx.config.machine != IMAGE_FILE_MACHINE_UNKNOWN) { + mangledDllMain = archiveSymtab->mangle("DllMain"); + impMangledDllMain = uniqueSaver().save("__imp_" + mangledDllMain); + } + + // Read the symbol table to construct Lazy objects. 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)) + // If an import library provides the DllMain symbol, skip importing it, as + // we should be using our own DllMain, not another DLL's DllMain. + if (!mangledDllMain.empty() && (sym.getName() == mangledDllMain || + sym.getName() == impMangledDllMain)) { + if (skipDllMain || fixupDllMain(ctx, file.get(), sym, skipDllMain)) continue; } archiveSymtab->addLazyArchive(this, sym); diff --git a/lld/test/COFF/imported-dllmain-i386.test b/lld/test/COFF/imported-dllmain-i386.test new file mode 100644 index 0000000000000..f8aa09006999c --- /dev/null +++ b/lld/test/COFF/imported-dllmain-i386.test @@ -0,0 +1,58 @@ +REQUIRES: x86 +RUN: split-file %s %t.dir && cd %t.dir + +RUN: llvm-mc -filetype=obj -triple=i386-windows a.s -o a.obj + +RUN: llvm-mc -filetype=obj -triple=i386-windows b1.s -o b1.obj +RUN: llvm-mc -filetype=obj -triple=i386-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 -safeseh:no + +RUN: llvm-mc -filetype=obj -triple=i386-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 -safeseh:no 2>&1 | FileCheck -check-prefix=WARN %s +RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -ignore:importeddllmain -safeseh:no 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 imported DllMain symbol [importeddllmain] +IGNORED-NOT: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] + +DISASM: The Import Tables: +DISASM: DLL Name: b.dll +DISASM-NOT: DllMain +DISASM: bar +DISASM: Disassembly of section .text: +DISASM: b0 01 movb $0x1, %al +DISASM-NEXT: c3 retl + +#--- a.s + .text + .globl _foo +_foo: + call *__imp__bar + ret + +#--- b1.s + .text + .globl _bar +_bar: + ret + +#--- b2.s + .intel_syntax noprefix + .text + .globl _DllMain +_DllMain: + xor al, al + ret + +#--- c.s + .intel_syntax noprefix + .text + .globl _DllMain +_DllMain: + mov al, 1 + ret diff --git a/lld/test/COFF/exported-dllmain.test b/lld/test/COFF/imported-dllmain.test similarity index 86% rename from lld/test/COFF/exported-dllmain.test rename to lld/test/COFF/imported-dllmain.test index fcf6ed1005379..fa8579b1b41c5 100644 --- a/lld/test/COFF/exported-dllmain.test +++ b/lld/test/COFF/imported-dllmain.test @@ -14,11 +14,11 @@ 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: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -ignore:importeddllmain 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] +WARN: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] +IGNORED-NOT: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] DISASM: The Import Tables: DISASM: DLL Name: b.dll