247 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			9.7 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,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,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,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,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,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,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,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,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:     {{bxge lr$}}
 | |
| ; NOHARDENTHUMB:   {{bx 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 i8*] [i8* blockaddress(@indirect_branch, %return), i8* 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 i8*], [2 x i8*]* @__const.indirect_branch.ptr, i64 0, i64 %idxprom
 | |
|   %0 = load i8*, i8** %arrayidx, align 8
 | |
|   indirectbr i8* %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", "X"(i8* blockaddress(@asmgoto, %d))
 | |
|             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(
 | |
| i32 (...)* nocapture %f1, i32 (...)* nocapture %f2) {
 | |
| entry:
 | |
| ; CHECK-LABEL: indirect_call:
 | |
|   %callee.knr.cast = bitcast i32 (...)* %f1 to i32 ()*
 | |
|   %call = tail call i32 %callee.knr.cast()
 | |
| ; HARDENARM: bl {{__llvm_slsblr_thunk_arm_r[0-9]+$}}
 | |
| ; HARDENTHUMB: bl {{__llvm_slsblr_thunk_thumb_r[0-9]+$}}
 | |
|   %callee.knr.cast1 = bitcast i32 (...)* %f2 to i32 ()*
 | |
|   %call2 = tail call i32 %callee.knr.cast1()
 | |
| ; 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 i32 (...)* 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 i32 ()*, i32 ()** bitcast (i32 (...)** @a to i32 ()**), 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, i32* @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(i32 ()** %fp) {
 | |
| entry:
 | |
| ; CHECK-LABEL: check_r12:
 | |
|   %f = load i32 ()*, i32 ()** %fp, align 4
 | |
|   ; Force f to be moved into r12
 | |
|   %r12_f = tail call i32 ()* asm "add $0, $1, #0", "={r12},{r12}"(i32 ()* %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(i32 ()** %fp) {
 | |
| entry:
 | |
| ; CHECK-LABEL: check_lr:
 | |
|   %f = load i32 ()*, i32 ()** %fp, align 4
 | |
|   ; Force f to be moved into lr
 | |
|   %lr_f = tail call i32 ()* asm "add $0, $1, #0", "={lr},{lr}"(i32 ()* %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(void ()* %g) {
 | |
| entry:
 | |
| ; CHECK-LABEL: verify_inline_asm_blx_r12:
 | |
|   %0 = bitcast void ()* %g to i8*
 | |
|   tail call void asm sideeffect "blx $0", "{r12}"(i8* %0) nounwind
 | |
| ; CHECK: blx r12
 | |
|   ret void
 | |
| ; CHECK:       {{bx lr$}}
 | |
| ; ISBDSB-NEXT: dsb sy
 | |
| ; ISBDSB-NEXT: isb
 | |
| ; SB-NEXT:     {{ sb$}}
 | |
| ; CHECK: .Lfunc_end
 | |
| }
 | |
| 
 | |
| ; 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
 | |
| 
 | |
| 
 |