Skip to content

Commit fa582b0

Browse files
author
Oren Ben Simhon
committedNov 26, 2017
Control-Flow Enforcement Technology - Shadow Stack support (LLVM side)
Shadow stack solution introduces a new stack for return addresses only. The HW has a Shadow Stack Pointer (SSP) that points to the next return address. If we return to a different address, an exception is triggered. The shadow stack is managed using a series of intrinsics that are introduced in this patch as well as the new register (SSP). The intrinsics are mapped to new instruction set that implements CET mechanism. The patch also includes initial infrastructure support for IBT. For more information, please see the following: https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf Differential Revision: https://reviews.llvm.org/D40223 Change-Id: I4daa1f27e88176be79a4ac3b4cd26a459e88fed4 llvm-svn: 318996
1 parent fec21ec commit fa582b0

22 files changed

+636
-97
lines changed
 

‎llvm/include/llvm/IR/IntrinsicsX86.td

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,35 @@ let TargetPrefix = "x86" in {
6363
Intrinsic<[llvm_i64_ty], [llvm_i32_ty], []>;
6464
}
6565

66+
//===----------------------------------------------------------------------===//
67+
// CET SS
68+
let TargetPrefix = "x86" in {
69+
def int_x86_incsspd : GCCBuiltin<"__builtin_ia32_incsspd">,
70+
Intrinsic<[], [llvm_i32_ty], []>;
71+
def int_x86_incsspq : GCCBuiltin<"__builtin_ia32_incsspq">,
72+
Intrinsic<[], [llvm_i64_ty], []>;
73+
def int_x86_rdsspd : GCCBuiltin<"__builtin_ia32_rdsspd">,
74+
Intrinsic<[llvm_i32_ty], [llvm_i32_ty], []>;
75+
def int_x86_rdsspq : GCCBuiltin<"__builtin_ia32_rdsspq">,
76+
Intrinsic<[llvm_i64_ty], [llvm_i64_ty], []>;
77+
def int_x86_saveprevssp : GCCBuiltin<"__builtin_ia32_saveprevssp">,
78+
Intrinsic<[], [], []>;
79+
def int_x86_rstorssp : GCCBuiltin<"__builtin_ia32_rstorssp">,
80+
Intrinsic<[], [llvm_ptr_ty], []>;
81+
def int_x86_wrssd : GCCBuiltin<"__builtin_ia32_wrssd">,
82+
Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], []>;
83+
def int_x86_wrssq : GCCBuiltin<"__builtin_ia32_wrssq">,
84+
Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], []>;
85+
def int_x86_wrussd : GCCBuiltin<"__builtin_ia32_wrussd">,
86+
Intrinsic<[], [llvm_i32_ty, llvm_ptr_ty], []>;
87+
def int_x86_wrussq : GCCBuiltin<"__builtin_ia32_wrussq">,
88+
Intrinsic<[], [llvm_i64_ty, llvm_ptr_ty], []>;
89+
def int_x86_setssbsy : GCCBuiltin<"__builtin_ia32_setssbsy">,
90+
Intrinsic<[], [], []>;
91+
def int_x86_clrssbsy : GCCBuiltin<"__builtin_ia32_clrssbsy">,
92+
Intrinsic<[], [llvm_ptr_ty], []>;
93+
}
94+
6695
//===----------------------------------------------------------------------===//
6796
// 3DNow!
6897

‎llvm/lib/Support/Host.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,13 +1217,16 @@ bool sys::getHostCPUFeatures(StringMap<bool> &Features) {
12171217
Features["avx512vbmi"] = HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save;
12181218
Features["pku"] = HasLeaf7 && ((ECX >> 4) & 1);
12191219
Features["avx512vbmi2"] = HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save;
1220+
Features["shstk"] = HasLeaf7 && ((ECX >> 7) & 1);
12201221
Features["gfni"] = HasLeaf7 && ((ECX >> 8) & 1);
12211222
Features["vaes"] = HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave;
12221223
Features["vpclmulqdq"] = HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave;
12231224
Features["avx512vnni"] = HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save;
12241225
Features["avx512bitalg"] = HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save;
12251226
Features["avx512vpopcntdq"] = HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save;
12261227

1228+
Features["ibt"] = HasLeaf7 && ((EDX >> 20) & 1);
1229+
12271230
bool HasLeafD = MaxLevel >= 0xd &&
12281231
!getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX);
12291232

