llvm.org GIT mirror llvm / 10c992c
[X86] Added support for nocf_check attribute for indirect Branch Tracking X86 Supports Indirect Branch Tracking (IBT) as part of Control-Flow Enforcement Technology (CET). IBT instruments ENDBR instructions used to specify valid targets of indirect call / jmp. The `nocf_check` attribute has two roles in the context of X86 IBT technology: 1. Appertains to a function - do not add ENDBR instruction at the beginning of the function. 2. Appertains to a function pointer - do not track the target function of this pointer by adding nocf_check prefix to the indirect-call instruction. This patch implements `nocf_check` context for Indirect Branch Tracking. It also auto generates `nocf_check` prefixes before indirect branchs to jump tables that are guarded by range checks. Differential Revision: https://reviews.llvm.org/D41879 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@327767 91177308-0d34-0410-b5e6-96231b3b80d8 Oren Ben Simhon 1 year, 8 months ago
34 changed file(s) with 303 addition(s) and 77 deletion(s). Raw diff Collapse all Expand all
8888 "uwtable",
8989 "zeroext",
9090 "cold",
91 "nocf_check"
9192 }
9293
9394 for _, name := range attrTests {
10531053 * code 53: ``speculatable``
10541054 * code 54: ``strictfp``
10551055 * code 55: ``sanitize_hwaddress``
1056 * code 56: ``nocf_check``
10561057
10571058 .. note::
10581059 The ``allocsize`` attribute has a special encoding for its arguments. Its two
16981698 show that no exceptions passes by it. This is normally the case for
16991699 the ELF x86-64 abi, but it can be disabled for some compilation
17001700 units.
1701 ``nocf_check``
1702 This attribute indicates that no control-flow check will be perfomed on
1703 the attributed entity. It disables -fcf-protection=<> for a specific
1704 entity to fine grain the HW control flow protection mechanism. The flag
1705 is target independant and currently appertains to a function or function
1706 pointer.
17011707
17021708 .. _glattrs:
17031709
586586 ATTR_KIND_SPECULATABLE = 53,
587587 ATTR_KIND_STRICT_FP = 54,
588588 ATTR_KIND_SANITIZE_HWADDRESS = 55,
589 ATTR_KIND_NOCF_CHECK = 56,
589590 };
590591
591592 enum ComdatSelectionKindCodes {
35833583 virtual SDValue LowerToTLSEmulatedModel(const GlobalAddressSDNode *GA,
35843584 SelectionDAG &DAG) const;
35853585
3586 /// Expands target specific indirect branch for the case of JumpTable
3587 /// expanasion.
3588 virtual SDValue expandIndirectJTBranch(const SDLoc& dl, SDValue Value, SDValue Addr,
3589 SelectionDAG &DAG) const {
3590 return DAG.getNode(ISD::BRIND, dl, MVT::Other, Value, Addr);
3591 }
3592
35863593 // seteq(x, 0) -> truncate(srl(ctlz(zext(x)), log2(#bits)))
35873594 // If we're comparing for equality to zero and isCtlzFast is true, expose the
35883595 // fact that this can be implemented as a ctlz/srl pair, so that the dag
104104
105105 /// Mark the function as not returning.
106106 def NoReturn : EnumAttr<"noreturn">;
107
108 /// Disable Indirect Branch Tracking.
109 def NoCfCheck : EnumAttr<"nocf_check">;
107110
108111 /// Function doesn't unwind stack.
109112 def NoUnwind : EnumAttr<"nounwind">;
493493 addFnAttr(Attribute::NoReturn);
494494 }
495495
496 /// Determine if the function should not perform indirect branch tracking.
497 bool doesNoCfCheck() const { return hasFnAttribute(Attribute::NoCfCheck); }
498
496499 /// @brief Determine if the function cannot unwind.
497500 bool doesNotThrow() const {
498501 return hasFnAttribute(Attribute::NoUnwind);
17941794 addAttribute(AttributeList::FunctionIndex, Attribute::NoReturn);
17951795 }
17961796
1797 /// Determine if the call should not perform indirect branch tracking.
1798 bool doesNoCfCheck() const { return hasFnAttr(Attribute::NoCfCheck); }
1799
17971800 /// Determine if the call cannot unwind.
17981801 bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); }
17991802 void setDoesNotThrow() {
38293832 static InvokeInst *Create(InvokeInst *II, ArrayRef Bundles,
38303833 Instruction *InsertPt = nullptr);
38313834
3832
3833
3835 /// Determine if the call should not perform indirect branch tracking.
3836 bool doesNoCfCheck() const { return hasFnAttr(Attribute::NoCfCheck); }
3837
3838 /// Determine if the call cannot unwind.
3839 bool doesNotThrow() const { return hasFnAttr(Attribute::NoUnwind); }
3840 void setDoesNotThrow() {
3841 addAttribute(AttributeList::FunctionIndex, Attribute::NoUnwind);
3842 }
3843
38343844 /// Return the function called, or null if this is an
38353845 /// indirect function invocation.
38363846 ///
647647 KEYWORD(nonnull);
648648 KEYWORD(noredzone);
649649 KEYWORD(noreturn);
650 KEYWORD(nocf_check);
650651 KEYWORD(nounwind);
651652 KEYWORD(optnone);
652653 KEYWORD(optsize);
11301130 case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break;
11311131 case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break;
11321132 case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
1133 case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
11331134 case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
11341135 case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
11351136 case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break;
14671468 case lltok::kw_nonlazybind:
14681469 case lltok::kw_noredzone:
14691470 case lltok::kw_noreturn:
1471 case lltok::kw_nocf_check:
14701472 case lltok::kw_nounwind:
14711473 case lltok::kw_optnone:
14721474 case lltok::kw_optsize:
15601562 case lltok::kw_nonlazybind:
15611563 case lltok::kw_noredzone:
15621564 case lltok::kw_noreturn:
1565 case lltok::kw_nocf_check:
15631566 case lltok::kw_nounwind:
15641567 case lltok::kw_optnone:
15651568 case lltok::kw_optsize:
198198 kw_nonnull,
199199 kw_noredzone,
200200 kw_noreturn,
201 kw_nocf_check,
201202 kw_nounwind,
202203 kw_optnone,
203204 kw_optsize,
11591159 case Attribute::Speculatable: return 1ULL << 54;
11601160 case Attribute::StrictFP: return 1ULL << 55;
11611161 case Attribute::SanitizeHWAddress: return 1ULL << 56;
1162 case Attribute::NoCfCheck: return 1ULL << 57;
11621163 case Attribute::Dereferenceable:
11631164 llvm_unreachable("dereferenceable attribute not supported in raw format");
11641165 break;
13371338 return Attribute::NoRedZone;
13381339 case bitc::ATTR_KIND_NO_RETURN:
13391340 return Attribute::NoReturn;
1341 case bitc::ATTR_KIND_NOCF_CHECK:
1342 return Attribute::NoCfCheck;
13401343 case bitc::ATTR_KIND_NO_UNWIND:
13411344 return Attribute::NoUnwind;
13421345 case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE:
637637 return bitc::ATTR_KIND_NO_RED_ZONE;
638638 case Attribute::NoReturn:
639639 return bitc::ATTR_KIND_NO_RETURN;
640 case Attribute::NoCfCheck:
641 return bitc::ATTR_KIND_NOCF_CHECK;
640642 case Attribute::NoUnwind:
641643 return bitc::ATTR_KIND_NO_UNWIND;
642644 case Attribute::OptimizeForSize:
37053705 Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr,
37063706 TLI.getPICJumpTableRelocBase(Table, DAG));
37073707 }
3708 Tmp1 = DAG.getNode(ISD::BRIND, dl, MVT::Other, LD.getValue(1), Addr);
3708
3709 Tmp1 = TLI.expandIndirectJTBranch(dl, LD.getValue(1), Addr, DAG);
37093710 Results.push_back(Tmp1);
37103711 break;
37113712 }
298298 return "noredzone";
299299 if (hasAttribute(Attribute::NoReturn))
300300 return "noreturn";
301 if (hasAttribute(Attribute::NoCfCheck))
302 return "nocf_check";
301303 if (hasAttribute(Attribute::NoRecurse))
302304 return "norecurse";
303305 if (hasAttribute(Attribute::NoUnwind))
14031403 static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
14041404 switch (Kind) {
14051405 case Attribute::NoReturn:
1406 case Attribute::NoCfCheck:
14061407 case Attribute::NoUnwind:
14071408 case Attribute::NoInline:
14081409 case Attribute::AlwaysInline:
23522352 .Cases("acquire", "release", isParsingIntelSyntax())
23532353 .Default(false);
23542354
2355 auto isLockRepeatPrefix = [](StringRef N) {
2355 auto isLockRepeatNtPrefix = [](StringRef N) {
23562356 return StringSwitch(N)
2357 .Cases("lock", "rep", "repe", "repz", "repne", "repnz", true)
2357 .Cases("lock", "rep", "repe", "repz", "repne", "repnz", "notrack", true)
23582358 .Default(false);
23592359 };
23602360
23612361 bool CurlyAsEndOfStatement = false;
23622362
23632363 unsigned Flags = X86::IP_NO_PREFIX;
2364 while (isLockRepeatPrefix(Name.lower())) {
2364 while (isLockRepeatNtPrefix(Name.lower())) {
23652365 unsigned Prefix =
23662366 StringSwitch(Name)
23672367 .Cases("lock", "lock", X86::IP_HAS_LOCK)
23682368 .Cases("rep", "repe", "repz", X86::IP_HAS_REPEAT)
23692369 .Cases("repne", "repnz", X86::IP_HAS_REPEAT_NE)
2370 .Cases("notrack", "notrack", X86::IP_HAS_NOTRACK)
23702371 .Default(X86::IP_NO_PREFIX); // Invalid prefix (impossible)
23712372 Flags |= Prefix;
23722373 if (getLexer().is(AsmToken::EndOfStatement)) {
5252 unsigned Flags = MI->getFlags();
5353 if ((TSFlags & X86II::LOCK) || (Flags & X86::IP_HAS_LOCK))
5454 OS << "\tlock\t";
55
56 if ((TSFlags & X86II::NOTRACK) || (Flags & X86::IP_HAS_NOTRACK))
57 OS << "\tnotrack\t";
5558
5659 if (Flags & X86::IP_HAS_REPEAT_NE)
5760 OS << "\trepne\t";
4747 OS << "\trepne\t";
4848 else if (Flags & X86::IP_HAS_REPEAT)
4949 OS << "\trep\t";
50
51 if ((TSFlags & X86II::NOTRACK) || (Flags & X86::IP_HAS_NOTRACK))
52 OS << "\tnotrack\t";
5053
5154 printInstruction(MI, OS);
5255
5959 IP_HAS_REPEAT_NE = 4,
6060 IP_HAS_REPEAT = 8,
6161 IP_HAS_LOCK = 16,
62 NO_SCHED_INFO = 32 // Don't add sched comment to the current instr because
63 // it was already added
62 NO_SCHED_INFO = 32, // Don't add sched comment to the current instr because
63 // it was already added
64 IP_HAS_NOTRACK = 64
6465 };
6566 } // end namespace X86;
6667
571572
572573 /// Explicitly specified rounding control
573574 EVEX_RCShift = Has3DNow0F0FOpcodeShift + 1,
574 EVEX_RC = 1ULL << EVEX_RCShift
575 EVEX_RC = 1ULL << EVEX_RCShift,
576
577 // NOTRACK prefix
578 NoTrackShift = EVEX_RCShift + 1,
579 NOTRACK = 1ULL << NoTrackShift
575580 };
576581
577582 // getBaseOpcodeFor - This function returns the "base" X86 opcode for the
11331133 if (TSFlags & X86II::LOCK || MI.getFlags() & X86::IP_HAS_LOCK)
11341134 EmitByte(0xF0, CurByte, OS);
11351135
1136 // Emit the NOTRACK opcode prefix.
1137 if (TSFlags & X86II::NOTRACK || MI.getFlags() & X86::IP_HAS_NOTRACK)
1138 EmitByte(0x3E, CurByte, OS);
1139
11361140 switch (TSFlags & X86II::OpPrefixMask) {
11371141 case X86II::PD: // 66
11381142 EmitByte(0x66, CurByte, OS);
31733173 CLI.CS ? dyn_cast(CLI.CS->getInstruction()) : nullptr;
31743174 const Function *CalledFn = CI ? CI->getCalledFunction() : nullptr;
31753175
3176 // Call / invoke instructions with NoCfCheck attribute require special
3177 // handling.
3178 const auto *II =
3179 CLI.CS ? dyn_cast(CLI.CS->getInstruction()) : nullptr;
3180 if ((CI && CI->doesNoCfCheck()) || (II && II->doesNoCfCheck()))
3181 return false;
3182
31763183 // Functions with no_caller_saved_registers that need special handling.
31773184 if ((CI && CI->hasFnAttr("no_caller_saved_registers")) ||
31783185 (CalledFn && CalledFn->hasFnAttribute("no_caller_saved_registers")))
34143414 const Function *Fn = CI ? CI->getCalledFunction() : nullptr;
34153415 bool HasNCSR = (CI && CI->hasFnAttr("no_caller_saved_registers")) ||
34163416 (Fn && Fn->hasFnAttribute("no_caller_saved_registers"));
3417 const auto *II = dyn_cast_or_null(CLI.CS.getInstruction());
3418 bool HasNoCfCheck =
3419 (CI && CI->doesNoCfCheck()) || (II && II->doesNoCfCheck());
3420 const Module *M = MF.getMMI().getModule();
3421 Metadata *IsCFProtectionSupported = M->getModuleFlag("cf-protection-branch");
34173422
34183423 if (CallConv == CallingConv::X86_INTR)
34193424 report_fatal_error("X86 interrupts may not be called directly");
38973902 return DAG.getNode(X86ISD::TC_RETURN, dl, NodeTys, Ops);
38983903 }
38993904
3900 Chain = DAG.getNode(X86ISD::CALL, dl, NodeTys, Ops);
3905 if (HasNoCfCheck && IsCFProtectionSupported) {
3906 Chain = DAG.getNode(X86ISD::NT_CALL, dl, NodeTys, Ops);
3907 } else {
3908 Chain = DAG.getNode(X86ISD::CALL, dl, NodeTys, Ops);
3909 }
39013910 InFlag = Chain.getValue(1);
39023911
39033912 // Create the CALLSEQ_END node.
2585125860 case X86ISD::GF2P8MULB: return "X86ISD::GF2P8MULB";
2585225861 case X86ISD::GF2P8AFFINEQB: return "X86ISD::GF2P8AFFINEQB";
2585325862 case X86ISD::GF2P8AFFINEINVQB: return "X86ISD::GF2P8AFFINEINVQB";
25863 case X86ISD::NT_CALL: return "X86ISD::NT_CALL";
25864 case X86ISD::NT_BRIND: return "X86ISD::NT_BRIND";
2585425865 }
2585525866 return nullptr;
2585625867 }
3870838719 TargetLoweringBase::finalizeLowering(MF);
3870938720 }
3871038721
38722 SDValue X86TargetLowering::expandIndirectJTBranch(const SDLoc& dl,
38723 SDValue Value, SDValue Addr,
38724 SelectionDAG &DAG) const {
38725 const Module *M = DAG.getMachineFunction().getMMI().getModule();
38726 Metadata *IsCFProtectionSupported = M->getModuleFlag("cf-protection-branch");
38727 if (IsCFProtectionSupported) {
38728 // In case control-flow branch protection is enabled, we need to add
38729 // notrack prefix to the indirect branch.
38730 // In order to do that we create NT_BRIND SDNode.
38731 // Upon ISEL, the pattern will convert it to jmp with NoTrack prefix.
38732 return DAG.getNode(X86ISD::NT_BRIND, dl, MVT::Other, Value, Addr);
38733 }
38734
38735 return TargetLowering::expandIndirectJTBranch(dl, Value, Addr, DAG);
38736 }
38737
3871138738 /// This method query the target whether it is beneficial for dag combiner to
3871238739 /// promote the specified node. If true, it should return the desired promotion
3871338740 /// type by reference.
7474 ///
7575 CALL,
7676
77 /// Same as call except it adds the NoTrack prefix.
78 NT_CALL,
79
7780 /// This operation implements the lowering for readcyclecounter.
7881 RDTSC_DAG,
7982
120123 /// condition code, and operand 3 is the flag operand produced by a CMP
121124 /// or TEST instruction.
122125 BRCOND,
126
127 /// BRIND node with NoTrack prefix. Operand 0 is the chain operand and
128 /// operand 1 is the target address.
129 NT_BRIND,
123130
124131 /// Return with a flag operand. Operand 0 is the chain operand, operand
125132 /// 1 is the number of bytes of stack to pop.
11131120 bool lowerInterleavedStore(StoreInst *SI, ShuffleVectorInst *SVI,
11141121 unsigned Factor) const override;
11151122
1116
11171123 void finalizeLowering(MachineFunction &MF) const override;
1124
1125 SDValue expandIndirectJTBranch(const SDLoc& dl, SDValue Value,
1126 SDValue Addr, SelectionDAG &DAG)
1127 const override;
11181128
11191129 protected:
11201130 std::pair
2121 #include "llvm/ADT/Statistic.h"
2222 #include "llvm/CodeGen/MachineFunctionPass.h"
2323 #include "llvm/CodeGen/MachineInstrBuilder.h"
24 #include "llvm/CodeGen/MachineJumpTableInfo.h"
2524 #include "llvm/CodeGen/MachineModuleInfo.h"
2625
2726 using namespace llvm;
5756 /// Adds a new ENDBR instruction to the begining of the MBB.
5857 /// The function will not add it if already exists.
5958 /// It will add ENDBR32 or ENDBR64 opcode, depending on the target.
60 void addENDBR(MachineBasicBlock &MBB) const;
59 /// \returns true if the ENDBR was added and false otherwise.
60 bool addENDBR(MachineBasicBlock &MBB) const;
6161 };
6262
6363 } // end anonymous namespace
6868 return new X86IndirectBranchTrackingPass();
6969 }
7070
71 void X86IndirectBranchTrackingPass::addENDBR(MachineBasicBlock &MBB) const {
71 bool X86IndirectBranchTrackingPass::addENDBR(MachineBasicBlock &MBB) const {
7272 assert(TII && "Target instruction info was not initialized");
7373 assert((X86::ENDBR64 == EndbrOpcode || X86::ENDBR32 == EndbrOpcode) &&
7474 "Unexpected Endbr opcode");
7979 if (MI == MBB.end() || EndbrOpcode != MI->getOpcode()) {
8080 BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(EndbrOpcode));
8181 NumEndBranchAdded++;
82 return true;
8283 }
84
85 return false;
8386 }
8487
8588 bool X86IndirectBranchTrackingPass::runOnMachineFunction(MachineFunction &MF) {
8689 const X86Subtarget &SubTarget = MF.getSubtarget();
8790
88 // Make sure that the target supports ENDBR instruction.
91 // Make sure that the target supports IBT instruction.
8992 if (!SubTarget.hasIBT())
9093 return false;
9194
102105 EndbrOpcode = SubTarget.is64Bit() ? X86::ENDBR64 : X86::ENDBR32;
103106
104107 // Non-internal function or function whose address was taken, can be
105 // invoked through indirect calls. Mark the first BB with ENDBR instruction.
106 // TODO: Do not add ENDBR instruction in case notrack attribute is used.
107 if (MF.getFunction().hasAddressTaken() ||
108 !MF.getFunction().hasLocalLinkage()) {
108 // accessed through indirect calls. Mark the first BB with ENDBR instruction
109 // unless nocf_check attribute is used.
110 if ((MF.getFunction().hasAddressTaken() ||
111 !MF.getFunction().hasLocalLinkage()) &&
112 !MF.getFunction().doesNoCfCheck()) {
109113 auto MBB = MF.begin();
110 addENDBR(*MBB);
111 Changed = true;
114 Changed |= addENDBR(*MBB);
112115 }
113116
114 for (auto &MBB : MF) {
115 // Find all basic blocks that thier address was taken (for example
117 for (auto &MBB : MF)
118 // Find all basic blocks that their address was taken (for example
116119 // in the case of indirect jump) and add ENDBR instruction.
117 if (MBB.hasAddressTaken()) {
118 addENDBR(MBB);
119 Changed = true;
120 }
121 }
122
123 // Adds ENDBR instructions to MBB destinations of the jump table.
124 // TODO: In case of more than 50 destinations, do not add ENDBR and
125 // instead add DS_PREFIX.
126 if (MachineJumpTableInfo *JTI = MF.getJumpTableInfo()) {
127 for (const auto &JT : JTI->getJumpTables()) {
128 for (auto *MBB : JT.MBBs) {
129 // This assert verifies the assumption that this MBB has an indirect
130 // jump terminator in one of its predecessor.
131 // Jump tables are generated when lowering switch-case statements or
132 // setjmp/longjump functions. As a result only indirect jumps use jump
133 // tables.
134 #ifndef NDEBUG
135 bool hasIndirectJumpTerm = false;
136 for (auto &PredMBB : MBB->predecessors())
137 for (auto &TermI : PredMBB->terminators())
138 if (TermI.isIndirectBranch())
139 hasIndirectJumpTerm = true;
140 assert(hasIndirectJumpTerm &&
141 "The MBB is not the destination of an indirect jump");
142 (void)hasIndirectJumpTerm;
143 #endif
144 addENDBR(*MBB);
145 Changed = true;
146 }
147 }
148 }
120 if (MBB.hasAddressTaken())
121 Changed |= addENDBR(MBB);
149122
150123 return Changed;
151124 }
152152 [(brind (loadi64 addr:$dst))], IIC_JMP_MEM>,
153153 Requires<[In64BitMode]>, Sched<[WriteJumpLd]>;
154154
155 let isCodeGenOnly = 1, Predicates = [HasIBT] in {
156 def JMP16r_NT : I<0xFF, MRM4r, (outs), (ins GR16 : $dst), "jmp{w}\t{*}$dst",
157 [(X86NoTrackBrind GR16 : $dst)], IIC_JMP_REG>, Requires<[Not64BitMode]>,
158 OpSize16, Sched<[WriteJump]>, NOTRACK;
159
160 def JMP16m_NT : I<0xFF, MRM4m, (outs), (ins i16mem : $dst), "jmp{w}\t{*}$dst",
161 [(X86NoTrackBrind (loadi16 addr : $dst))], IIC_JMP_MEM>,
162 Requires<[Not64BitMode]>, OpSize16, Sched<[WriteJumpLd]>, NOTRACK;
163
164 def JMP32r_NT : I<0xFF, MRM4r, (outs), (ins GR32 : $dst), "jmp{l}\t{*}$dst",
165 [(X86NoTrackBrind GR32 : $dst)], IIC_JMP_REG>, Requires<[Not64BitMode]>,
166 OpSize32, Sched<[WriteJump]>, NOTRACK;
167 def JMP32m_NT : I<0xFF, MRM4m, (outs), (ins i32mem : $dst), "jmp{l}\t{*}$dst",
168 [(X86NoTrackBrind (loadi32 addr : $dst))], IIC_JMP_MEM>,
169 Requires<[Not64BitMode]>, OpSize32, Sched<[WriteJumpLd]>, NOTRACK;
170
171 def JMP64r_NT : I<0xFF, MRM4r, (outs), (ins GR64 : $dst), "jmp{q}\t{*}$dst",
172 [(X86NoTrackBrind GR64 : $dst)], IIC_JMP_REG>, Requires<[In64BitMode]>,
173 Sched<[WriteJump]>, NOTRACK;
174 def JMP64m_NT : I<0xFF, MRM4m, (outs), (ins i64mem : $dst), "jmp{q}\t{*}$dst",
175 [(X86NoTrackBrind(loadi64 addr : $dst))], IIC_JMP_MEM>,
176 Requires<[In64BitMode]>, Sched<[WriteJumpLd]>, NOTRACK;
177 }
178
155179 let Predicates = [Not64BitMode] in {
156180 def FARJMP16i : Iseg16<0xEA, RawFrmImm16, (outs),
157181 (ins i16imm:$off, i16imm:$seg),
173197 "{l}jmp{l}\t{*}$dst", [], IIC_JMP_FAR_MEM>, OpSize32,
174198 Sched<[WriteJumpLd]>;
175199 }
176
177200
178201 // Loop instructions
179202 let SchedRW = [WriteJump] in {
218241 Requires<[Not64BitMode,FavorMemIndirectCall,NotUseRetpoline]>,
219242 Sched<[WriteJumpLd]>;
220243
244 let isCodeGenOnly = 1, Predicates = [HasIBT] in {
245 def CALL16r_NT : I<0xFF, MRM2r, (outs), (ins GR16 : $dst),
246 "call{w}\t{*}$dst",[(X86NoTrackCall GR16 : $dst)], IIC_CALL_RI>,
247 OpSize16, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK;
248 def CALL16m_NT : I<0xFF, MRM2m, (outs), (ins i16mem : $dst),
249 "call{w}\t{*}$dst",[(X86NoTrackCall(loadi16 addr : $dst))],
250 IIC_CALL_MEM>, OpSize16,
251 Requires<[Not64BitMode,FavorMemIndirectCall]>,
252 Sched<[WriteJumpLd]>, NOTRACK;
253 def CALL32r_NT : I<0xFF, MRM2r, (outs), (ins GR32 : $dst),
254 "call{l}\t{*}$dst",[(X86NoTrackCall GR32 : $dst)], IIC_CALL_RI>,
255 OpSize32, Requires<[Not64BitMode]>, Sched<[WriteJump]>, NOTRACK;
256 def CALL32m_NT : I<0xFF, MRM2m, (outs), (ins i32mem : $dst),
257 "call{l}\t{*}$dst",[(X86NoTrackCall(loadi32 addr : $dst))],
258 IIC_CALL_MEM>, OpSize32,
259 Requires<[Not64BitMode,FavorMemIndirectCall]>,
260 Sched<[WriteJumpLd]>, NOTRACK;
261 }
262
221263 let Predicates = [Not64BitMode] in {
222264 def FARCALL16i : Iseg16<0x9A, RawFrmImm16, (outs),
223265 (ins i16imm:$off, i16imm:$seg),
305347 Requires<[In64BitMode,FavorMemIndirectCall,
306348 NotUseRetpoline]>;
307349
350 let isCodeGenOnly = 1, Predicates = [HasIBT] in{
351 def CALL64r_NT : I<0xFF, MRM2r, (outs), (ins GR64 : $dst),
352 "call{q}\t{*}$dst",[(X86NoTrackCall GR64 : $dst)],
353 IIC_CALL_RI>,
354 Requires<[In64BitMode]>, NOTRACK;
355 def CALL64m_NT : I<0xFF, MRM2m, (outs), (ins i64mem : $dst),
356 "call{q}\t{*}$dst",[(X86NoTrackCall(loadi64 addr : $dst))],
357 IIC_CALL_MEM>,
358 Requires<[In64BitMode,FavorMemIndirectCall]>, NOTRACK;
359 }
360
308361 def FARCALL64 : RI<0xFF, MRM3m, (outs), (ins opaque80mem:$dst),
309362 "lcall{q}\t{*}$dst", [], IIC_CALL_FAR_MEM>;
310363 }
214214 class EVEX_V512 { bit hasEVEX_L2 = 1; bit hasVEX_L = 0; }
215215 class EVEX_V256 { bit hasEVEX_L2 = 0; bit hasVEX_L = 1; }
216216 class EVEX_V128 { bit hasEVEX_L2 = 0; bit hasVEX_L = 0; }
217 class NOTRACK { bit hasNoTrackPrefix = 1; }
217218
218219 // Specify AVX512 8-bit compressed displacement encoding based on the vector
219220 // element size in bits (8, 16, 32, 64) and the CDisp8 form.
295296 int CD8_EltSize = 0; // Compressed disp8 form - element-size in bytes.
296297 bit has3DNow0F0FOpcode =0;// Wacky 3dNow! encoding?
297298 bit hasEVEX_RC = 0; // Explicitly specified rounding control in FP instruction.
299 bit hasNoTrackPrefix = 0; // Does this inst has 0x3E (NoTrack) prefix?
298300
299301 bits<2> EVEX_LL;
300302 let EVEX_LL{0} = hasVEX_L;
346348 let TSFlags{52-46} = CD8_Scale;
347349 let TSFlags{53} = has3DNow0F0FOpcode;
348350 let TSFlags{54} = hasEVEX_RC;
351 let TSFlags{55} = hasNoTrackPrefix;
349352 }
350353
351354 class PseudoI pattern,
9292 SDTCisVT<1, i32>]>;
9393
9494 def SDT_X86Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
95
96 def SDT_X86NtBrind : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
9597
9698 def SDT_X86VASTART_SAVE_XMM_REGS : SDTypeProfile<0, -1, [SDTCisVT<0, i8>,
9799 SDTCisVT<1, iPTR>,
194196 def X86call : SDNode<"X86ISD::CALL", SDT_X86Call,
195197 [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
196198 SDNPVariadic]>;
199
200 def X86NoTrackCall : SDNode<"X86ISD::NT_CALL", SDT_X86Call,
201 [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
202 SDNPVariadic]>;
203 def X86NoTrackBrind : SDNode<"X86ISD::NT_BRIND", SDT_X86NtBrind,
204 [SDNPHasChain]>;
197205
198206 def X86rep_stos: SDNode<"X86ISD::REP_STOS", SDTX86RepStr,
199207 [SDNPHasChain, SDNPInGlue, SDNPOutGlue, SDNPMayStore]>;
4141 .Case("nonlazybind", Attribute::NonLazyBind)
4242 .Case("noredzone", Attribute::NoRedZone)
4343 .Case("noreturn", Attribute::NoReturn)
44 .Case("nocf_check", Attribute::NoCfCheck)
4445 .Case("norecurse", Attribute::NoRecurse)
4546 .Case("nounwind", Attribute::NoUnwind)
4647 .Case("optnone", Attribute::OptimizeNone)
695695 case Attribute::StackProtectStrong:
696696 case Attribute::StrictFP:
697697 case Attribute::UWTable:
698 case Attribute::NoCfCheck:
698699 break;
699700 }
700701
None ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86_64
1 ; RUN: llc -mtriple=i386-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86
0 ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86_64
1 ; RUN: llc -mtriple=i386-unknown-unknown -mattr=+ibt < %s | FileCheck %s --check-prefix=ALL --check-prefix=X86
2 ; RUN: llc -mtriple i386-windows-gnu -mattr=+ibt -exception-model sjlj < %s | FileCheck %s --check-prefix=SJLJ
23
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45 ;; Test1
56 ;; -----
6 ;; Checks ENDBR insertion in case of indirect branch IR instruction.
7 ;; Checks ENDBR insertion in case of switch case statement.
78 ;; Also since the function is not internal, make sure that endbr32/64 was
89 ;; added at the beginning of the function.
910 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3334 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3435 ;; Test2
3536 ;; -----
36 ;; Checks ENDBR insertion in case of switch case statement.
37 ;; Checks NOTRACK insertion in case of switch case statement.
38 ;; Check that there is no ENDBR insertion in the following case statements.
3739 ;; Also since the function is not internal, ENDBR instruction should be
3840 ;; added to its first basic block.
3941 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4244 ; ALL-LABEL: test2
4345 ; X86_64: endbr64
4446 ; X86: endbr32
45 ; ALL: jmp{{q|l}} *
46 ; ALL: .LBB1_2:
47 ; X86_64-NEXT: endbr64
48 ; X86-NEXT: endbr32
49 ; ALL: .LBB1_7:
47 ; ALL: notrack jmp{{q|l}} *
5048 ; X86_64-NOT: endbr64
5149 ; X86-NOT: endbr32
52 ; ALL: .LBB1_3:
53 ; X86_64-NEXT: endbr64
54 ; X86-NEXT: endbr32
55 ; ALL: .LBB1_4:
56 ; X86_64-NEXT: endbr64
57 ; X86-NEXT: endbr32
58 ; ALL: .LBB1_5:
59 ; X86_64-NEXT: endbr64
60 ; X86-NEXT: endbr32
61 ; ALL: .LBB1_6:
62 ; X86_64-NEXT: endbr64
63 ; X86-NEXT: endbr32
6450 entry:
6551 %retval = alloca i32, align 4
6652 %a.addr = alloca i32, align 4
197183 ; X86: endbr32
198184 ret i32 1
199185 }
186
187 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
188 ;; Test8
189 ;; -----
190 ;; Checks that NO TRACK prefix is not added for indirect jumps to a jump-
191 ;; table that was created for SJLJ dispatch.
192 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
193
194 declare void @_Z20function_that_throwsv()
195 declare i32 @__gxx_personality_sj0(...)
196 declare i8* @__cxa_begin_catch(i8*)
197 declare void @__cxa_end_catch()
198
199 define void @test8() personality i8* bitcast (i32 (...)* @__gxx_personality_sj0 to i8*) {
200 ;SJLJ-LABEL: test8
201 ;SJLJ-NOT: ds
202 entry:
203 invoke void @_Z20function_that_throwsv()
204 to label %try.cont unwind label %lpad
205
206 lpad:
207 %0 = landingpad { i8*, i32 }
208 catch i8* null
209 %1 = extractvalue { i8*, i32 } %0, 0
210 %2 = tail call i8* @__cxa_begin_catch(i8* %1)
211 tail call void @__cxa_end_catch()
212 br label %try.cont
213
214 try.cont:
215 ret void
216 }
217
218 !llvm.module.flags = !{!0}
219
220 !0 = !{i32 4, !"cf-protection-branch", i32 1}
0 ; RUN: llc -mtriple=x86_64-unknown-unknown -mattr=+ibt -x86-indirect-branch-tracking < %s | FileCheck %s
1
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; This test verify the handling of ''nocf_check'' attribute by the backend. ;;
4 ;; The file was generated using the following C code: ;;
5 ;; ;;
6 ;; void __attribute__((nocf_check)) NoCfCheckFunc(void) {} ;;
7 ;; ;;
8 ;; typedef void(*FuncPointer)(void); ;;
9 ;; void NoCfCheckCall(FuncPointer f) { ;;
10 ;; __attribute__((nocf_check)) FuncPointer p = f; ;;
11 ;; (*p)(); ;;
12 ;; } ;;
13 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
15 ; Make sure that a function with ''nocf_check'' attribute is not instrumented
16 ; with endbr instruction at the beginning.
17 define void @NoCfCheckFunc() #0 {
18 ; CHECK-LABEL: NoCfCheckFunc
19 ; CHECK-NOT: endbr64
20 ; CHECK: retq
21 entry:
22 ret void
23 }
24
25 ; Make sure that notrack prefix is added before a call with ''nocf_check'' attribute.
26 define void @NoCfCheckCall(void ()* %f) {
27 ; CHECK-LABEL: NoCfCheckCall
28 ; CHECK: notrack call
29 entry:
30 %f.addr = alloca void ()*, align 4
31 %p = alloca void ()*, align 4
32 store void ()* %f, void ()** %f.addr, align 4
33 %0 = load void ()*, void ()** %f.addr, align 4
34 store void ()* %0, void ()** %p, align 4
35 %1 = load void ()*, void ()** %p, align 4
36 call void %1() #1
37 ret void
38 }
39
40 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" }
41 attributes #1 = { nocf_check }
42
43 !llvm.module.flags = !{!0}
44
45 !0 = !{i32 4, !"cf-protection-branch", i32 1}
16541654 // CHECK: encoding: [0xff,0xd1]
16551655 call *%ecx
16561656
1657 // CHECK: notrack calll *%ecx
1658 // CHECK: encoding: [0x3e,0xff,0xd1]
1659 notrack call *%ecx
1660
16571661 // CHECK: calll *3735928559(%ebx,%ecx,8)
16581662 // CHECK: encoding: [0xff,0x94,0xcb,0xef,0xbe,0xad,0xde]
16591663 call *0xdeadbeef(%ebx,%ecx,8)
16601664
1665 // CHECK: notrack calll *3735928559(%ebx,%ecx,8)
1666 // CHECK: encoding: [0x3e,0xff,0x94,0xcb,0xef,0xbe,0xad,0xde]
1667 notrack call *0xdeadbeef(%ebx,%ecx,8)
1668
16611669 // CHECK: calll *3135175374
16621670 // CHECK: encoding: [0xff,0x15,0xce,0xfa,0xde,0xba]
16631671 call *0xbadeface
16851693 // CHECK: jmpl *3735928559(%ebx,%ecx,8)
16861694 // CHECK: encoding: [0xff,0xa4,0xcb,0xef,0xbe,0xad,0xde]
16871695 jmp *0xdeadbeef(%ebx,%ecx,8)
1696
1697 // CHECK: notrack jmpl *3735928559(%ebx,%ecx,8)
1698 // CHECK: encoding: [0x3e,0xff,0xa4,0xcb,0xef,0xbe,0xad,0xde]
1699 notrack jmp *0xdeadbeef(%ebx,%ecx,8)
16881700
16891701 // CHECK: jmpl *3135175374
16901702 // CHECK: encoding: [0xff,0x25,0xce,0xfa,0xde,0xba]
349349 MemRec->getValueAsBit("hasREX_WPrefix") ||
350350 RegRec->getValueAsBit("hasLockPrefix") !=
351351 MemRec->getValueAsBit("hasLockPrefix") ||
352 RegRec->getValueAsBit("hasNoTrackPrefix") !=
353 MemRec->getValueAsBit("hasNoTrackPrefix") ||
352354 !equalBitsInits(RegRec->getValueAsBitsInit("EVEX_LL"),
353355 MemRec->getValueAsBitsInit("EVEX_LL")) ||
354356 !equalBitsInits(RegRec->getValueAsBitsInit("VEX_WPrefix"),