llvm-project/llvm/test/CodeGen/ARM/speculation-hardening-sls.ll
David Green 3770b4aa3c [ARM] Don't emit Arm speculation hardening thunks under Thumb and vice-versa
Given a patch like D129506, using instructions not valid for the current
target feature set becomes an error. This means that emitting Arm
instructions in a Thumb target (or vice versa) becomes an error. When
running in Thumb mode only thumb thunks will be needed, and in Arm mode
only arm thunks are needed. This patch limits the emitted thunks to just
the ones valid for the current architecture.

Differential Revision: https://reviews.llvm.org/D129693
2023-01-23 11:22:11 +00:00

261 lines
12 KiB
LLVM

; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,SB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,SB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,SB -dump-input-context=100
; RUN: llc -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,SB -dump-input-context=100
; RUN: llc -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,NOHARDENARM -dump-input-context=100
; RUN: llc -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,NOHARDENTHUMB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-nocomdat -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-nocomdat -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,SB
; RUN: llc -global-isel -global-isel-abort=0 -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,SB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT,ISBDSB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT,ISBDSB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=harden-sls-nocomdat -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,HARDEN-COMDAT-OFF,ISBDSB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=armv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,ARM,HARDEN,SB
; RUN: llc -fast-isel -mattr=harden-sls-retbr -mattr=harden-sls-blr -mattr=+sb -verify-machineinstrs -mtriple=thumbv8-linux-gnueabi < %s | FileCheck %s --check-prefixes=CHECK,THUMB,HARDENTHUMB,HARDEN,SB
; Function Attrs: norecurse nounwind readnone
define dso_local i32 @double_return(i32 %a, i32 %b) local_unnamed_addr {
entry:
%cmp = icmp sgt i32 %a, 0
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %entry
; Make a very easy, very likely to predicate return (BX LR), to test that
; it will not get predicated when sls-hardening is enabled.
%mul = mul i32 %b, %a
ret i32 %mul
; CHECK-LABEL: double_return:
; HARDEN: {{bx lr$}}
; NOHARDENARM: {{bxgt lr$}}
; NOHARDENTHUMB: {{bxgt lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
if.else: ; preds = %entry
%div3 = sdiv i32 %a, %b
%div2 = sdiv i32 %a, %div3
%div1 = sdiv i32 %a, %div2
ret i32 %div1
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
; CHECK-NEXT: .Lfunc_end
}
@__const.indirect_branch.ptr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirect_branch, %return), ptr blockaddress(@indirect_branch, %l2)], align 8
; Function Attrs: norecurse nounwind readnone
define dso_local i32 @indirect_branch(i32 %a, i32 %b, i32 %i) {
; CHECK-LABEL: indirect_branch:
entry:
%idxprom = sext i32 %i to i64
%arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirect_branch.ptr, i64 0, i64 %idxprom
%0 = load ptr, ptr %arrayidx, align 8
indirectbr ptr %0, [label %return, label %l2]
; ARM: bx r0
; THUMB: mov pc, r0
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
l2: ; preds = %entry
br label %return
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
return: ; preds = %entry, %l2
%retval.0 = phi i32 [ 1, %l2 ], [ 0, %entry ]
ret i32 %retval.0
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
; CHECK-NEXT: .Lfunc_end
}
define i32 @asmgoto() {
entry:
; CHECK-LABEL: asmgoto:
callbr void asm sideeffect "B $0", "!i"()
to label %asm.fallthrough [label %d]
; The asm goto above produces a direct branch:
; CHECK: @APP
; CHECK-NEXT: {{^[ \t]+b }}
; CHECK-NEXT: @NO_APP
; For direct branches, no mitigation is needed.
; ISDDSB-NOT: dsb sy
; SB-NOT: {{ sb$}}
asm.fallthrough: ; preds = %entry
ret i32 0
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
d: ; preds = %asm.fallthrough, %entry
ret i32 1
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
; CHECK-NEXT: .Lfunc_end
}
; Check that indirect branches produced through switch jump tables are also
; hardened:
define dso_local i32 @jumptable(i32 %a, i32 %b) {
; CHECK-LABEL: jumptable:
entry:
switch i32 %b, label %sw.epilog [
i32 0, label %sw.bb
i32 1, label %sw.bb1
i32 3, label %sw.bb3
i32 4, label %sw.bb5
]
; ARM: ldr pc, [{{r[0-9]}}, {{r[0-9]}}, lsl #2]
; NOHARDENTHUMB: tbb [pc, {{r[0-9]}}]
; HARDENTHUMB: mov pc, {{r[0-9]}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
sw.bb: ; preds = %entry
%add = shl nsw i32 %a, 1
br label %sw.bb1
sw.bb1: ; preds = %entry, %sw.bb
%a.addr.0 = phi i32 [ %a, %entry ], [ %add, %sw.bb ]
%add2 = shl nsw i32 %a.addr.0, 1
br label %sw.bb3
sw.bb3: ; preds = %entry, %sw.bb1
%a.addr.1 = phi i32 [ %a, %entry ], [ %add2, %sw.bb1 ]
%add4 = shl nsw i32 %a.addr.1, 1
br label %sw.bb5
sw.bb5: ; preds = %entry, %sw.bb3
%a.addr.2 = phi i32 [ %a, %entry ], [ %add4, %sw.bb3 ]
%add6 = shl nsw i32 %a.addr.2, 1
br label %sw.epilog
sw.epilog: ; preds = %sw.bb5, %entry
%a.addr.3 = phi i32 [ %a, %entry ], [ %add6, %sw.bb5 ]
ret i32 %a.addr.3
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
}
define dso_local i32 @indirect_call(
ptr nocapture %f1, ptr nocapture %f2) {
entry:
; CHECK-LABEL: indirect_call:
%call = tail call i32 %f1()
; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
%call2 = tail call i32 %f2()
; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
%add = add nsw i32 %call2, %call
ret i32 %add
; CHECK: .Lfunc_end
}
; verify calling through a function pointer.
@a = dso_local local_unnamed_addr global ptr null, align 8
@b = dso_local local_unnamed_addr global i32 0, align 4
define dso_local void @indirect_call_global() local_unnamed_addr {
; CHECK-LABEL: indirect_call_global:
entry:
%0 = load ptr, ptr @a, align 8
%call = tail call i32 %0() nounwind
; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
store i32 %call, ptr @b, align 4
ret void
; CHECK: .Lfunc_end
}
; Verify that neither r12 nor lr are used as registers in indirect call
; instructions when the sls-hardening-blr mitigation is enabled, as
; (a) a linker is allowed to clobber r12 on calls, and
; (b) the hardening transformation isn't correct if lr is the register holding
; the address of the function called.
define i32 @check_r12(ptr %fp) {
entry:
; CHECK-LABEL: check_r12:
%f = load ptr, ptr %fp, align 4
; Force f to be moved into r12
%r12_f = tail call ptr asm "add $0, $1, #0", "={r12},{r12}"(ptr %f) nounwind
%call = call i32 %r12_f()
; NOHARDENARM: blx r12
; NOHARDENTHUMB: blx r12
; HARDEN-NOT: bl {{__llvm_slsblr_thunk_(arm|thumb)_r12}}
ret i32 %call
; CHECK: .Lfunc_end
}
define i32 @check_lr(ptr %fp) {
entry:
; CHECK-LABEL: check_lr:
%f = load ptr, ptr %fp, align 4
; Force f to be moved into lr
%lr_f = tail call ptr asm "add $0, $1, #0", "={lr},{lr}"(ptr %f) nounwind
%call = call i32 %lr_f()
; NOHARDENARM: blx lr
; NOHARDENTHUMB: blx lr
; HARDEN-NOT: bl {{__llvm_slsblr_thunk_(arm|thumb)_lr}}
ret i32 %call
; CHECK: .Lfunc_end
}
; Verify that even when sls-harden-blr is enabled, "blx r12" is still an
; instruction that is accepted by the inline assembler
define void @verify_inline_asm_blx_r12(ptr %g) {
entry:
; CHECK-LABEL: verify_inline_asm_blx_r12:
tail call void asm sideeffect "blx $0", "{r12}"(ptr %g) nounwind
; CHECK: blx r12
ret void
; CHECK: {{bx lr$}}
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: {{ sb$}}
; CHECK: .Lfunc_end
}
; HARDEN-COMDAT: .section {{.text.__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT: .hidden {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT: .weak {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT: .type {{__llvm_slsblr_thunk_(arm|thumb)_r5}},%function
; HARDEN-COMDAT-OFF-NOT: .section {{.text.__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT-OFF-NOT: .hidden {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT-OFF-NOT: .weak {{__llvm_slsblr_thunk_(arm|thumb)_r5}}
; HARDEN-COMDAT-OFF: .type {{__llvm_slsblr_thunk_(arm|thumb)_r5}},%function
; HARDEN-label: {{__llvm_slsblr_thunk_(arm|thumb)_r5}}:
; HARDEN: bx r5
; ISBDSB-NEXT: dsb sy
; ISBDSB-NEXT: isb
; SB-NEXT: dsb sy
; SB-NEXT: isb
; HARDEN-NEXT: .Lfunc_end
; THUMB-NOT: __llvm_slsblr_thunk_arm
; ARM-NOT: __llvm_slsblr_thunk_thumb