Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -561,6 +561,7 @@ ATTR_KIND_SPECULATABLE = 53, ATTR_KIND_STRICT_FP = 54, ATTR_KIND_SANITIZE_HWADDRESS = 55, + ATTR_KIND_NOCF_CHECK = 56, }; enum ComdatSelectionKindCodes { Index: include/llvm/CodeGen/TargetLowering.h =================================================================== --- include/llvm/CodeGen/TargetLowering.h +++ include/llvm/CodeGen/TargetLowering.h @@ -3530,6 +3530,13 @@ virtual SDValue LowerToTLSEmulatedModel(const GlobalAddressSDNode *GA, SelectionDAG &DAG) const; + /// Expands target specific indirect branch for the case of JumpTable + /// expanasion. + virtual SDValue expandIndirectJTBranch(SDLoc dl, SDValue Value, SDValue Addr, + SelectionDAG &DAG) const { + return DAG.getNode(ISD::BRIND, dl, MVT::Other, Value, Addr); + } + // seteq(x, 0) -> truncate(srl(ctlz(zext(x)), log2(#bits))) // If we're comparing for equality to zero and isCtlzFast is true, expose the // fact that this can be implemented as a ctlz/srl pair, so that the dag Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -106,6 +106,9 @@ /// Mark the function as not returning. def NoReturn : EnumAttr<"noreturn">; +/// Disable Indirect Branch Tracking. +def NoCfCheck : EnumAttr<"nocf_check">; + /// Function doesn't unwind stack. def NoUnwind : EnumAttr<"nounwind">; Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -461,6 +461,9 @@ addFnAttr(Attribute::NoReturn); } + /// Determine if the function should not perform indirect branch tracking. + bool doesNoCfCheck() const { return hasFnAttribute(Attribute::NoCfCheck); } + /// @brief Determine if the function cannot unwind. bool doesNotThrow() const { return hasFnAttribute(Attribute::NoUnwind); Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -1831,6 +1831,9 @@ addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } + /// Determine if the call should not perform indirect branch tracking. + bool doesNoCfCheck() const { return hasFnAttr(Attribute::NoCfCheck); } + /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { @@ -3931,6 +3934,9 @@ addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } + /// Determine if the call should not perform indirect branch tracking. + bool doesNoCfCheck() const { return hasFnAttr(Attribute::NoCfCheck); } + /// Determine if the call cannot unwind. bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); } void setDoesNotThrow() { Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -648,6 +648,7 @@ KEYWORD(nonnull); KEYWORD(noredzone); KEYWORD(noreturn); + KEYWORD(nocf_check); KEYWORD(nounwind); KEYWORD(optnone); KEYWORD(optsize); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1128,6 +1128,7 @@ case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break; case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break; case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break; + case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break; case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break; case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; @@ -1465,6 +1466,7 @@ case lltok::kw_nonlazybind: case lltok::kw_noredzone: case lltok::kw_noreturn: + case lltok::kw_nocf_check: case lltok::kw_nounwind: case lltok::kw_optnone: case lltok::kw_optsize: @@ -1558,6 +1560,7 @@ case lltok::kw_nonlazybind: case lltok::kw_noredzone: case lltok::kw_noreturn: + case lltok::kw_nocf_check: case lltok::kw_nounwind: case lltok::kw_optnone: case lltok::kw_optsize: Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -199,6 +199,7 @@ kw_nonnull, kw_noredzone, kw_noreturn, + kw_nocf_check, kw_nounwind, kw_optnone, kw_optsize, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1157,6 +1157,7 @@ case Attribute::Speculatable: return 1ULL << 54; case Attribute::StrictFP: return 1ULL << 55; case Attribute::SanitizeHWAddress: return 1ULL << 56; + case Attribute::NoCfCheck: return 1ULL << 57; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; @@ -1335,6 +1336,8 @@ return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; + case bitc::ATTR_KIND_NOCF_CHECK: + return Attribute::NoCfCheck; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -635,6 +635,8 @@ return bitc::ATTR_KIND_NO_RED_ZONE; case Attribute::NoReturn: return bitc::ATTR_KIND_NO_RETURN; + case Attribute::NoCfCheck: + return bitc::ATTR_KIND_NOCF_CHECK; case Attribute::NoUnwind: return bitc::ATTR_KIND_NO_UNWIND; case Attribute::OptimizeForSize: Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3699,7 +3699,8 @@ Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, TLI.getPICJumpTableRelocBase(Table, DAG)); } - Tmp1 = DAG.getNode(ISD::BRIND, dl, MVT::Other, LD.getValue(1), Addr); + + Tmp1 = TLI.expandIndirectJTBranch(dl, LD.getValue(1), Addr, DAG); Results.push_back(Tmp1); break; } Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -299,6 +299,8 @@ return "noredzone"; if (hasAttribute(Attribute::NoReturn)) return "noreturn"; + if (hasAttribute(Attribute::NoCfCheck)) + return "nocf_check"; if (hasAttribute(Attribute::NoRecurse)) return "norecurse"; if (hasAttribute(Attribute::NoUnwind)) Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1360,6 +1360,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::NoReturn: + case Attribute::NoCfCheck: case Attribute::NoUnwind: case Attribute::NoInline: case Attribute::AlwaysInline: Index: lib/Target/X86/X86FastISel.cpp =================================================================== --- lib/Target/X86/X86FastISel.cpp +++ lib/Target/X86/X86FastISel.cpp @@ -3167,6 +3167,12 @@ CLI.CS ? dyn_cast(CLI.CS->getInstruction()) : nullptr; const Function *CalledFn = CI ? CI->getCalledFunction() : nullptr; + // Call / invoke instructions with NoCfCheck attribute require special handling. + const auto *II = + CLI.CS ? dyn_cast(CLI.CS->getInstruction()) : nullptr; + if ((CI && CI->doesNoCfCheck()) || (II && II->doesNoCfCheck())) + return false; + // Functions with no_caller_saved_registers that need special handling. if ((CI && CI->hasFnAttr("no_caller_saved_registers")) || (CalledFn && CalledFn->hasFnAttribute("no_caller_saved_registers"))) Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -75,6 +75,12 @@ /// CALL, + /// Attaches NoCfCheck (DS) prefix to the next instruction. + /// It has an incoming and outgoing token chain. + /// The node should be glued to a call instruction and be part of + /// the call instruction chain. + NOCF_CHECK, + /// This operation implements the lowering for readcyclecounter. RDTSC_DAG, @@ -1098,9 +1104,11 @@ bool lowerInterleavedStore(StoreInst *SI, ShuffleVectorInst *SVI, unsigned Factor) const override; - void finalizeLowering(MachineFunction &MF) const override; + SDValue expandIndirectJTBranch(SDLoc dl, SDValue Value, SDValue Addr, + SelectionDAG &DAG) const override; + protected: std::pair findRepresentativeClass(const TargetRegisterInfo *TRI, Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -3351,6 +3351,8 @@ const Function *Fn = CI ? CI->getCalledFunction() : nullptr; bool HasNCSR = (CI && CI->hasFnAttr("no_caller_saved_registers")) || (Fn && Fn->hasFnAttribute("no_caller_saved_registers")); + const auto *II = dyn_cast_or_null(CLI.CS.getInstruction()); + bool HasNoCfCheck = (CI && CI->doesNoCfCheck()) || (II && II->doesNoCfCheck()); if (CallConv == CallingConv::X86_INTR) report_fatal_error("X86 interrupts may not be called directly"); @@ -3750,6 +3752,11 @@ InFlag = Chain.getValue(1); } + if (HasNoCfCheck && Subtarget.hasIBT()) { + Chain = DAG.getNode(X86ISD::NOCF_CHECK, dl, NodeTys, Chain); + InFlag = Chain.getValue(1); + } + Ops.push_back(Chain); Ops.push_back(Callee); @@ -25482,6 +25489,7 @@ case X86ISD::GF2P8MULB: return "X86ISD::GF2P8MULB"; case X86ISD::GF2P8AFFINEQB: return "X86ISD::GF2P8AFFINEQB"; case X86ISD::GF2P8AFFINEINVQB: return "X86ISD::GF2P8AFFINEINVQB"; + case X86ISD::NOCF_CHECK: return "X86ISD::NOCF_CHECK"; } return nullptr; } @@ -37633,6 +37641,27 @@ TargetLoweringBase::finalizeLowering(MF); } +SDValue X86TargetLowering::expandIndirectJTBranch(SDLoc dl, SDValue Value, + SDValue Addr, + SelectionDAG &DAG) const { + const Module *M = DAG.getMachineFunction().getMMI().getModule(); + Metadata *IsCFProtectionSupported = M->getModuleFlag("cf-protection-branch"); + if (Subtarget.hasIBT() && IsCFProtectionSupported) { + // In case IBT and control-flow protection are enabled, we need to add + // NOCF_CHECK prefix SDnode before the indirect branch. + // In order to do that we chain the previous Value to NOCF_CHECK SDNode, + // then we chain and glue NOCF_CHECK SDNode to BRIND SDNode in order to make + // sure that no other SDnode is inserted between them. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SDValue Chain = DAG.getNode(X86ISD::NOCF_CHECK, dl, NodeTys, Value); + SDValue InFlag = Chain.getValue(1); + return DAG.getNode(ISD::BRIND, dl, MVT::Other, Chain, Addr, InFlag); + } + + return TargetLowering::expandIndirectJTBranch(dl, Value, Addr, DAG); +} + + /// This method query the target whether it is beneficial for dag combiner to /// promote the specified node. If true, it should return the desired promotion /// type by reference. Index: lib/Target/X86/X86IndirectBranchTracking.cpp =================================================================== --- lib/Target/X86/X86IndirectBranchTracking.cpp +++ lib/Target/X86/X86IndirectBranchTracking.cpp @@ -22,7 +22,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" using namespace llvm; @@ -55,21 +54,11 @@ /// Endbr opcode for the current machine function. unsigned int EndbrOpcode; - /// The function looks for an indirect jump terminator in MBB predecessors. - /// - /// Jump tables are generated when lowering switch-case statements or - /// setjmp/longjump functions. - /// As a result only indirect jumps use jump tables. - /// The function verifies this assumption. - /// - /// \return true if the input \p MBB has a predecessor MBB with indirect - /// branch terminator or false otherwise. - bool verifyIndirectJump(const MachineBasicBlock *MBB) const; - /// Adds a new ENDBR instruction to the begining of the MBB. /// The function will not add it if already exists. /// It will add ENDBR32 or ENDBR64 opcode, depending on the target. - void addENDBR(MachineBasicBlock &MBB) const; + /// \returns true if the ENDBR was added and false otherwise. + bool addENDBR(MachineBasicBlock &MBB) const; }; } // end anonymous namespace @@ -80,17 +69,7 @@ return new X86IndirectBranchTrackingPass(); } -bool X86IndirectBranchTrackingPass::verifyIndirectJump( - const MachineBasicBlock *MBB) const { - for (auto &PredMBB : MBB->predecessors()) - for (auto &TermI : PredMBB->terminators()) - if (TermI.isIndirectBranch()) - return true; - - return false; -} - -void X86IndirectBranchTrackingPass::addENDBR(MachineBasicBlock &MBB) const { +bool X86IndirectBranchTrackingPass::addENDBR(MachineBasicBlock &MBB) const { assert(TII && "Target instruction info was not initialized"); assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) && "Unexpected Endbr opcode"); @@ -101,13 +80,16 @@ if (MI == MBB.end() || EndbrOpcode != MI->getOpcode()) { BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(EndbrOpcode)); NumEndBranchAdded++; + return true; } + + return false; } bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) { const X86Subtarget &SubTarget = MF.getSubtarget(); - // Make sure that the target supports ENDBR instruction. + // Make sure that the target supports IBT instruction. if (!SubTarget.hasIBT()) return false; @@ -124,40 +106,20 @@ EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32; // Non-internal function or function whose address was taken, can be - // invoked through indirect calls. Mark the first BB with ENDBR instruction. - // TODO: Do not add ENDBR instruction in case notrack attribute is used. - if (MF.getFunction().hasAddressTaken() || - !MF.getFunction().hasLocalLinkage()) { + // accessed through indirect calls. Mark the first BB with ENDBR instruction + // unless nocf_check attribute is used. + if ((MF.getFunction().hasAddressTaken() || + !MF.getFunction().hasLocalLinkage()) && + !MF.getFunction().doesNoCfCheck()) { auto MBB = MF.begin(); - addENDBR(*MBB); - Changed = true; + Changed |= addENDBR(*MBB); } - for (auto &MBB : MF) { - // Find all basic blocks that thier address was taken (for example + for (auto &MBB : MF) + // Find all basic blocks that their address was taken (for example // in the case of indirect jump) and add ENDBR instruction. - if (MBB.hasAddressTaken()) { - addENDBR(MBB); - Changed = true; - } - } - - // Adds ENDBR instructions to MBB destinations of the jump table. - // TODO: In case of more than 50 destinations, do not add ENDBR and - // instead add DS_PREFIX. - if (MachineJumpTableInfo *JTI = MF.getJumpTableInfo()) { - for (const auto &JT : JTI->getJumpTables()) { - for (auto *MBB : JT.MBBs) { - // This assert verifies the assumption that this MBB has an indirect - // jump terminator in one of its predecessor. - assert(verifyIndirectJump(MBB) && - "The MBB is not the destination of an indirect jump"); - - addENDBR(*MBB); - Changed = true; - } - } - } + if (MBB.hasAddressTaken()) + Changed |= addENDBR(MBB); return Changed; } Index: lib/Target/X86/X86InstrInfo.td =================================================================== --- lib/Target/X86/X86InstrInfo.td +++ lib/Target/X86/X86InstrInfo.td @@ -196,6 +196,9 @@ [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; +def X86nocf_check : SDNode<"X86ISD::NOCF_CHECK", SDTX86Void, + [SDNPHasChain, SDNPOutGlue, SDNPSideEffect]>; + def X86rep_stos: SDNode<"X86ISD::REP_STOS", SDTX86RepStr, [SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore]>; def X86rep_movs: SDNode<"X86ISD::REP_MOVS", SDTX86RepStr, Index: lib/Target/X86/X86InstrSystem.td =================================================================== --- lib/Target/X86/X86InstrSystem.td +++ lib/Target/X86/X86InstrSystem.td @@ -541,6 +541,28 @@ def ENDBR32 : I<0x1E, MRM_FB, (outs), (ins), "endbr32", []>, XS; } // HasIBT +def X86nocf_check_calljmp : PatFrag<(ops), (X86nocf_check), [{ + if (!N->hasOneUse() && !N->getGluedUser()) + return false; + + unsigned Opcode = N->use_begin()->getMachineOpcode(); + switch (Opcode) { + default: + return false; + case X86::CALL16r: case X86::CALL16m: + case X86::CALL32r: case X86::CALL32m: + case X86::CALL64r: case X86::CALL64m: + case X86::JMP16r: case X86::JMP16m: + case X86::JMP32r: case X86::JMP32m: + case X86::JMP64r: case X86::JMP64m: + return true; + } +}]>; + +// Lower NOCF_CHECK to DS_PREFIX if it is used by an indirect call/jmp. +let Predicates = [HasIBT] in + def : Pat<(X86nocf_check_calljmp), (DS_PREFIX)>; + //===----------------------------------------------------------------------===// // XSAVE instructions let SchedRW = [WriteSystem] in { Index: lib/Transforms/IPO/ForceFunctionAttrs.cpp =================================================================== --- lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -42,6 +42,7 @@ .Case("nonlazybind", Attribute::NonLazyBind) .Case("noredzone", Attribute::NoRedZone) .Case("noreturn", Attribute::NoReturn) + .Case("nocf_check", Attribute::NoCfCheck) .Case("norecurse", Attribute::NoRecurse) .Case("nounwind", Attribute::NoUnwind) .Case("optnone", Attribute::OptimizeNone) Index: test/CodeGen/X86/indirect-branch-tracking.ll =================================================================== --- test/CodeGen/X86/indirect-branch-tracking.ll +++ test/CodeGen/X86/indirect-branch-tracking.ll @@ -1,10 +1,11 @@ -; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86_64 -; RUN: llc -mtriple=i386-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86 +; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86_64 +; RUN: llc -mtriple=i386-unknown-unknown -mattr=+ibt < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86 +; RUN: llc -mtriple i386-windows-gnu -mattr=+ibt -exception-model sjlj < %s | FileCheck %s --check-prefix=SJLJ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Test1 ;; ----- -;; Checks ENDBR insertion in case of indirect branch IR instruction. +;; Checks DS_PREFIX insertion in case of switch case statement. ;; Also since the function is not internal, make sure that endbr32/64 was ;; added at the beginning of the function. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -43,25 +44,10 @@ ; ALL-LABEL: test2 ; X86_64: endbr64 ; X86: endbr32 -; ALL: jmp{{q|l}} * -; ALL: .LBB1_2: -; X86_64-NEXT: endbr64 -; X86-NEXT: endbr32 -; ALL: .LBB1_7: +; ALL: ds +; ALL-NEXT: jmp{{q|l}} * ; X86_64-NOT: endbr64 ; X86-NOT: endbr32 -; ALL: .LBB1_3: -; X86_64-NEXT: endbr64 -; X86-NEXT: endbr32 -; ALL: .LBB1_4: -; X86_64-NEXT: endbr64 -; X86-NEXT: endbr32 -; ALL: .LBB1_5: -; X86_64-NEXT: endbr64 -; X86-NEXT: endbr32 -; ALL: .LBB1_6: -; X86_64-NEXT: endbr64 -; X86-NEXT: endbr32 entry: %retval = alloca i32, align 4 %a.addr = alloca i32, align 4 @@ -198,3 +184,38 @@ ; X86: endbr32 ret i32 1 } + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Test8 +;; ----- +;; Checks that NO TRACK prefix is not added for indirect jumps to a jump- +;; table that was created for SJLJ dispatch. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +declare void @_Z20function_that_throwsv() +declare i32 @__gxx_personality_sj0(...) +declare i8* @__cxa_begin_catch(i8*) +declare void @__cxa_end_catch() + +define void @test8() personality i8* bitcast (i32 (...)* @__gxx_personality_sj0 to i8*) { +;SJLJ-LABEL: test8 +;SJLJ-NOT: ds +entry: + invoke void @_Z20function_that_throwsv() + to label %try.cont unwind label %lpad + +lpad: + %0 = landingpad { i8*, i32 } + catch i8* null + %1 = extractvalue { i8*, i32 } %0, 0 + %2 = tail call i8* @__cxa_begin_catch(i8* %1) + tail call void @__cxa_end_catch() + br label %try.cont + +try.cont: + ret void +} + +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"cf-protection-branch", i32 1} \ No newline at end of file Index: test/CodeGen/X86/nocf_check.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/nocf_check.ll @@ -0,0 +1,47 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; These tests verify the handling of ''nocf_check'' attribute by the backend.;; +;; The file was generated using the following C code: ;; +;; ;; +;; void __attribute__((nocf_check)) NoCfCheckFunc(void) {} ;; +;; ;; +;; typedef void(*FuncPointer)(void); ;; +;; void NoCfCheckCall(FuncPointer f) { ;; +;; __attribute__((nocf_check)) FuncPointer p = f; ;; +;; (*p)(); ;; +;; } ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Make sure that a function with ''nocf_check'' attribute is not instrumented +; with endbr instruction at the beginning. +define void @NoCfCheckFunc() #0 { +; CHECK-LABEL: NoCfCheckFunc +; CHECK-NOT: endbr64 +; CHECK: retq +entry: + ret void +} + +; Make sure that DS prefix is added before a call with ''nocf_check'' attribute. +define void @NoCfCheckCall(void ()* %f) { +; CHECK-LABEL: NoCfCheckCall +; CHECK: ds +; CHECK: call +entry: + %f.addr = alloca void ()*, align 4 + %p = alloca void ()*, align 4 + store void ()* %f, void ()** %f.addr, align 4 + %0 = load void ()*, void ()** %f.addr, align 4 + store void ()* %0, void ()** %p, align 4 + %1 = load void ()*, void ()** %p, align 4 + call void %1() #1 + ret void +} + +attributes #0 = { noinline nocf_check nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nocf_check } + +!llvm.module.flags = !{!0} + +!0 = !{i32 4, !"cf-protection-branch", i32 1}