Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -62,6 +62,7 @@ void initializeWinEHStatePassPass(PassRegistry &); void initializeX86ExecutionDepsFixPass(PassRegistry &); +void initializeX86EmptyFunctionFixPass(PassRegistry &); } // end namespace llvm @@ -76,6 +77,7 @@ initializeFixupBWInstPassPass(PR); initializeEvexToVexInstPassPass(PR); initializeX86ExecutionDepsFixPass(PR); + initializeX86EmptyFunctionFixPass(PR); } static std::unique_ptr createTLOF(const Triple &TT) { @@ -360,11 +362,34 @@ }; char X86ExecutionDepsFix::ID; +class X86EmptyFunctionFix : public MachineFunctionPass { +public: + static char ID; + X86EmptyFunctionFix() : MachineFunctionPass(ID) {} + StringRef getPassName() const override { return "X86 Empty Function Fix"; } + bool runOnMachineFunction(MachineFunction &MF) override { + assert(!MF.empty() && "There's always an entry block."); + MachineBasicBlock &Entry = *MF.begin(); + if (++MF.begin() != MF.end() || !Entry.empty()) + return false; + + // The function has a single basic block, and that is empty. Add a trap + // instruction to avoid emitting a zero-byte function. + BuildMI(Entry, Entry.begin(), DebugLoc(), + MF.getSubtarget().getInstrInfo()->get(X86::TRAP)); + return true; + } +}; +char X86EmptyFunctionFix::ID; + } // end anonymous namespace INITIALIZE_PASS(X86ExecutionDepsFix, "x86-execution-deps-fix", "X86 Execution Dependency Fix", false, false) +INITIALIZE_PASS(X86EmptyFunctionFix, "x86-empty-function-fix", + "X86 Empty Function Fix", false, false) + TargetPassConfig *X86TargetMachine::createPassConfig(PassManagerBase &PM) { return new X86PassConfig(this, PM); } @@ -457,4 +482,11 @@ addPass(createX86FixupLEAs()); addPass(createX86EvexToVexInsts()); } + + // Make sure not to empty zero-byte functions for Windows. Empty functions can + // lead to duplicate entries (different functions with same RVAs) in the Guard + // CF Function Table, which the kernel will then refuse to load. See + // https://developercommunity.visualstudio.com/content/problem/45366/vc-linker-creates-invalid-dll-with-clang-cl.html + if (TM->getTargetTriple().isOSWindows()) + addPass(new X86EmptyFunctionFix()); } Index: test/CodeGen/X86/empty-function.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/empty-function.ll @@ -0,0 +1,38 @@ +; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck -check-prefix=CHECK -check-prefix=WIN -check-prefix=WIN32 %s +; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck -check-prefix=CHECK -check-prefix=WIN %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: +; WIN: ud2 +; LINUX-NOT: ud2 + +} + + +; unreachable still shouldn't trap in general on 32-bit Windows. As long as the +; function doesn't end up being empty, it's fine. + +define void @g() { +entry: + tail call void @foo() + unreachable + +; WIN32-LABEL: _g: +; WIN32: calll _foo +; WIN32-NOT: ud2 + +} + + +declare void @foo()