‎llvm/lib/Target/X86/X86.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ def FeatureADX : SubtargetFeature<"adx", "HasADX", "true",
213213
def FeatureSHA : SubtargetFeature<"sha", "HasSHA", "true",
214214
"Enable SHA instructions",
215215
[FeatureSSE2]>;
216+
def FeatureSHSTK : SubtargetFeature<"shstk", "HasSHSTK", "true",
217+
"Support CET Shadow-Stack instructions">;
218+
def FeatureIBT : SubtargetFeature<"ibt", "HasIBT", "true",
219+
"Support CET Indirect-Branch-Tracking instructions">;
216220
def FeaturePRFCHW : SubtargetFeature<"prfchw", "HasPRFCHW", "true",
217221
"Support PRFCHW instructions">;
218222
def FeatureRDSEED : SubtargetFeature<"rdseed", "HasRDSEED", "true",

‎llvm/lib/Target/X86/X86InstrCompiler.td

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def GetLo8XForm : SDNodeXForm<imm, [{
3232
// PIC base construction. This expands to code that looks like this:
3333
// call $next_inst
3434
// popl %destreg"
35-
let hasSideEffects = 0, isNotDuplicable = 1, Uses = [ESP] in
35+
let hasSideEffects = 0, isNotDuplicable = 1, Uses = [ESP, SSP] in
3636
def MOVPC32r : Ii32<0xE8, Pseudo, (outs GR32:$reg), (ins i32imm:$label),
3737
"", []>;
3838

@@ -42,7 +42,7 @@ let hasSideEffects = 0, isNotDuplicable = 1, Uses = [ESP] in
4242
// pointer before prolog-epilog rewriting occurs.
4343
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
4444
// sub / add which can clobber EFLAGS.
45-
let Defs = [ESP, EFLAGS], Uses = [ESP] in {
45+
let Defs = [ESP, EFLAGS, SSP], Uses = [ESP, SSP] in {
4646
def ADJCALLSTACKDOWN32 : I<0, Pseudo, (outs),
4747
(ins i32imm:$amt1, i32imm:$amt2, i32imm:$amt3),
4848
"#ADJCALLSTACKDOWN",
@@ -62,7 +62,7 @@ def : Pat<(X86callseq_start timm:$amt1, timm:$amt2),
6262
// pointer before prolog-epilog rewriting occurs.
6363
// Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become
6464
// sub / add which can clobber EFLAGS.
65-
let Defs = [RSP, EFLAGS], Uses = [RSP] in {
65+
let Defs = [RSP, EFLAGS, SSP], Uses = [RSP, SSP] in {
6666
def ADJCALLSTACKDOWN64 : I<0, Pseudo, (outs),
6767
(ins i32imm:$amt1, i32imm:$amt2, i32imm:$amt3),
6868
"#ADJCALLSTACKDOWN",
@@ -458,7 +458,7 @@ let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7,
458458
MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7,
459459
XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
460460
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS],
461-
usesCustomInserter = 1, Uses = [ESP] in {
461+
usesCustomInserter = 1, Uses = [ESP, SSP] in {
462462
def TLS_addr32 : I<0, Pseudo, (outs), (ins i32mem:$sym),
463463
"# TLS_addr32",
464464
[(X86tlsaddr tls32addr:$sym)]>,
@@ -478,7 +478,7 @@ let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11,
478478
MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7,
479479
XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
480480
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, EFLAGS],
481-
usesCustomInserter = 1, Uses = [RSP] in {
481+
usesCustomInserter = 1, Uses = [RSP, SSP] in {
482482
def TLS_addr64 : I<0, Pseudo, (outs), (ins i64mem:$sym),
483483
"# TLS_addr64",
484484
[(X86tlsaddr tls64addr:$sym)]>,
@@ -494,7 +494,7 @@ def TLS_base_addr64 : I<0, Pseudo, (outs), (ins i64mem:$sym),
494494
// address of the variable is in %eax. %ecx is trashed during the function
495495
// call. All other registers are preserved.
496496
let Defs = [EAX, ECX, EFLAGS],
497-
Uses = [ESP],
497+
Uses = [ESP, SSP],
498498
usesCustomInserter = 1 in
499499
def TLSCall_32 : I<0, Pseudo, (outs), (ins i32mem:$sym),
500500
"# TLSCall_32",
@@ -507,7 +507,7 @@ def TLSCall_32 : I<0, Pseudo, (outs), (ins i32mem:$sym),
507507
// On return the address of the variable is in %rax. All other
508508
// registers are preserved.
509509
let Defs = [RAX, EFLAGS],
510-
Uses = [RSP],
510+
Uses = [RSP, SSP],
511511
usesCustomInserter = 1 in
512512
def TLSCall_64 : I<0, Pseudo, (outs), (ins i64mem:$sym),
513513
"# TLSCall_64",

‎llvm/lib/Target/X86/X86InstrControl.td

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ let isCall = 1 in
191191
// a use to prevent stack-pointer assignments that appear immediately
192192
// before calls from potentially appearing dead. Uses for argument
193193
// registers are added manually.
194-
let Uses = [ESP] in {
194+
let Uses = [ESP, SSP] in {
195195
def CALLpcrel32 : Ii32PCRel<0xE8, RawFrm,
196196
(outs), (ins i32imm_pcrel:$dst),
197197
"call{l}\t$dst", [], IIC_CALL_RI>, OpSize32,
@@ -241,7 +241,7 @@ let isCall = 1 in
241241
// Tail call stuff.
242242
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
243243
isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
244-
let Uses = [ESP] in {
244+
let Uses = [ESP, SSP] in {
245245
def TCRETURNdi : PseudoI<(outs),
246246
(ins i32imm_pcrel:$dst, i32imm:$offset), []>, NotMemoryFoldable;
247247
def TCRETURNri : PseudoI<(outs),
@@ -268,7 +268,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
268268
// rather than barriers, and they use EFLAGS.
269269
let isCall = 1, isTerminator = 1, isReturn = 1, isBranch = 1,
270270
isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
271-
let Uses = [ESP, EFLAGS] in {
271+
let Uses = [ESP, EFLAGS, SSP] in {
272272
def TCRETURNdicc : PseudoI<(outs),
273273
(ins i32imm_pcrel:$dst, i32imm:$offset, i32imm:$cond), []>;
274274

@@ -287,7 +287,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBranch = 1,
287287
// RSP is marked as a use to prevent stack-pointer assignments that appear
288288
// immediately before calls from potentially appearing dead. Uses for argument
289289
// registers are added manually.
290-
let isCall = 1, Uses = [RSP], SchedRW = [WriteJump] in {
290+
let isCall = 1, Uses = [RSP, SSP], SchedRW = [WriteJump] in {
291291
// NOTE: this pattern doesn't match "X86call imm", because we do not know
292292
// that the offset between an arbitrary immediate and the call will fit in
293293
// the 32-bit pcrel field that we have.
@@ -309,7 +309,7 @@ let isCall = 1, Uses = [RSP], SchedRW = [WriteJump] in {
309309
}
310310

311311
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
312-
isCodeGenOnly = 1, Uses = [RSP], usesCustomInserter = 1,
312+
isCodeGenOnly = 1, Uses = [RSP, SSP], usesCustomInserter = 1,
313313
SchedRW = [WriteJump] in {
314314
def TCRETURNdi64 : PseudoI<(outs),
315315
(ins i64i32imm_pcrel:$dst, i32imm:$offset),
@@ -345,7 +345,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
345345
// rather than barriers, and they use EFLAGS.
346346
let isCall = 1, isTerminator = 1, isReturn = 1, isBranch = 1,
347347
isCodeGenOnly = 1, SchedRW = [WriteJumpLd] in
348-
let Uses = [RSP, EFLAGS] in {
348+
let Uses = [RSP, EFLAGS, SSP] in {
349349
def TCRETURNdi64cc : PseudoI<(outs),
350350
(ins i64i32imm_pcrel:$dst, i32imm:$offset,
351351
i32imm:$cond), []>;

‎llvm/lib/Target/X86/X86InstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ def HasCLZERO : Predicate<"Subtarget->hasCLZERO()">;
881881
def FPStackf32 : Predicate<"!Subtarget->hasSSE1()">;
882882
def FPStackf64 : Predicate<"!Subtarget->hasSSE2()">;
883883
def HasMPX : Predicate<"Subtarget->hasMPX()">;
884+
def HasSHSTK : Predicate<"Subtarget->hasSHSTK()">;
885+
def HasIBT : Predicate<"Subtarget->hasIBT()">;
884886
def HasCLFLUSHOPT : Predicate<"Subtarget->hasCLFLUSHOPT()">;
885887
def HasCLWB : Predicate<"Subtarget->hasCLWB()">;
886888
def HasCmpxchg16b: Predicate<"Subtarget->hasCmpxchg16b()">;

‎llvm/lib/Target/X86/X86InstrSystem.td

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,64 @@ def INVD : I<0x08, RawFrm, (outs), (ins), "invd", [], IIC_INVD>, TB;
480480
def WBINVD : I<0x09, RawFrm, (outs), (ins), "wbinvd", [], IIC_INVD>, TB;
481481
} // SchedRW
482482

483+
//===----------------------------------------------------------------------===//
484+
// CET instructions
485+
let SchedRW = [WriteSystem], Predicates = [HasSHSTK] in{
486+
let Uses = [SSP] in {
487+
let Defs = [SSP] in {
488+
def INCSSPD : I<0xAE, MRM5r, (outs), (ins GR32:$src), "incsspd\t$src",
489+
[(int_x86_incsspd GR32:$src)]>, XS;
490+
def INCSSPQ : RI<0xAE, MRM5r, (outs), (ins GR64:$src), "incsspq\t$src",
491+
[(int_x86_incsspq GR64:$src)]>, XS,
492+
Requires<[In64BitMode]>;
493+
} // Defs SSP
494+
495+
let Constraints = "$src = $dst" in {
496+
def RDSSPD : I<0x1E, MRM1r, (outs GR32:$dst), (ins GR32:$src),
497+
"rdsspd\t$dst",
498+
[(set GR32:$dst, (int_x86_rdsspd GR32:$src))]>, XS;
499+
def RDSSPQ : RI<0x1E, MRM1r, (outs GR64:$dst), (ins GR64:$src),
500+
"rdsspq\t$dst",
501+
[(set GR64:$dst, (int_x86_rdsspq GR64:$src))]>, XS,
502+
Requires<[In64BitMode]>;
503+
}
504+
505+
let Defs = [SSP] in {
506+
def SAVEPREVSSP : I<0x01, MRM_EA, (outs), (ins), "saveprevssp",
507+
[(int_x86_saveprevssp)]>, XS;
508+
def RSTORSSP : I<0x01, MRM5m, (outs), (ins i32mem:$src),
509+
"rstorssp\t$src",
510+
[(int_x86_rstorssp addr:$src)]>, XS;
511+
} // Defs SSP
512+
} // Uses SSP
513+
514+
def WRSSD : I<0xF6, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src),
515+
"wrssd\t{$src, $dst|$dst, $src}",
516+
[(int_x86_wrssd GR32:$src, addr:$dst)]>, T8;
517+
def WRSSQ : RI<0xF6, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src),
518+
"wrssq\t{$src, $dst|$dst, $src}",
519+
[(int_x86_wrssq GR64:$src, addr:$dst)]>, T8,
520+
Requires<[In64BitMode]>;
521+
def WRUSSD : I<0xF5, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src),
522+
"wrussd\t{$src, $dst|$dst, $src}",
523+
[(int_x86_wrussd GR32:$src, addr:$dst)]>, T8PD;
524+
def WRUSSQ : RI<0xF5, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src),
525+
"wrussq\t{$src, $dst|$dst, $src}",
526+
[(int_x86_wrussq GR64:$src, addr:$dst)]>, T8PD,
527+
Requires<[In64BitMode]>;
528+
529+
let Defs = [SSP] in {
530+
let Uses = [SSP] in {
531+
def SETSSBSY : I<0x01, MRM_E8, (outs), (ins), "setssbsy",
532+
[(int_x86_setssbsy)]>, XS;
533+
} // Uses SSP
534+
535+
def CLRSSBSY : I<0xAE, MRM6m, (outs), (ins i32mem:$src),
536+
"clrssbsy\t$src",
537+
[(int_x86_clrssbsy addr:$src)]>, XS;
538+
} // Defs SSP
539+
} // SchedRW && HasSHSTK
540+
483541
//===----------------------------------------------------------------------===//
484542
// XSAVE instructions
485543
let SchedRW = [WriteSystem] in {

‎llvm/lib/Target/X86/X86RegisterInfo.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,9 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
507507
++I)
508508
Reserved.set(*I);
509509

510+
// Set the Shadow Stack Pointer as reserved.
511+
Reserved.set(X86::SSP);
512+
510513
// Set the instruction pointer register and its aliases as reserved.
511514
for (MCSubRegIterator I(X86::RIP, this, /*IncludeSelf=*/true); I.isValid();
512515
++I)

‎llvm/lib/Target/X86/X86RegisterInfo.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ def BND1 : X86Reg<"bnd1", 1>;
308308
def BND2 : X86Reg<"bnd2", 2>;
309309
def BND3 : X86Reg<"bnd3", 3>;
310310

311+
// CET registers - Shadow Stack Pointer
312+
def SSP : X86Reg<"ssp", 0>;
313+
311314
//===----------------------------------------------------------------------===//
312315
// Register Class Definitions... now that we have all of the pieces, define the
313316
// top-level register classes. The order specified in the register list is

‎llvm/lib/Target/X86/X86Subtarget.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ void X86Subtarget::initializeEnvironment() {
334334
HasMWAITX = false;
335335
HasCLZERO = false;
336336
HasMPX = false;
337+
HasSHSTK = false;
338+
HasIBT = false;
337339
HasSGX = false;
338340
HasCLFLUSHOPT = false;
339341
HasCLWB = false;

‎llvm/lib/Target/X86/X86Subtarget.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ class X86Subtarget final : public X86GenSubtargetInfo {
320320
/// Processor supports MPX - Memory Protection Extensions
321321
bool HasMPX;
322322

323+
/// Processor supports CET SHSTK - Control-Flow Enforcement Technology
324+
/// using Shadow Stack
325+
bool HasSHSTK;
326+
327+
/// Processor supports CET IBT - Control-Flow Enforcement Technology
328+
/// using Indirect Branch Tracking
329+
bool HasIBT;
330+
323331
/// Processor has Software Guard Extensions
324332
bool HasSGX;
325333

@@ -548,6 +556,8 @@ class X86Subtarget final : public X86GenSubtargetInfo {
548556
bool hasVNNI() const { return HasVNNI; }
549557
bool hasBITALG() const { return HasBITALG; }
550558
bool hasMPX() const { return HasMPX; }
559+
bool hasSHSTK() const { return HasSHSTK; }
560+
bool hasIBT() const { return HasIBT; }
551561
bool hasCLFLUSHOPT() const { return HasCLFLUSHOPT; }
552562
bool hasCLWB() const { return HasCLWB; }
553563

‎llvm/test/CodeGen/MIR/X86/frame-info-save-restore-points.mir

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ body: |
6060
liveins: %eax
6161
6262
MOV32mr %stack.0.tmp, 1, _, 0, _, killed %eax
63-
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def %rsp, implicit-def dead %eflags, implicit %rsp
63+
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def %rsp, implicit-def %ssp, implicit-def dead %eflags, implicit %rsp, implicit %ssp
6464
%rsi = LEA64r %stack.0.tmp, 1, _, 0, _
6565
%edi = MOV32r0 implicit-def dead %eflags
66-
CALL64pcrel32 @doSomething, csr_64, implicit %rsp, implicit %edi, implicit %rsi, implicit-def %rsp, implicit-def %eax
67-
ADJCALLSTACKUP64 0, 0, implicit-def %rsp, implicit-def dead %eflags, implicit %rsp
66+
CALL64pcrel32 @doSomething, csr_64, implicit %rsp, implicit %ssp, implicit %edi, implicit %rsi, implicit-def %rsp, implicit-def %ssp, implicit-def %eax
67+
ADJCALLSTACKUP64 0, 0, implicit-def %rsp, implicit-def %ssp, implicit-def dead %eflags, implicit %rsp, implicit %ssp
6868
6969
bb.3.false:
7070
liveins: %eax

0 commit comments

Comments
 (0)
Please sign in to comment.