Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1046,15 +1046,17 @@ // If the function is empty and the object file uses .subsections_via_symbols, // then we need to emit *something* to the function body to prevent the // labels from collapsing together. Just emit a noop. - if ((MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode)) { + // Similarly, don't emit empty functions on Windows either. It can lead to + // duplicate entries (two functions with the same RVA) in the Guard CF Table + // after linking, causing the kernel not to load the binary: + // https://developercommunity.visualstudio.com/content/problem/45366/vc-linker-creates-invalid-dll-with-clang-cl.html + if (!HasAnyRealCode && + (MAI->hasSubsectionsViaSymbols() || TM.getTargetTriple().isOSWindows())) { MCInst Noop; + // FIXME: getNoopForMachoTarget() is actually not just for Mach-O. MF->getSubtarget().getInstrInfo()->getNoopForMachoTarget(Noop); OutStreamer->AddComment("avoids zero-length function"); - - // Targets can opt-out of emitting the noop here by leaving the opcode - // unspecified. - if (Noop.getOpcode()) - OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); + OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); } const Function *F = MF->getFunction(); Index: test/CodeGen/X86/empty-function.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/empty-function.ll @@ -0,0 +1,22 @@ +; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck -check-prefix=CHECK -check-prefix=WIN32 %s +; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck -check-prefix=CHECK -check-prefix=WIN64 %s +; RUN: llc < %s -mtriple=i386-linux-gnu | FileCheck -check-prefix=LINUX %s + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.0" + +; Don't emit empty functions on Windows; it can lead to duplicate entries +; (multiple functions sharing the same RVA) in the Guard CF Function Table which +; the kernel refuses to load. + +define void @f() { +entry: + unreachable + +; CHECK-LABEL: f: +; WIN32: nop +; WIN64: ud2 +; LINUX-NOT: nop +; LINUX-NOT: ud2 + +}