ajpaverd updated this revision to Diff 223167. ajpaverd marked 22 inline comments as done. ajpaverd added a comment.
Improved Control Flow Guard implementation. As suggested by @rnk, the CFGuard dispatch mechanism now uses a new `cfguardtarget` operand bundle to pass the indirect call target. Instruction selection adds this target as a new ArgListEntry and sets a new `isCFGuardTarget` bit. CC_X86_Win64_C puts this argument in RAX. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D65761/new/ https://reviews.llvm.org/D65761 Files: clang/include/clang/Driver/CC1Options.td clang/include/clang/Driver/Options.td clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/MSVC.cpp clang/test/Driver/cl-fallback.c llvm/docs/LangRef.rst llvm/include/llvm/CodeGen/MachineBasicBlock.h llvm/include/llvm/CodeGen/TargetCallingConv.h llvm/include/llvm/CodeGen/TargetLowering.h llvm/include/llvm/IR/CallingConv.h llvm/include/llvm/IR/InstrTypes.h llvm/include/llvm/IR/LLVMContext.h llvm/include/llvm/Target/TargetCallingConv.td llvm/include/llvm/Transforms/CFGuard.h llvm/lib/AsmParser/LLLexer.cpp llvm/lib/AsmParser/LLParser.cpp llvm/lib/AsmParser/LLToken.h llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h llvm/lib/CodeGen/CFGuardLongjmp.cpp llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp llvm/lib/CodeGen/MachineBasicBlock.cpp llvm/lib/CodeGen/SelectionDAG/FastISel.cpp llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp llvm/lib/IR/AsmWriter.cpp llvm/lib/IR/LLVMContext.cpp llvm/lib/IR/Verifier.cpp llvm/lib/Target/AArch64/AArch64ISelLowering.cpp llvm/lib/Target/AArch64/AArch64TargetMachine.cpp llvm/lib/Target/ARM/ARMISelLowering.cpp llvm/lib/Target/ARM/ARMTargetMachine.cpp llvm/lib/Target/X86/CMakeLists.txt llvm/lib/Target/X86/X86.h llvm/lib/Target/X86/X86CallingConv.td llvm/lib/Target/X86/X86FastISel.cpp llvm/lib/Target/X86/X86FixupCFGuard.cpp llvm/lib/Target/X86/X86RegisterInfo.cpp llvm/lib/Target/X86/X86Subtarget.h llvm/lib/Target/X86/X86TargetMachine.cpp llvm/lib/Transforms/CFGuard/CFGuard.cpp llvm/test/Bitcode/calling-conventions.3.2.ll llvm/test/Bitcode/operand-bundles-bc-analyzer.ll llvm/test/CodeGen/AArch64/cfguard-checks.ll llvm/test/CodeGen/AArch64/cfguard-module-flag.ll llvm/test/CodeGen/ARM/cfguard-checks.ll llvm/test/CodeGen/ARM/cfguard-module-flag.ll llvm/test/CodeGen/WinCFGuard/cfguard-setjmp.ll llvm/test/CodeGen/X86/cfguard-checks.ll llvm/test/CodeGen/X86/cfguard-module-flag.ll
Index: llvm/test/CodeGen/X86/cfguard-module-flag.ll =================================================================== --- llvm/test/CodeGen/X86/cfguard-module-flag.ll +++ llvm/test/CodeGen/X86/cfguard-module-flag.ll @@ -1,9 +1,7 @@ ; RUN: llc < %s -mtriple=i686-pc-windows-msvc | FileCheck %s -check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s -check-prefix=X64 - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are not added in modules with the ; cfguard=1 flag (emit tables but no checks). Index: llvm/test/CodeGen/X86/cfguard-checks.ll =================================================================== --- llvm/test/CodeGen/X86/cfguard-checks.ll +++ llvm/test/CodeGen/X86/cfguard-checks.ll @@ -1,8 +1,6 @@ ; RUN: llc < %s -mtriple=i686-pc-windows-msvc | FileCheck %s -check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s -check-prefix=X64 - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required. @@ -32,7 +30,8 @@ attributes #0 = { nocf_check } -; Test that Control Flow Guard checks are correctly added as single instructions even at -O0. +; Test that Control Flow Guard checks are added even at -O0. +; FIXME Ideally these checks should be added as a single call instruction, as in the optimized case. define i32 @func_optnone_cf() #1 { entry: %func_ptr = alloca i32 ()*, align 8 @@ -46,13 +45,15 @@ ; X32: leal _target_func, %eax ; X32: movl %eax, (%esp) ; X32: movl (%esp), %ecx - ; X32: calll *___guard_check_icall_fptr + ; X32: movl ___guard_check_icall_fptr, %eax + ; X32: calll *%eax ; X32-NEXT: calll *%ecx ; On x86_64, __guard_dispatch_icall_fptr tail calls the function, so there should be only one call instruction. ; X64-LABEL: func_optnone_cf ; X64: leaq target_func(%rip), %rax - ; X64: callq *__guard_dispatch_icall_fptr(%rip) + ; X64: movq __guard_dispatch_icall_fptr(%rip), %rcx + ; X64: callq *%rcx ; X64-NOT: callq } attributes #1 = { noinline optnone } @@ -120,5 +121,61 @@ declare void @h() +; Test that Control Flow Guard preserves floating point arguments. +declare double @target_func_doubles(double, double, double, double) + +define double @func_cf_doubles() { +entry: + %func_ptr = alloca double (double, double, double, double)*, align 8 + store double (double, double, double, double)* @target_func_doubles, double (double, double, double, double)** %func_ptr, align 8 + %0 = load double (double, double, double, double)*, double (double, double, double, double)** %func_ptr, align 8 + %1 = call double %0(double 1.000000e+00, double 2.000000e+00, double 3.000000e+00, double 4.000000e+00) + ret double %1 + + ; On i686, the call to __guard_check_icall_fptr should come immediately before the call to the target function. + ; X32-LABEL: func_cf_doubles + ; X32: movl $_target_func_doubles, %esi + ; X32: movl $_target_func_doubles, %ecx + ; X32: calll *___guard_check_icall_fptr + ; X32: calll *%esi + + + ; On x86_64, __guard_dispatch_icall_fptr tail calls the function, so there should be only one call instruction. + ; X64-LABEL: func_cf_doubles + ; X64: leaq target_func_doubles(%rip), %rax + ; X64: movsd __real@3ff0000000000000(%rip), %xmm0 + ; X64: movsd __real@4000000000000000(%rip), %xmm1 + ; X64: movsd __real@4008000000000000(%rip), %xmm2 + ; X64: movsd __real@4010000000000000(%rip), %xmm3 + ; X64: callq *__guard_dispatch_icall_fptr(%rip) + ; X64-NOT: callq +} + + +; Test that Control Flow Guard checks are correctly added for tail calls. +define i32 @func_cf_tail() { +entry: + %func_ptr = alloca i32 ()*, align 8 + store i32 ()* @target_func, i32 ()** %func_ptr, align 8 + %0 = load i32 ()*, i32 ()** %func_ptr, align 8 + %1 = musttail call i32 %0() + ret i32 %1 + + ; On i686, the call to __guard_check_icall_fptr should come immediately before the call to the target function. + ; X32-LABEL: func_cf_tail + ; X32: movl $_target_func, %ecx + ; X32: calll *___guard_check_icall_fptr + ; X32: movl $_target_func, %eax + ; X32: jmpl *%eax # TAILCALL + ; X32-NOT: calll + + ; X64-LABEL: func_cf_tail + ; X64: leaq target_func(%rip), %rax + ; X64: movq __guard_dispatch_icall_fptr(%rip), %rcx + ; X64: rex64 jmpq *%rcx # TAILCALL + ; X64-NOT: callq +} + + !llvm.module.flags = !{!0} !0 = !{i32 2, !"cfguard", i32 2} \ No newline at end of file Index: llvm/test/CodeGen/WinCFGuard/cfguard-setjmp.ll =================================================================== --- llvm/test/CodeGen/WinCFGuard/cfguard-setjmp.ll +++ llvm/test/CodeGen/WinCFGuard/cfguard-setjmp.ll @@ -1,8 +1,5 @@ ; RUN: llc < %s | FileCheck %s -; This test is disabled on Linux -; UNSUPPORTED: linux - ; Test that longjmp targets have public labels and are included in the .gljmp section. %struct._SETJMP_FLOAT128 = type { [2 x i64] } @@ -19,14 +16,21 @@ %4 = call i32 @_setjmp(i8* bitcast ([16 x %struct._SETJMP_FLOAT128]* @buf1 to i8*), i8* %3) #2 ; CHECK: callq _setjmp - ; CHECK-NEXT: BB0_1: + ; CHECK-NEXT: $cfgsj_main0: + + %5 = call i8* @llvm.frameaddress(i32 0) + %6 = call i32 @_setjmp(i8* bitcast ([16 x %struct._SETJMP_FLOAT128]* @buf1 to i8*), i8* %5) #3 + + ; CHECK: callq _setjmp + ; CHECK-NEXT: $cfgsj_main1: store i32 1, i32* %2, align 4 - %5 = load i32, i32* %2, align 4 - ret i32 %5 + %7 = load i32, i32* %2, align 4 + ret i32 %7 ; CHECK: .section .gljmp$y,"dr" - ; CHECK-NEXT: .symidx BB0_1 + ; CHECK-NEXT: .symidx $cfgsj_main0 + ; CHECK-NEXT: .symidx $cfgsj_main1 } @@ -39,7 +43,8 @@ attributes #0 = { noinline nounwind } attributes #1 = { nounwind readnone } attributes #2 = { returns_twice } +attributes #3 = { returns_twice } !llvm.module.flags = !{!0} !0 = !{i32 2, !"cfguard", i32 2} \ No newline at end of file Index: llvm/test/CodeGen/ARM/cfguard-module-flag.ll =================================================================== --- llvm/test/CodeGen/ARM/cfguard-module-flag.ll +++ llvm/test/CodeGen/ARM/cfguard-module-flag.ll @@ -1,8 +1,6 @@ ; RUN: llc < %s -mtriple=arm-pc-windows-msvc | FileCheck %s - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are not added in modules with the ; cfguard=1 flag (emit tables but no checks). Index: llvm/test/CodeGen/ARM/cfguard-checks.ll =================================================================== --- llvm/test/CodeGen/ARM/cfguard-checks.ll +++ llvm/test/CodeGen/ARM/cfguard-checks.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s -mtriple=arm-pc-windows-msvc | FileCheck %s - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required. @@ -27,7 +25,7 @@ attributes #0 = { nocf_check "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+armv7-a,+dsp,+fp16,+neon,+strict-align,+thumb-mode,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false"} -; Test that Control Flow Guard checks are correctly added as single instructions even at -O0. +; Test that Control Flow Guard checks are added even at -O0. define i32 @func_optnone_cf() #1 { entry: %func_ptr = alloca i32 ()*, align 8 Index: llvm/test/CodeGen/AArch64/cfguard-module-flag.ll =================================================================== --- llvm/test/CodeGen/AArch64/cfguard-module-flag.ll +++ llvm/test/CodeGen/AArch64/cfguard-module-flag.ll @@ -1,8 +1,6 @@ ; RUN: llc < %s -mtriple=aarch64-pc-windows-msvc | FileCheck %s - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are not added in modules with the ; cfguard=1 flag (emit tables but no checks). Index: llvm/test/CodeGen/AArch64/cfguard-checks.ll =================================================================== --- llvm/test/CodeGen/AArch64/cfguard-checks.ll +++ llvm/test/CodeGen/AArch64/cfguard-checks.ll @@ -1,7 +1,5 @@ ; RUN: llc < %s -mtriple=aarch64-pc-windows-msvc | FileCheck %s - -; This test is disabled on Linux -; UNSUPPORTED: linux +; Control Flow Guard is currently only available on Windows ; Test that Control Flow Guard checks are correctly added when required. @@ -27,7 +25,7 @@ attributes #0 = { nocf_check } -; Test that Control Flow Guard checks are correctly added as single instructions even at -O0. +; Test that Control Flow Guard checks are added even at -O0. define i32 @func_optnone_cf() #1 { entry: %func_ptr = alloca i32 ()*, align 8 Index: llvm/test/Bitcode/operand-bundles-bc-analyzer.ll =================================================================== --- llvm/test/Bitcode/operand-bundles-bc-analyzer.ll +++ llvm/test/Bitcode/operand-bundles-bc-analyzer.ll @@ -6,6 +6,7 @@ ; CHECK-NEXT: <OPERAND_BUNDLE_TAG ; CHECK-NEXT: <OPERAND_BUNDLE_TAG ; CHECK-NEXT: <OPERAND_BUNDLE_TAG +; CHECK-NEXT: <OPERAND_BUNDLE_TAG ; CHECK-NEXT: </OPERAND_BUNDLE_TAGS_BLOCK ; CHECK: <FUNCTION_BLOCK Index: llvm/test/Bitcode/calling-conventions.3.2.ll =================================================================== --- llvm/test/Bitcode/calling-conventions.3.2.ll +++ llvm/test/Bitcode/calling-conventions.3.2.ll @@ -29,9 +29,6 @@ declare cfguard_checkcc void @cfguard_checkcc() ; CHECK: declare cfguard_checkcc void @cfguard_checkcc -declare cfguard_dispatchcc void @cfguard_dispatchcc() -; CHECK: declare cfguard_dispatchcc void @cfguard_dispatchcc - declare x86_stdcallcc void @x86_stdcallcc() ; CHECK: declare x86_stdcallcc void @x86_stdcallcc @@ -107,12 +104,6 @@ ret void } -define void @call_cfguard_dispatchcc() { -; CHECK: call cfguard_dispatchcc void @cfguard_dispatchcc -call cfguard_dispatchcc void @cfguard_dispatchcc() -ret void -} - define void @call_x86_stdcallcc() { ; CHECK: call x86_stdcallcc void @x86_stdcallcc call x86_stdcallcc void @x86_stdcallcc() Index: llvm/lib/Transforms/CFGuard/CFGuard.cpp =================================================================== --- llvm/lib/Transforms/CFGuard/CFGuard.cpp +++ llvm/lib/Transforms/CFGuard/CFGuard.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/IR/CallingConv.h" -#include "llvm/IR/Function.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IRBuilder.h" #include "llvm/InitializePasses.h" @@ -25,6 +24,8 @@ using namespace llvm; +using OperandBundleDef = OperandBundleDefT<Value *>; + #define DEBUG_TYPE "cfguard" STATISTIC(CFGuardCounter, "Number of Control Flow Guard checks added"); @@ -33,23 +34,23 @@ /// Adds Control Flow Guard (CFG) checks on indirect function calls/invokes. /// These checks ensure that the target address corresponds to the start of an -/// address-taken function. Different mechanisms are used for specific -/// architectures (e.g. X86_32 uses cf_check, X86_64 uses cf_dispatch). -class CFGuard : public ModulePass { +/// address-taken function. X86_64 targets use the CF_Dispatch mechanism. X86, +/// ARM, and AArch64 targets use the CF_Check machanism. +class CFGuard : public FunctionPass { public: static char ID; - enum Mechanism { cf_check, cf_dispatch }; + enum Mechanism { CF_Check, CF_Dispatch }; - // Default constructor required for the INITIALIZE_PASS macro - CFGuard() : ModulePass(ID) { + // Default constructor required for the INITIALIZE_PASS macro. + CFGuard() : FunctionPass(ID) { initializeCFGuardPass(*PassRegistry::getPassRegistry()); - // By default, use the guard check mechanism - GuardMechanism = cf_check; + // By default, use the guard check mechanism. + GuardMechanism = CF_Check; } - // Recommended constructor used to specify the type of guard mechanism - CFGuard(Mechanism Var) : ModulePass(ID) { + // Recommended constructor used to specify the type of guard mechanism. + CFGuard(Mechanism Var) : FunctionPass(ID) { initializeCFGuardPass(*PassRegistry::getPassRegistry()); GuardMechanism = Var; } @@ -121,8 +122,8 @@ /// %func_ptr = alloca i32 ()*, align 8 /// store i32 ()* @target_func, i32 ()** %func_ptr, align 8 /// %0 = load i32 ()*, i32 ()** %func_ptr, align 8 - /// %1 = load i32 (i32 ()*)*, i32 (i32 ()*)** @__guard_dispatch_icall_fptr - /// %2 = call cfguard_dispatchcc i32 %1(i32 ()* %0) + /// %1 = load i32 ()*, i32 ()** @__guard_dispatch_icall_fptr + /// %2 = call i32 %1() [ "cfguardtarget"(i32 ()* %0) ] /// \endcode /// /// For example, the following X86_64 assembly code: @@ -140,10 +141,13 @@ /// \param CB indirect call to instrument. void insertCFGuardDispatch(CallBase *CB); - bool runOnModule(Module &M) override; + bool doInitialization(Module &M) override; + bool runOnFunction(Function &F) override; private: - Mechanism GuardMechanism = cf_check; + // Only add checks if the module has the cfguard=2 flag. + int cfguard_module_flag = 0; + Mechanism GuardMechanism = CF_Check; FunctionType *GuardFnType = nullptr; PointerType *GuardFnPtrType = nullptr; Constant *GuardFnGlobal = nullptr; @@ -161,7 +165,7 @@ IRBuilder<> B(CB); Value *CalledOperand = CB->getCalledOperand(); - // Load the global symbol as a pointer to the check function + // Load the global symbol as a pointer to the check function. LoadInst *GuardCheckLoad = B.CreateLoad(GuardFnPtrType, GuardFnGlobal); // Create new call instruction. The CFGuard check should always be a call, @@ -171,7 +175,7 @@ {B.CreateBitCast(CalledOperand, B.getInt8PtrTy())}); // Ensure that the first argument is passed in the correct register - // (e.g. ECX on 32-bit X86 targets) + // (e.g. ECX on 32-bit X86 targets). GuardCheck->setCallingConv(CallingConv::CFGuard_Check); } @@ -184,160 +188,121 @@ IRBuilder<> B(CB); Value *CalledOperand = CB->getCalledOperand(); - Type *CalledOperandType = CalledOperand->getType(); - FunctionType *CalledFunctionType = cast<FunctionType>( - cast<PointerType>(CalledOperandType)->getElementType()); - - // Set up the new function type - SmallVector<Type *, 8> ArgTypes; - ArgTypes.push_back(CalledOperandType); - ArgTypes.append(CalledFunctionType->param_begin(), - CalledFunctionType->param_end()); - FunctionType *GuardDispatchType = - FunctionType::get(CalledFunctionType->getReturnType(), ArgTypes, - CalledFunctionType->isVarArg()); - PointerType *GuardDispatchPtrType = PointerType::get(GuardDispatchType, 0U); - - // Get or insert the global symbol "__guard_dispatch_icall_fptr" - Constant *GuardDispatchGlobal = CB->getModule()->getOrInsertGlobal( - "__guard_dispatch_icall_fptr", GuardDispatchPtrType); - - // Load the global symbol as a pointer to a function of the new type + + // Cast the guard dispatch global to the type of the called operand. + PointerType *PTy = PointerType::get(CalledOperandType, 0); + if (GuardFnGlobal->getType() != PTy) + GuardFnGlobal = ConstantExpr::getBitCast(GuardFnGlobal, PTy); + + // Load the global as a pointer to a function of the same type. LoadInst *GuardDispatchLoad = - B.CreateLoad(GuardDispatchPtrType, GuardDispatchGlobal); - - // Prepare the arguments for the new call - SmallVector<Value *, 8> GuardDispatchArgs; - GuardDispatchArgs.push_back(CalledOperand); - GuardDispatchArgs.append(CB->arg_begin(), CB->arg_end()); - - // Depending on the type of the original instruction, create new - // call/invoke/callbr instruction - CallBase *GuardDispatch; - if (CallInst::classof(CB)) { - GuardDispatch = - B.CreateCall(GuardDispatchType, GuardDispatchLoad, GuardDispatchArgs); - } else if (InvokeInst::classof(CB)) { - InvokeInst *CBInvoke = cast<InvokeInst>(CB); - GuardDispatch = B.CreateInvoke( - GuardDispatchType, GuardDispatchLoad, CBInvoke->getNormalDest(), - CBInvoke->getUnwindDest(), GuardDispatchArgs); + B.CreateLoad(CalledOperandType, GuardFnGlobal); + + // Add the original call target as a cfguardtarget operand bundle. + SmallVector<llvm::OperandBundleDef, 1> Bundles; + CB->getOperandBundlesAsDefs(Bundles); + Bundles.emplace_back("cfguardtarget", CalledOperand); + + // Create a copy of the call/invoke instruction and add the new bundle. + CallBase *NewCB; + if (CallInst* CI = dyn_cast<CallInst>(CB)) { + NewCB = CallInst::Create(CI, Bundles, CB); } else { - assert(CallBrInst::classof(CB) && "Unsupported indirect call instruction."); - CallBrInst *CBCallBr = cast<CallBrInst>(CB); - GuardDispatch = B.CreateCallBr( - GuardDispatchType, GuardDispatchLoad, CBCallBr->getDefaultDest(), - CBCallBr->getIndirectDests(), GuardDispatchArgs); + assert(isa<InvokeInst>(CB) && "Unknown indirect call type"); + InvokeInst* II = cast<InvokeInst>(CB); + NewCB = llvm::InvokeInst::Create(II, Bundles, CB); } - assert(GuardDispatch->getNumArgOperands() == CB->getNumArgOperands() + 1 && - "Incorrect number of arguments!"); - - // Create new attribute list and copy function attributes, return attributes, - // and parameter attributes (shifting parameter attributes one to the right). - AttributeList OldAttrs = CB->getAttributes(); - AttributeList NewAttrs = GuardDispatch->getAttributes(); - NewAttrs.addAttributes(CB->getContext(), AttributeList::FunctionIndex, - CB->getAttributes().getFnAttributes()); - NewAttrs.addAttributes(CB->getContext(), AttributeList::ReturnIndex, - CB->getAttributes().getRetAttributes()); - for (unsigned int i = 0; i < CB->getNumArgOperands(); i++) { - NewAttrs.addParamAttributes(CB->getContext(), i + 1, - OldAttrs.getParamAttributes(i)); - } - GuardDispatch->setAttributes(NewAttrs); - - // Use a custom calling convention to pass the address of the original - // function as the first argument to the guard dispatch call in the correct - // register (i.e. RAX on 64-bit X86 targets) - GuardDispatch->setCallingConv(CallingConv::CFGuard_Dispatch); - - // Replace all uses of the original call/invoke with the new dispatch - CB->replaceAllUsesWith(GuardDispatch); + // Change the target of the call to be the guard dispatch function. + NewCB->setCalledOperand(GuardDispatchLoad); + + // Replace the original call/invoke with the new instruction. + CB->replaceAllUsesWith(NewCB); - // Delete the original call/invoke + // Delete the original call/invoke. CB->eraseFromParent(); } -bool CFGuard::runOnModule(Module &M) { +bool CFGuard::doInitialization(Module &M) { - // Only add checks if the module has the cfguard=2 flag - int cfguard_flag = 0; + // Check if this module has the cfguard flag and read its value. if (auto *MD = mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("cfguard"))) - cfguard_flag = MD->getZExtValue(); - if (cfguard_flag != 2) + cfguard_module_flag = MD->getZExtValue(); + + // Skip modules for which CFGuard checks have been disabled. + if (cfguard_module_flag != 2) return false; - // The guard check function has the same type for every indirect call in the - // module, so this can be initialized once per module. - if (GuardMechanism == cf_check) { - GuardFnType = - FunctionType::get(Type::getVoidTy(M.getContext()), + // Set up prototypes for the guard check and dispatch functions. + GuardFnType = FunctionType::get(Type::getVoidTy(M.getContext()), {Type::getInt8PtrTy(M.getContext())}, false); - GuardFnPtrType = PointerType::get(GuardFnType, 0); - GuardFnGlobal = - M.getOrInsertGlobal("__guard_check_icall_fptr", GuardFnPtrType); - } - - for (Function &F : M) { + GuardFnPtrType = PointerType::get(GuardFnType, 0); - bool ChecksAdded = false; - - // Skip functions for which CFG checks have been disabled - if (F.hasFnAttribute(Attribute::NoCfCheck)) - continue; + // Get or insert the guard check or dispatch global symbols. + if (GuardMechanism == CF_Check) { + GuardFnGlobal = M.getOrInsertGlobal( + "__guard_check_icall_fptr", GuardFnPtrType); + } else { + assert(GuardMechanism == CF_Dispatch && "Invalid CFGuard mechanism"); + GuardFnGlobal = M.getOrInsertGlobal( + "__guard_dispatch_icall_fptr", GuardFnPtrType); + } - // Iterate over the instructions to find all indirect call/invoke/callbr - // instructions. Make a separate list of pointers to indirect - // call/invoke/callbr instructions because the original instructions will be - // deleted as the checks are added - SmallVector<CallBase *, 8> IndirectCalls; - for (BasicBlock &BB : F.getBasicBlockList()) { - for (Instruction &I : BB.getInstList()) { + return true; +} - auto *CB = dyn_cast<CallBase>(&I); - if (!CB) continue; +bool CFGuard::runOnFunction(Function &F) { - if (CB->isIndirectCall()) { - IndirectCalls.push_back(CB); - ChecksAdded = true; - CFGuardCounter++; - } + // Skip modules and functions for which CFGuard checks have been disabled. + if (cfguard_module_flag != 2 || F.hasFnAttribute(Attribute::NoCfCheck)) + return false; + SmallVector<CallBase *, 8> IndirectCalls; + + // Iterate over the instructions to find all indirect call/invoke/callbr + // instructions. Make a separate list of pointers to indirect + // call/invoke/callbr instructions because the original instructions will be + // deleted as the checks are added. + for (BasicBlock &BB : F.getBasicBlockList()) { + for (Instruction &I : BB.getInstList()) { + auto *CB = dyn_cast<CallBase>(&I); + if (CB && CB->isIndirectCall()) { + IndirectCalls.push_back(CB); + CFGuardCounter++; } } + } - // For each indirect call/invoke/callbr, add the appropriate dispatch or - // check - if (GuardMechanism == cf_dispatch) { - for (CallBase *CB : IndirectCalls) { - insertCFGuardDispatch(CB); - } - } else { - for (CallBase *CB : IndirectCalls) { - insertCFGuardCheck(CB); - } - } + // If no checks are needed, return early and add this attribute to indicate + // that subsequent CFGuard passes can skip this function. + if (IndirectCalls.empty()) { + F.addFnAttr(Attribute::NoCfCheck); + return false; + } - // If no checks were added, add this attribute to indicate that subsequent - // CFGuard passes do not need to consider this function - if (!ChecksAdded) - F.addFnAttr(Attribute::NoCfCheck); + // For each indirect call/invoke, add the appropriate dispatch or check. + if (GuardMechanism == CF_Dispatch) { + for (CallBase *CB : IndirectCalls) { + insertCFGuardDispatch(CB); + } + } else { + for (CallBase *CB : IndirectCalls) { + insertCFGuardCheck(CB); + } } return true; } - char CFGuard::ID = 0; INITIALIZE_PASS(CFGuard, "CFGuard", "CFGuard", false, false) -ModulePass *llvm::createCFGuardCheckPass() { - return new CFGuard(CFGuard::cf_check); +FunctionPass *llvm::createCFGuardCheckPass() { + return new CFGuard(CFGuard::CF_Check); } -ModulePass *llvm::createCFGuardDispatchPass() { - return new CFGuard(CFGuard::cf_dispatch); +FunctionPass *llvm::createCFGuardDispatchPass() { + return new CFGuard(CFGuard::CF_Dispatch); } \ No newline at end of file Index: llvm/lib/Target/X86/X86TargetMachine.cpp =================================================================== --- llvm/lib/Target/X86/X86TargetMachine.cpp +++ llvm/lib/Target/X86/X86TargetMachine.cpp @@ -420,10 +420,9 @@ // feature enabled. addPass(createIndirectBrExpandPass()); - // Add Control Flow Guard checks + // Add Control Flow Guard checks. const Triple &TT = TM->getTargetTriple(); if (TT.isOSWindows()) { - //addPass(createCFGuardLongjmpFPass()); if(TT.getArch() == Triple::x86_64) { addPass(createCFGuardDispatchPass()); } else { @@ -495,11 +494,6 @@ addPass(createX86SpeculativeLoadHardeningPass()); addPass(createX86FlagsCopyLoweringPass()); addPass(createX86WinAllocaExpander()); - if (TM->getTargetTriple().isOSWindows()) - // Fixup Control Flow Guard checks. - addPass(createX86FixupCFGuardPass()); - // Emit longjmp targets for Control Flow Guard - //addPass(createCFGuardLongjmpPass()); } void X86PassConfig::addMachineSSAOptimization() { addPass(createX86DomainReassignmentPass()); @@ -544,7 +538,7 @@ (!TT.isOSWindows() || MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI)) addPass(createCFIInstrInserter()); - // Identify valid longjmp targets for Windows Control Flow Guard + // Identify valid longjmp targets for Windows Control Flow Guard. if (TT.isOSWindows()) addPass(createCFGuardLongjmpPass()); } Index: llvm/lib/Target/X86/X86Subtarget.h =================================================================== --- llvm/lib/Target/X86/X86Subtarget.h +++ llvm/lib/Target/X86/X86Subtarget.h @@ -815,7 +815,6 @@ case CallingConv::X86_ThisCall: case CallingConv::X86_VectorCall: case CallingConv::Intel_OCL_BI: - case CallingConv::CFGuard_Dispatch: return isTargetWin64(); // This convention allows using the Win64 convention on other targets. case CallingConv::Win64: Index: llvm/lib/Target/X86/X86RegisterInfo.cpp =================================================================== --- llvm/lib/Target/X86/X86RegisterInfo.cpp +++ llvm/lib/Target/X86/X86RegisterInfo.cpp @@ -353,14 +353,9 @@ if (!HasSSE) return CSR_Win64_NoSSE_SaveList; return CSR_Win64_SaveList; - case CallingConv::CFGuard_Dispatch: - assert(IsWin64 && "CFGuard dispatch mechanism only used on X86_64"); - if (!HasSSE) - return CSR_Win64_NoSSE_SaveList; - return CSR_Win64_SaveList; - case CallingConv::X86_64_SysV: - if (CallsEHReturn) - return CSR_64EHRet_SaveList; + case CallingConv::X86_64_SysV: + if (CallsEHReturn) + return CSR_64EHRet_SaveList; return CSR_64_SaveList; case CallingConv::X86_INTR: if (Is64Bit) { @@ -474,9 +469,6 @@ break; case CallingConv::Win64: return CSR_Win64_RegMask; - case CallingConv::CFGuard_Dispatch: - assert(IsWin64 && "CFGuard dispatch mechanism only used on X86_64"); - return CSR_Win64_RegMask; case CallingConv::X86_64_SysV: return CSR_64_RegMask; case CallingConv::X86_INTR: Index: llvm/lib/Target/X86/X86FixupCFGuard.cpp =================================================================== --- llvm/lib/Target/X86/X86FixupCFGuard.cpp +++ /dev/null @@ -1,218 +0,0 @@ -//===-- X86FixupCFGuard.cpp - Control Flow Guard checks ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file contains the machine instruction transform to fixup the Control -/// Flow Guard checks inserted by /X86CFGuard.cpp. This pass searches -/// for such cases and replaces the pair of instructions with a single -/// call/invoke. For example: -/// -/// For 32-bit targets, the following assembly code: -/// \code -/// movl ___guard_check_icall_fptr, %eax -/// calll *%eax -/// \endcode -/// -/// is transformed to: -/// \code -/// calll *___guard_check_icall_fptr -/// \endcode -/// -/// For 64-bit targets, the following assembly code: -/// \code -/// movq __guard_dispatch_icall_fptr(%rip), %rcx -/// callq *%rcx -/// \endcode -/// -/// is transformed to: -/// \code -/// callq *__guard_dispatch_icall_fptr(%rip) -/// \endcode -/// -//===----------------------------------------------------------------------===// - -#include "X86InstrInfo.h" -#include "X86Subtarget.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/MachineOperand.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" - -using namespace llvm; - -#define DEBUG_TYPE "x86-fixup-cfguard" - -STATISTIC(X86CFGuardFixed, "Number of X86 Control Flow Guard checks fixed"); - -namespace { - -/// MachineFunction pass to fix x86 Control Flow Guard checks that have been -/// generated as separate load and call/invoke instructions. -class X86FixupCFGuard : public MachineFunctionPass { -public: - static char ID; - - X86FixupCFGuard() : MachineFunctionPass(ID) {} - - StringRef getPassName() const override { - return "X86 Fixup Control Flow Guard"; - } - - /// Check if an instruction is loading a Guard function pointer by comparing - /// the instruction's global value to our cached pointers to the Guard - /// globals. - bool isGuardLoad(MachineInstr &MI); - - /// Given a guard load instruction, find all subsequent calls/invokes of the - /// loaded value in the basic block and replace each of these load-call/invoke - /// pairs with a single call/invoke. This function returns true if any - /// instructions were modified. - bool fixupGuardLoad(MachineInstr &LoadMI, const X86InstrInfo *TII); - - bool runOnMachineFunction(MachineFunction &MF) override; - -private: - const GlobalVariable *GuardCheckGlobal = nullptr; - const GlobalVariable *GuardDispatchGlobal = nullptr; -}; - -} // end anonymous namespace - -FunctionPass *llvm::createX86FixupCFGuardPass() { - return new X86FixupCFGuard(); -} - -char X86FixupCFGuard::ID = 0; - -bool X86FixupCFGuard::isGuardLoad(MachineInstr &MI) { - return (MI.getOpcode() == X86::MOV32rm && MI.getNumOperands() > 4 && - MI.getOperand(4).isGlobal() && - MI.getOperand(4).getGlobal() == GuardCheckGlobal) || - (MI.getOpcode() == X86::MOV64rm && MI.getNumOperands() > 4 && - MI.getOperand(4).isGlobal() && - MI.getOperand(4).getGlobal() == GuardDispatchGlobal); -} - -bool X86FixupCFGuard::fixupGuardLoad(MachineInstr &LoadMI, - const X86InstrInfo *TII) { - - // Select the correct opcodes based on the load instruction - unsigned int OldCallOpcode, NewCallOpcode; - if (LoadMI.getOpcode() == X86::MOV32rm) { - OldCallOpcode = X86::CALL32r; - NewCallOpcode = X86::CALL32m; - } else if (LoadMI.getOpcode() == X86::MOV64rm) { - OldCallOpcode = X86::CALL64r; - NewCallOpcode = X86::CALL64m; - } else { - // Not a supported load instruction - return false; - } - - // List of call/invoke machine instructions to erase - SmallVector<MachineInstr *, 2> MIsToErase; - - // Store the register into which the guard function pointer was loaded - unsigned int LoadReg = LoadMI.getOperand(0).getReg(); - assert(Register::isPhysicalRegister(LoadReg) == false && - "X86CFGuardFixup pass must be run before register allocation."); - - // Get an iterator starting from the load instruction - MachineBasicBlock *MBB = LoadMI.getParent(); - MachineBasicBlock::instr_iterator MIIter = LoadMI.getIterator(); - - // Iterate through the remaining instructions in the basic block after the - // load instruction - for (auto I = LoadMI.getIterator(), E = MBB->instr_end(); I != E; ++I) { - MachineInstr &MI = cast<MachineInstr>(*I); - - // Check if the instruction is a call/invoke through the loaded register - if (MI.getOpcode() == OldCallOpcode && - MI.getOperand(0).getReg() == LoadReg) { - - // Add new call/invoke instruction with same external symbol as preceding - // load. Omit operand 0 of the load instruction (destination register) and - // shift other operands one to the left. - MachineInstrBuilder B = - BuildMI(*MBB, MI, MI.getDebugLoc(), TII->get(NewCallOpcode)) - .add(LoadMI.getOperand(1)) - .add(LoadMI.getOperand(2)) - .add(LoadMI.getOperand(3)) - .add(LoadMI.getOperand(4)) - .add(LoadMI.getOperand(5)); - - // Copy implicit operands from the original call/invoke. This also copies - // the register mask from the original call/invoke. - B.copyImplicitOps(MI); - - // Mark original call/invoke instruction to be erased - MIsToErase.push_back(&MI); - - // Increment counter of guard calls/invokes fixed - X86CFGuardFixed++; - } - } - - // Instructions have not been changed - if (MIsToErase.empty()) - return false; - - // Erase all marked call/invoke instructions - for (MachineInstr *MI : MIsToErase) { - MI->eraseFromParent(); - } - - // Instructions have been changed - return true; -} - -bool X86FixupCFGuard::runOnMachineFunction(MachineFunction &MF) { - - // Skip functions that should not have CF checks - if (MF.getFunction().hasFnAttribute(Attribute::NoCfCheck)) - return false; - - // Look up the guard global variables from the parent module - GuardCheckGlobal = - MF.getFunction().getParent()->getNamedGlobal("__guard_check_icall_fptr"); - GuardDispatchGlobal = MF.getFunction().getParent()->getNamedGlobal( - "__guard_dispatch_icall_fptr"); - - // Skip functions that do not contain either of the guard globals - if (!GuardCheckGlobal && !GuardDispatchGlobal) - return false; - - const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>(); - const X86InstrInfo *TII = STI.getInstrInfo(); - - SmallVector<MachineInstr *, 16> GuardLoads; - - for (MachineBasicBlock &MBB : MF) { - for (MachineInstr &MI : MBB) { - if (isGuardLoad(MI)) - GuardLoads.push_back(&MI); - } - } - - if (GuardLoads.empty()) - return false; - - for (MachineInstr *LoadMI : GuardLoads) { - fixupGuardLoad(*LoadMI, TII); - - assert(MF.getRegInfo().use_empty(LoadMI->getOperand(0).getReg()) && - "Register containing guard function pointer is still in use."); - - LoadMI->eraseFromParent(); - } - - return true; -} \ No newline at end of file Index: llvm/lib/Target/X86/X86FastISel.cpp =================================================================== --- llvm/lib/Target/X86/X86FastISel.cpp +++ llvm/lib/Target/X86/X86FastISel.cpp @@ -1164,7 +1164,6 @@ CC != CallingConv::X86_StdCall && CC != CallingConv::X86_ThisCall && CC != CallingConv::X86_64_SysV && - CC != CallingConv::CFGuard_Dispatch && CC != CallingConv::Win64) return false; @@ -3217,7 +3216,6 @@ case CallingConv::Win64: case CallingConv::X86_64_SysV: case CallingConv::CFGuard_Check: - case CallingConv::CFGuard_Dispatch: break; } Index: llvm/lib/Target/X86/X86CallingConv.td =================================================================== --- llvm/lib/Target/X86/X86CallingConv.td +++ llvm/lib/Target/X86/X86CallingConv.td @@ -457,7 +457,6 @@ // Handle explicit CC selection CCIfCC<"CallingConv::Win64", CCDelegateTo<RetCC_X86_Win64_C>>, - CCIfCC<"CallingConv::CFGuard_Dispatch", CCDelegateTo<RetCC_X86_Win64_C>>, CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<RetCC_X86_64_C>>, // Handle Vectorcall CC @@ -607,6 +606,9 @@ // A SwiftError is passed in R12. CCIfSwiftError<CCIfType<[i64], CCAssignToReg<[R12]>>>, + // The 'CFGuardTarget' parameter, if any, is passed in RAX. + CCIfCFGuardTarget<CCAssignToReg<[RAX]>>, + // 128 bit vectors are passed by pointer CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCPassIndirect<i64>>, @@ -650,14 +652,6 @@ CCIfType<[i8, i16, i32, i64, f32, f64], CCAssignToStack<8, 8>> ]>; -def CC_X86_Win64_CFGuard_Dispatch : CallingConv<[ - // The function address (i.e. first integer argument) is passed in RAX - CCIfType<[i64], CCAssignToReg<[RAX]>>, - - // Otherwise, same as everything else. - CCDelegateTo<CC_X86_Win64_C> -]>; - def CC_X86_Win64_VectorCall : CallingConv<[ CCCustom<"CC_X86_64_VectorCall">, @@ -1032,7 +1026,6 @@ CCIfCC<"CallingConv::WebKit_JS", CCDelegateTo<CC_X86_64_WebKit_JS>>, CCIfCC<"CallingConv::AnyReg", CCDelegateTo<CC_X86_64_AnyReg>>, CCIfCC<"CallingConv::Win64", CCDelegateTo<CC_X86_Win64_C>>, - CCIfCC<"CallingConv::CFGuard_Dispatch", CCDelegateTo<CC_X86_Win64_CFGuard_Dispatch>>, CCIfCC<"CallingConv::X86_64_SysV", CCDelegateTo<CC_X86_64_C>>, CCIfCC<"CallingConv::X86_VectorCall", CCDelegateTo<CC_X86_Win64_VectorCall>>, CCIfCC<"CallingConv::HHVM", CCDelegateTo<CC_X86_64_HHVM>>, Index: llvm/lib/Target/X86/X86.h =================================================================== --- llvm/lib/Target/X86/X86.h +++ llvm/lib/Target/X86/X86.h @@ -123,10 +123,6 @@ /// This pass applies profiling information to insert cache prefetches. FunctionPass *createX86InsertPrefetchPass(); -/// This pass fixes up Control Flow Guard checks by merging a load and -/// subsequent call into a single call instruction. See X86FixupCFGuard.cpp -FunctionPass *createX86FixupCFGuardPass(); - InstructionSelector *createX86InstructionSelector(const X86TargetMachine &TM, X86Subtarget &, X86RegisterBankInfo &); @@ -147,7 +143,6 @@ void initializeX86ExecutionDomainFixPass(PassRegistry &); void initializeX86FlagsCopyLoweringPassPass(PassRegistry &); void initializeX86SpeculativeLoadHardeningPassPass(PassRegistry &); -void initializeX86CFGuardPass(PassRegistry &); } // End llvm namespace Index: llvm/lib/Target/X86/CMakeLists.txt =================================================================== --- llvm/lib/Target/X86/CMakeLists.txt +++ llvm/lib/Target/X86/CMakeLists.txt @@ -33,7 +33,6 @@ X86ExpandPseudo.cpp X86FastISel.cpp X86FixupBWInsts.cpp - X86FixupCFGuard.cpp X86FixupLEAs.cpp X86AvoidStoreForwardingBlocks.cpp X86FixupSetCC.cpp Index: llvm/lib/Target/ARM/ARMTargetMachine.cpp =================================================================== --- llvm/lib/Target/ARM/ARMTargetMachine.cpp +++ llvm/lib/Target/ARM/ARMTargetMachine.cpp @@ -421,8 +421,8 @@ if (TM->getOptLevel() != CodeGenOpt::None) addPass(createInterleavedAccessPass()); - // Add Control Flow Guard checks - if (TM->getTargetTriple().isOSWindows()) + // Add Control Flow Guard checks. + if (TM->getTargetTriple().isOSWindows()) addPass(createCFGuardCheckPass()); } Index: llvm/lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- llvm/lib/Target/ARM/ARMISelLowering.cpp +++ llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1798,7 +1798,6 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC, bool isVarArg) const { switch (CC) { - case CallingConv::CFGuard_Dispatch: default: report_fatal_error("Unsupported calling convention"); case CallingConv::ARM_AAPCS: Index: llvm/lib/Target/AArch64/AArch64TargetMachine.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -451,7 +451,7 @@ addPass(createAArch64StackTaggingPass()); - // Add Control Flow Guard checks + // Add Control Flow Guard checks. if (TM->getTargetTriple().isOSWindows()) addPass(createCFGuardCheckPass()); } Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3048,7 +3048,6 @@ CCAssignFn *AArch64TargetLowering::CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const { switch (CC) { - case CallingConv::CFGuard_Dispatch: default: report_fatal_error("Unsupported calling convention."); case CallingConv::WebKit_JS: Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -2958,10 +2958,10 @@ if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) visitIntrinsicCall(ID, Call); - // Verify that a callsite has at most one "deopt", at most one "funclet" and - // at most one "gc-transition" operand bundle. + // Verify that a callsite has at most one "deopt", at most one "funclet", at + // most one "gc-transition", and at most one "cfguardtarget" operand bundle. bool FoundDeoptBundle = false, FoundFuncletBundle = false, - FoundGCTransitionBundle = false; + FoundGCTransitionBundle = false, FoundCFGuardTargetBundle = false; for (unsigned i = 0, e = Call.getNumOperandBundles(); i < e; ++i) { OperandBundleUse BU = Call.getOperandBundleAt(i); uint32_t Tag = BU.getTagID(); @@ -2980,6 +2980,12 @@ Assert(isa<FuncletPadInst>(BU.Inputs.front()), "Funclet bundle operands should correspond to a FuncletPadInst", Call); + } else if (Tag == LLVMContext::OB_cfguardtarget) { + Assert(!FoundCFGuardTargetBundle, + "Multiple CFGuardTarget operand bundles", Call); + FoundCFGuardTargetBundle = true; + Assert(BU.Inputs.size() == 1, + "Expected exactly one cfguardtarget bundle operand", Call); } } Index: llvm/lib/IR/LLVMContext.cpp =================================================================== --- llvm/lib/IR/LLVMContext.cpp +++ llvm/lib/IR/LLVMContext.cpp @@ -62,6 +62,11 @@ "gc-transition operand bundle id drifted!"); (void)GCTransitionEntry; + auto *CFGuardTargetEntry = pImpl->getOrInsertBundleTag("cfguardtarget"); + assert(CFGuardTargetEntry->second == LLVMContext::OB_cfguardtarget && + "cfguardtarget operand bundle id drifted!"); + (void)CFGuardTargetEntry; + SyncScope::ID SingleThreadSSID = pImpl->getOrInsertSyncScopeID("singlethread"); assert(SingleThreadSSID == SyncScope::SingleThread && Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -353,7 +353,6 @@ case CallingConv::CXX_FAST_TLS: Out << "cxx_fast_tlscc"; break; case CallingConv::GHC: Out << "ghccc"; break; case CallingConv::CFGuard_Check: Out << "cfguard_checkcc"; break; - case CallingConv::CFGuard_Dispatch: Out << "cfguard_dispatchcc"; break; case CallingConv::X86_StdCall: Out << "x86_stdcallcc"; break; case CallingConv::X86_FastCall: Out << "x86_fastcallcc"; break; case CallingConv::X86_ThisCall: Out << "x86_thiscallcc"; break; Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2741,7 +2741,7 @@ // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't // have to do anything here to lower funclet bundles. assert(!I.hasOperandBundlesOtherThan( - {LLVMContext::OB_deopt, LLVMContext::OB_funclet}) && + {LLVMContext::OB_deopt, LLVMContext::OB_funclet, LLVMContext::OB_cfguardtarget}) && "Cannot lower invokes with arbitrary operand bundles yet!"); const Value *Callee(I.getCalledValue()); @@ -7100,6 +7100,18 @@ isTailCall = false; } + // If call site has a cfguardtarget operand bundle, create and add an + // additional ArgListEntry. + if (auto Bundle = CS.getOperandBundle(LLVMContext::OB_cfguardtarget)) { + TargetLowering::ArgListEntry Entry; + Value *V = Bundle->Inputs[0]; + SDValue ArgNode = getValue(V); + Entry.Node = ArgNode; + Entry.Ty = V->getType(); + Entry.IsCFGuardTarget = true; + Args.push_back(Entry); + } + // Check if target-independent constraints permit a tail call here. // Target-dependent constraints are checked within TLI->LowerCallTo. if (isTailCall && !isInTailCallPosition(CS, DAG.getTarget())) @@ -7641,8 +7653,9 @@ // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't // have to do anything here to lower funclet bundles. + // CFGuardTarget bundles are lowered in LowerCallTo. assert(!I.hasOperandBundlesOtherThan( - {LLVMContext::OB_deopt, LLVMContext::OB_funclet}) && + {LLVMContext::OB_deopt, LLVMContext::OB_funclet, LLVMContext::OB_cfguardtarget}) && "Cannot lower calls with arbitrary operand bundles!"); SDValue Callee = getValue(I.getCalledValue()); @@ -8985,6 +8998,7 @@ Entry.IsReturned = false; Entry.IsSwiftSelf = false; Entry.IsSwiftError = false; + Entry.IsCFGuardTarget = false; Entry.Alignment = Align; CLI.getArgs().insert(CLI.getArgs().begin(), Entry); CLI.NumFixedArgs += 1; @@ -9097,6 +9111,8 @@ Flags.setSwiftSelf(); if (Args[i].IsSwiftError) Flags.setSwiftError(); + if (Args[i].IsCFGuardTarget) + Flags.setCFGuardTarget(); if (Args[i].IsByVal) Flags.setByVal(); if (Args[i].IsInAlloca) { Index: llvm/lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1190,6 +1190,8 @@ Flags.setSwiftSelf(); if (Arg.IsSwiftError) Flags.setSwiftError(); + if (Arg.IsCFGuardTarget) + Flags.setCFGuardTarget(); if (Arg.IsByVal) Flags.setByVal(); if (Arg.IsInAlloca) { Index: llvm/lib/CodeGen/MachineBasicBlock.cpp =================================================================== --- llvm/lib/CodeGen/MachineBasicBlock.cpp +++ llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -54,8 +54,7 @@ if (!CachedMCSymbol) { const MachineFunction *MF = getParent(); MCContext &Ctx = MF->getContext(); - auto Prefix = - LabelIsPublic ? "" : Ctx.getAsmInfo()->getPrivateLabelPrefix(); + auto Prefix = Ctx.getAsmInfo()->getPrivateLabelPrefix(); assert(getNumber() >= 0 && "cannot get label for unreachable MBB"); CachedMCSymbol = Ctx.getOrCreateSymbol(Twine(Prefix) + "BB" + Twine(MF->getFunctionNumber()) + Index: llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -1553,6 +1553,10 @@ if (F && F->hasDLLImportStorageClass()) return false; + // FIXME: support control flow guard targets. + if (CI.countOperandBundlesOfType(LLVMContext::OB_cfguardtarget)) + return false; + if (CI.isInlineAsm()) return translateInlineAsm(CI, MIRBuilder); @@ -1657,6 +1661,10 @@ if (I.countOperandBundlesOfType(LLVMContext::OB_deopt)) return false; + // FIXME: support control flow guard targets. + if (I.countOperandBundlesOfType(LLVMContext::OB_cfguardtarget)) + return false; + // FIXME: support Windows exception handling. if (!isa<LandingPadInst>(EHPadBB->front())) return false; Index: llvm/lib/CodeGen/CFGuardLongjmp.cpp =================================================================== --- llvm/lib/CodeGen/CFGuardLongjmp.cpp +++ llvm/lib/CodeGen/CFGuardLongjmp.cpp @@ -59,12 +59,12 @@ bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) { - // Skip modules for which the cfguard flag is not set + // Skip modules for which the cfguard flag is not set. if (!mdconst::extract_or_null<ConstantInt>( MF.getMMI().getModule()->getModuleFlag("cfguard"))) return false; - // Skip functions that do not have calls to _setjmp + // Skip functions that do not have calls to _setjmp. if (!MF.getFunction().callsFunctionThatReturnsTwice()) return false; @@ -75,7 +75,7 @@ for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { - // Skip instructions that are not calls to global functions + // Skip instructions that are not calls to global functions. if (!MI.isCall() || MI.getNumOperands() < 1 || !MI.getOperand(0).isGlobal()) continue; @@ -94,25 +94,20 @@ if (SetjmpCalls.empty()) return false; - // For each possible target, split the basic block after the call to setjmp. - // Ensure that the label of the second basic block will be emitted and does - // not have a private prefix. Add this label to the function's list of longjmp - // targets. + unsigned SetjmpNum = 0; + + // For each possible target, create a new symbol and insert it immediately + // after the call to setjmp. Add this symbol to the MachineFunction's list + // of longjmp targets. for (MachineInstr *Setjmp : SetjmpCalls) { - MachineBasicBlock *OldMBB = Setjmp->getParent(); - MachineBasicBlock *NewMBB = - MF.CreateMachineBasicBlock(OldMBB->getBasicBlock()); - NewMBB->setLabelIsPublic(); - NewMBB->setLabelMustBeEmitted(); - MF.insert(++OldMBB->getIterator(), NewMBB); - NewMBB->splice(NewMBB->begin(), OldMBB, - std::next(MachineBasicBlock::iterator(Setjmp)), - OldMBB->end()); - NewMBB->transferSuccessorsAndUpdatePHIs(OldMBB); - OldMBB->addSuccessor(NewMBB); - MF.addLongjmpTarget(NewMBB->getSymbol()); - CFGuardLongjmpTargets++; + SmallString<128> SymbolName; + raw_svector_ostream(SymbolName) << "$cfgsj_" << MF.getName() << SetjmpNum++; + MCSymbol *SjSymbol = MF.getContext().getOrCreateSymbol(SymbolName); + + Setjmp->setPostInstrSymbol(MF, SjSymbol); + MF.addLongjmpTarget(SjSymbol); + CFGuardLongjmpTargets++; } return true; } \ No newline at end of file Index: llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h +++ llvm/lib/CodeGen/AsmPrinter/WinCFGuard.h @@ -31,7 +31,7 @@ void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} - /// Emit the Control Flow Guard function ID table + /// Emit the Control Flow Guard function ID table. void endModule() override; /// Gather pre-function debug information. Index: llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp +++ llvm/lib/CodeGen/AsmPrinter/WinCFGuard.cpp @@ -32,11 +32,11 @@ void WinCFGuard::endFunction(const MachineFunction *MF) { - // Skip functions without any longjmp targets + // Skip functions without any longjmp targets. if (MF->getLongjmpTargets().empty()) return; - // Copy the function's longjmp targets to a module-level list + // Copy the function's longjmp targets to a module-level list. LongjmpTargets.insert(LongjmpTargets.end(), MF->getLongjmpTargets().begin(), MF->getLongjmpTargets().end()); } @@ -54,7 +54,7 @@ for (const Function *F : Functions) OS.EmitCOFFSymbolIndex(Asm->getSymbol(F)); - // Emit the symbol index of each longjmp target + // Emit the symbol index of each longjmp target. OS.SwitchSection(Asm->OutContext.getObjectFileInfo()->getGLJMPSection()); for (const MCSymbol *S : LongjmpTargets) { OS.EmitCOFFSymbolIndex(S); Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -378,7 +378,7 @@ EHTimerDescription, DWARFGroupName, DWARFGroupDescription); - // Emit tables for any value of cfguard flag (i.e. cfguard=1 or cfguard=2) + // Emit tables for any value of cfguard flag (i.e. cfguard=1 or cfguard=2). if (mdconst::extract_or_null<ConstantInt>( MMI->getModule()->getModuleFlag("cfguard"))) Handlers.emplace_back(llvm::make_unique<WinCFGuard>(this), CFGuardName, Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -133,7 +133,6 @@ kw_coldcc, kw_intel_ocl_bicc, kw_cfguard_checkcc, - kw_cfguard_dispatchcc, kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc, Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1921,7 +1921,6 @@ /// ::= 'intel_ocl_bicc' /// ::= 'coldcc' /// ::= 'cfguard_checkcc' -/// ::= 'cfguard_dispatchcc' /// ::= 'x86_stdcallcc' /// ::= 'x86_fastcallcc' /// ::= 'x86_thiscallcc' @@ -1966,7 +1965,6 @@ case lltok::kw_fastcc: CC = CallingConv::Fast; break; case lltok::kw_coldcc: CC = CallingConv::Cold; break; case lltok::kw_cfguard_checkcc: CC = CallingConv::CFGuard_Check; break; - case lltok::kw_cfguard_dispatchcc: CC = CallingConv::CFGuard_Dispatch; break; case lltok::kw_x86_stdcallcc: CC = CallingConv::X86_StdCall; break; case lltok::kw_x86_fastcallcc: CC = CallingConv::X86_FastCall; break; case lltok::kw_x86_regcallcc: CC = CallingConv::X86_RegCall; break; Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -586,7 +586,6 @@ KEYWORD(fastcc); KEYWORD(coldcc); KEYWORD(cfguard_checkcc); - KEYWORD(cfguard_dispatchcc); KEYWORD(x86_stdcallcc); KEYWORD(x86_fastcallcc); KEYWORD(x86_thiscallcc); Index: llvm/include/llvm/Transforms/CFGuard.h =================================================================== --- llvm/include/llvm/Transforms/CFGuard.h +++ llvm/include/llvm/Transforms/CFGuard.h @@ -13,13 +13,13 @@ namespace llvm { -class ModulePass; +class FunctionPass; /// Insert Control FLow Guard checks on indirect function calls. -ModulePass *createCFGuardCheckPass(); +FunctionPass *createCFGuardCheckPass(); /// Insert Control FLow Guard dispatches on indirect function calls. -ModulePass *createCFGuardDispatchPass(); +FunctionPass *createCFGuardDispatchPass(); } Index: llvm/include/llvm/Target/TargetCallingConv.td =================================================================== --- llvm/include/llvm/Target/TargetCallingConv.td +++ llvm/include/llvm/Target/TargetCallingConv.td @@ -51,6 +51,11 @@ class CCIfSwiftError<CCAction A> : CCIf<"ArgFlags.isSwiftError()", A> { } +/// CCIfCFGuardTarget - If the current argument has cfguardtarget parameter +/// attribute, apply Action A. +class CCIfCFGuardTarget<CCAction A> : CCIf<"ArgFlags.isCFGuardTarget()", A> { +} + /// CCIfConsecutiveRegs - If the current argument has InConsecutiveRegs /// parameter attribute, apply Action A. class CCIfConsecutiveRegs<CCAction A> : CCIf<"ArgFlags.isInConsecutiveRegs()", A> { Index: llvm/include/llvm/IR/LLVMContext.h =================================================================== --- llvm/include/llvm/IR/LLVMContext.h +++ llvm/include/llvm/IR/LLVMContext.h @@ -85,6 +85,7 @@ OB_deopt = 0, // "deopt" OB_funclet = 1, // "funclet" OB_gc_transition = 2, // "gc-transition" + OB_cfguardtarget = 3, // "cfguardtarget" }; /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -1039,6 +1039,11 @@ return getTagID() == LLVMContext::OB_funclet; } + /// Return true if this is a "cfguardtarget" operand bundle. + bool isCFGuardTargetOperandBundle() const { + return getTagID() == LLVMContext::OB_cfguardtarget; + } + private: /// Pointer to an entry in LLVMContextImpl::getOrInsertBundleTag. StringMapEntry<uint32_t> *Tag; Index: llvm/include/llvm/IR/CallingConv.h =================================================================== --- llvm/include/llvm/IR/CallingConv.h +++ llvm/include/llvm/IR/CallingConv.h @@ -76,17 +76,11 @@ CXX_FAST_TLS = 17, /// Special calling convention on Windows for calling the Control - /// Guard Check ICall funtion. The function take exactly one argument + /// Guard Check ICall funtion. The function takes exactly one argument /// (address of the target function) passed in the first argument register, /// and has no return value. All register values are preserved. CFGuard_Check = 18, - /// Special calling convention on Windows for calling the Control - /// Guard Dispatch ICall funtion. The address of the target function to - /// tail-call is passed in a register (RAX on X86_64 targets), and all other - /// arguments are the same as if they were calling the target function. - CFGuard_Dispatch = 19, - // Target - This is the start of the target-specific calling conventions, // e.g. fastcall and thiscall on X86. FirstTargetCC = 64, Index: llvm/include/llvm/CodeGen/TargetLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLowering.h +++ llvm/include/llvm/CodeGen/TargetLowering.h @@ -188,13 +188,14 @@ bool IsReturned : 1; bool IsSwiftSelf : 1; bool IsSwiftError : 1; + bool IsCFGuardTarget : 1; uint16_t Alignment = 0; Type *ByValType = nullptr; ArgListEntry() : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false), IsInAlloca(false), IsReturned(false), - IsSwiftSelf(false), IsSwiftError(false) {} + IsSwiftSelf(false), IsSwiftError(false), IsCFGuardTarget(false) {} void setAttributes(const CallBase *Call, unsigned ArgIdx); Index: llvm/include/llvm/CodeGen/TargetCallingConv.h =================================================================== --- llvm/include/llvm/CodeGen/TargetCallingConv.h +++ llvm/include/llvm/CodeGen/TargetCallingConv.h @@ -38,6 +38,7 @@ unsigned IsSplitEnd : 1; ///< Last part of a split unsigned IsSwiftSelf : 1; ///< Swift self parameter unsigned IsSwiftError : 1; ///< Swift error parameter + unsigned IsCFGuardTarget : 1; ///< Control Flow Guard target unsigned IsHva : 1; ///< HVA field for unsigned IsHvaStart : 1; ///< HVA structure start unsigned IsSecArgPass : 1; ///< Second argument @@ -56,8 +57,8 @@ ArgFlagsTy() : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0), IsReturned(0), IsSplit(0), IsInAlloca(0), IsSplitEnd(0), - IsSwiftSelf(0), IsSwiftError(0), IsHva(0), IsHvaStart(0), - IsSecArgPass(0), ByValAlign(0), OrigAlign(0), + IsSwiftSelf(0), IsSwiftError(0), IsCFGuardTarget(0), IsHva(0), + IsHvaStart(0), IsSecArgPass(0), ByValAlign(0), OrigAlign(0), IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), IsCopyElisionCandidate(0), IsPointer(0), ByValSize(0), PointerAddrSpace(0) { @@ -88,6 +89,9 @@ bool isSwiftError() const { return IsSwiftError; } void setSwiftError() { IsSwiftError = 1; } + bool isCFGuardTarget() const { return IsCFGuardTarget; } + void setCFGuardTarget() { IsCFGuardTarget = 1; } + bool isHva() const { return IsHva; } void setHva() { IsHva = 1; } Index: llvm/include/llvm/CodeGen/MachineBasicBlock.h =================================================================== --- llvm/include/llvm/CodeGen/MachineBasicBlock.h +++ llvm/include/llvm/CodeGen/MachineBasicBlock.h @@ -118,10 +118,6 @@ /// whether the flow just falls-through to it. bool LabelMustBeEmitted = false; - /// Indicate that this basic block's symbol will not have a private label - /// prefix, and will thus be included in the symbol table. - bool LabelIsPublic = false; - /// Indicate that this basic block is the entry block of an EH scope, i.e., /// the block that used to have a catchpad or cleanuppad instruction in the /// LLVM IR. @@ -173,12 +169,6 @@ /// its label be emitted. void setLabelMustBeEmitted() { LabelMustBeEmitted = true; } - /// Set this block to reflect that its label will not have a private prefix. - void setLabelIsPublic() { - assert((!CachedMCSymbol || LabelIsPublic == true) && "Cannot set label to public after it has been accessed."); - LabelIsPublic = true; - } - /// Return the MachineFunction containing this basic block. const MachineFunction *getParent() const { return xParent; } MachineFunction *getParent() { return xParent; } Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -438,24 +438,15 @@ - On iOS platforms, we use AAPCS-VFP calling convention. "``cfguard_checkcc``" - Windows Control Flow Guard (Check mechanism) This calling convention is used for the Control Flow Guard check function, - which can be inserted before indirect calls to check that the call target - is a valid function address. The check function has no return value, but - it will trigger an OS-level error if the address is not a valid target. - The set of registers preserved by the check function, and the register - containing the target address are architecture-specific. + calls to which can be inserted before indirect calls to check that the call + target is a valid function address. The check function has no return value, + but it will trigger an OS-level error if the address is not a valid target. + The set of registers preserved by the check function, and the register + containing the target address are architecture-specific. - - On X86_32 the target address is passed in ECX. + - On X86 the target address is passed in ECX. - On ARM the target address is passed in R0. - On Aarch64 the target address is passed in X15. -"``cfguard_dispatchcc``" - Windows Control Flow Guard (Dispatch mechanism) - This calling convention is used for the Control Flow Guard dispatch - function, which can be inserted in place of indirect calls to check - that the call target is a valid function address and then tail-call the - function. It passes the target address in the appropriate - (architecture-specific) register. All other function arguments are - passed as usual. - - - On X86-64 the target address is passed in RAX. "``cc <n>``" - Numbered convention Any calling convention may be specified by number, allowing target-specific calling conventions to be used. Target specific Index: clang/test/Driver/cl-fallback.c =================================================================== --- clang/test/Driver/cl-fallback.c +++ clang/test/Driver/cl-fallback.c @@ -2,7 +2,7 @@ // command-line option, e.g. on Mac where %s is commonly under /Users. // RUN: %clang_cl --target=i686-pc-win32 /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /GS /GS- /Gy /Gy- \ -// RUN: /Gw /Gw- /LD /LDd /EHs /EHs- /Zl /MD /MDd /MTd /MT /FImyheader.h /Zi \ +// RUN: /Gw /Gw- /guard:cf /guard:cf- /LD /LDd /EHs /EHs- /Zl /MD /MDd /MTd /MT /FImyheader.h /Zi \ // RUN: -garbage -moregarbage \ // RUN: -### -- %s 2>&1 \ // RUN: | FileCheck %s @@ -25,6 +25,7 @@ // CHECK: "/GS-" // CHECK: "/Gy-" // CHECK: "/Gw-" +// CHECK: "/guard:cf-" // CHECK: "/Z7" // CHECK: "/FImyheader.h" // CHECK: "/LD" Index: clang/lib/Driver/ToolChains/MSVC.cpp =================================================================== --- clang/lib/Driver/ToolChains/MSVC.cpp +++ clang/lib/Driver/ToolChains/MSVC.cpp @@ -416,8 +416,17 @@ } Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); - // Flags that can simply be passed through. - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_guard); + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { + // MSVC doesn't yet support the "nochecks" modifier. + CmdArgs.push_back("-guard:cf"); + } + else if (GuardArgs.equals_lower("cf-")) { + CmdArgs.push_back("-guard:cf-"); + } + } if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) { Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -5951,30 +5951,24 @@ } if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { - SmallVector<StringRef, 1> SplitArgs; - StringRef(A->getValue()).split(SplitArgs, ","); - bool Instrument = false; - bool NoChecks = false; - for (StringRef Arg : SplitArgs) { - if (Arg.equals_lower("cf")) - Instrument = true; - else if (Arg.equals_lower("cf-")) - Instrument = false; - else if (Arg.equals_lower("nochecks")) - NoChecks = true; - else if (Arg.equals_lower("nochecks-")) - NoChecks = false; - else - D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg; - } - - if (Instrument && !NoChecks) - //Emit CFG instrumentation and the table of address-taken functions. + StringRef GuardArgs = A->getValue(); + // The only valid options are "cf", "cf,nochecks", and "cf-". + if (GuardArgs.equals_lower("cf")) { + // Emit CFG instrumentation and the table of address-taken functions. CmdArgs.push_back("-cfguard"); - else if (NoChecks) - //Emit only the table of address-taken functions. + } + else if (GuardArgs.equals_lower("cf,nochecks")) { + // Emit only the table of address-taken functions. CmdArgs.push_back("-cfguard-no-checks"); + } + else if (GuardArgs.equals_lower("cf-")) { + // Do nothing, but we might want to emit a security warning in future. + } + else { + D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; + } } + } visualstudio::Compiler *Clang::getCLFallback() const { Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -486,14 +486,14 @@ if (CodeGenOpts.CodeViewGHash) { getModule().addModuleFlag(llvm::Module::Warning, "CodeViewGHash", 1); } - if (CodeGenOpts.ControlFlowGuardNoChecks) { - // Function ID tables for Control Flow Guard (cfguard=1). - getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1); - } if (CodeGenOpts.ControlFlowGuard) { // Function ID tables and checks for Control Flow Guard (cfguard=2). getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 2); } + else if (CodeGenOpts.ControlFlowGuardNoChecks) { + // Function ID tables for Control Flow Guard (cfguard=1). + getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1); + } if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) { // We don't support LTO with 2 with different StrictVTablePointers // FIXME: we could support it by stripping all the information introduced Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -497,10 +497,6 @@ def bundle__loader : Separate<["-"], "bundle_loader">; def bundle : Flag<["-"], "bundle">; def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>; -def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">, Flags<[CC1Option]>, - HelpText<"Emit Windows Control Flow Guard tables only (no checks).">; -def cfguard : Flag<["-"], "cfguard">, Flags<[CC1Option]>, - HelpText<"Emit Windows Control Flow Guard tables and checks.">; def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group<opencl_Group>, Flags<[CC1Option]>, HelpText<"OpenCL only. This option disables all optimizations. By default optimizations are enabled.">; def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, Group<opencl_Group>, Flags<[CC1Option]>, Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -399,6 +399,10 @@ Values<"a_key,b_key">; def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">; def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">; +def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">, + HelpText<"Emit Windows Control Flow Guard tables only (no checks)">; +def cfguard : Flag<["-"], "cfguard">, + HelpText<"Emit Windows Control Flow Guard tables and checks">; //===----------------------------------------------------------------------===// // Dependency Output Options
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits