
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
261 lines
12 KiB
LLVM
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
|