1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple x86_64-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86_64 3; RUN: llc -mtriple i386-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86 4 5; The MacOS tripples are used to get trapping behavior on the "unreachable" IR 6; instruction, so that the placement of the ud2 instruction could be verified. 7 8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 9;; The IR was created using the following C code: 10;; typedef void *jmp_buf; 11;; jmp_buf buf; 12;; 13;; __attribute__((noinline)) int bar(int i) { 14;; int j = i - 111; 15;; __builtin_longjmp(&buf, 1); 16;; return j; 17;; } 18;; 19;; int foo(int i) { 20;; int j = i * 11; 21;; if (!__builtin_setjmp(&buf)) { 22;; j += 33 + bar(j); 23;; } 24;; return j + i; 25;; } 26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 27 28@buf = common local_unnamed_addr global i8* null, align 8 29 30; Functions that use LongJmp should fix the Shadow Stack using previosuly saved 31; ShadowStackPointer in the input buffer. 32; The fix requires unwinding the shadow stack to the last SSP. 33define i32 @bar(i32 %i) local_unnamed_addr { 34; X86_64-LABEL: bar: 35; X86_64: ## %bb.0: ## %entry 36; X86_64-NEXT: pushq %rbp 37; X86_64-NEXT: .cfi_def_cfa_offset 16 38; X86_64-NEXT: .cfi_offset %rbp, -16 39; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax 40; X86_64-NEXT: movq (%rax), %rax 41; X86_64-NEXT: xorq %rdx, %rdx 42; X86_64-NEXT: rdsspq %rdx 43; X86_64-NEXT: testq %rdx, %rdx 44; X86_64-NEXT: je LBB0_5 45; X86_64-NEXT: ## %bb.1: ## %entry 46; X86_64-NEXT: movq 24(%rax), %rcx 47; X86_64-NEXT: subq %rdx, %rcx 48; X86_64-NEXT: jbe LBB0_5 49; X86_64-NEXT: ## %bb.2: ## %entry 50; X86_64-NEXT: shrq $3, %rcx 51; X86_64-NEXT: incsspq %rcx 52; X86_64-NEXT: shrq $8, %rcx 53; X86_64-NEXT: je LBB0_5 54; X86_64-NEXT: ## %bb.3: ## %entry 55; X86_64-NEXT: shlq %rcx 56; X86_64-NEXT: movq $128, %rdx 57; X86_64-NEXT: LBB0_4: ## %entry 58; X86_64-NEXT: ## =>This Inner Loop Header: Depth=1 59; X86_64-NEXT: incsspq %rdx 60; X86_64-NEXT: decq %rcx 61; X86_64-NEXT: jne LBB0_4 62; X86_64-NEXT: LBB0_5: ## %entry 63; X86_64-NEXT: movq (%rax), %rbp 64; X86_64-NEXT: movq 8(%rax), %rcx 65; X86_64-NEXT: movq 16(%rax), %rsp 66; X86_64-NEXT: jmpq *%rcx 67; X86_64-NEXT: ud2 68; 69; X86-LABEL: bar: 70; X86: ## %bb.0: ## %entry 71; X86-NEXT: pushl %ebp 72; X86-NEXT: .cfi_def_cfa_offset 8 73; X86-NEXT: .cfi_offset %ebp, -8 74; X86-NEXT: movl L_buf$non_lazy_ptr, %eax 75; X86-NEXT: movl (%eax), %eax 76; X86-NEXT: xorl %edx, %edx 77; X86-NEXT: rdsspd %edx 78; X86-NEXT: testl %edx, %edx 79; X86-NEXT: je LBB0_5 80; X86-NEXT: ## %bb.1: ## %entry 81; X86-NEXT: movl 12(%eax), %ecx 82; X86-NEXT: subl %edx, %ecx 83; X86-NEXT: jbe LBB0_5 84; X86-NEXT: ## %bb.2: ## %entry 85; X86-NEXT: shrl $2, %ecx 86; X86-NEXT: incsspd %ecx 87; X86-NEXT: shrl $8, %ecx 88; X86-NEXT: je LBB0_5 89; X86-NEXT: ## %bb.3: ## %entry 90; X86-NEXT: shll %ecx 91; X86-NEXT: movl $128, %edx 92; X86-NEXT: LBB0_4: ## %entry 93; X86-NEXT: ## =>This Inner Loop Header: Depth=1 94; X86-NEXT: incsspd %edx 95; X86-NEXT: decl %ecx 96; X86-NEXT: jne LBB0_4 97; X86-NEXT: LBB0_5: ## %entry 98; X86-NEXT: movl (%eax), %ebp 99; X86-NEXT: movl 4(%eax), %ecx 100; X86-NEXT: movl 8(%eax), %esp 101; X86-NEXT: jmpl *%ecx 102; X86-NEXT: ud2 103entry: 104 %0 = load i8*, i8** @buf, align 8 105 tail call void @llvm.eh.sjlj.longjmp(i8* %0) 106 unreachable 107} 108 109declare void @llvm.eh.sjlj.longjmp(i8*) 110 111; Functions that call SetJmp should save the current ShadowStackPointer for 112; future fixing of the Shadow Stack. 113define i32 @foo(i32 %i) local_unnamed_addr { 114; X86_64-LABEL: foo: 115; X86_64: ## %bb.0: ## %entry 116; X86_64-NEXT: pushq %rbp 117; X86_64-NEXT: .cfi_def_cfa_offset 16 118; X86_64-NEXT: .cfi_offset %rbp, -16 119; X86_64-NEXT: movq %rsp, %rbp 120; X86_64-NEXT: .cfi_def_cfa_register %rbp 121; X86_64-NEXT: pushq %r15 122; X86_64-NEXT: pushq %r14 123; X86_64-NEXT: pushq %r13 124; X86_64-NEXT: pushq %r12 125; X86_64-NEXT: pushq %rbx 126; X86_64-NEXT: pushq %rax 127; X86_64-NEXT: .cfi_offset %rbx, -56 128; X86_64-NEXT: .cfi_offset %r12, -48 129; X86_64-NEXT: .cfi_offset %r13, -40 130; X86_64-NEXT: .cfi_offset %r14, -32 131; X86_64-NEXT: .cfi_offset %r15, -24 132; X86_64-NEXT: ## kill: def $edi killed $edi def $rdi 133; X86_64-NEXT: movq %rdi, {{[-0-9]+}}(%r{{[sb]}}p) ## 8-byte Spill 134; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax 135; X86_64-NEXT: movq (%rax), %rax 136; X86_64-NEXT: movq %rbp, (%rax) 137; X86_64-NEXT: movq %rsp, 16(%rax) 138; X86_64-NEXT: leaq {{.*}}(%rip), %rcx 139; X86_64-NEXT: movq %rcx, 8(%rax) 140; X86_64-NEXT: xorq %rcx, %rcx 141; X86_64-NEXT: rdsspq %rcx 142; X86_64-NEXT: movq %rcx, 24(%rax) 143; X86_64-NEXT: #EH_SjLj_Setup LBB1_4 144; X86_64-NEXT: ## %bb.1: ## %entry 145; X86_64-NEXT: xorl %eax, %eax 146; X86_64-NEXT: testl %eax, %eax 147; X86_64-NEXT: jne LBB1_3 148; X86_64-NEXT: jmp LBB1_5 149; X86_64-NEXT: LBB1_4: ## Block address taken 150; X86_64-NEXT: ## %entry 151; X86_64-NEXT: movl $1, %eax 152; X86_64-NEXT: testl %eax, %eax 153; X86_64-NEXT: je LBB1_5 154; X86_64-NEXT: LBB1_3: ## %if.end 155; X86_64-NEXT: movq {{[-0-9]+}}(%r{{[sb]}}p), %rax ## 8-byte Reload 156; X86_64-NEXT: shll $2, %eax 157; X86_64-NEXT: leal (%rax,%rax,2), %eax 158; X86_64-NEXT: addq $8, %rsp 159; X86_64-NEXT: popq %rbx 160; X86_64-NEXT: popq %r12 161; X86_64-NEXT: popq %r13 162; X86_64-NEXT: popq %r14 163; X86_64-NEXT: popq %r15 164; X86_64-NEXT: popq %rbp 165; X86_64-NEXT: retq 166; X86_64-NEXT: LBB1_5: ## %if.then 167; X86_64-NEXT: callq _bar 168; X86_64-NEXT: ud2 169; 170; X86-LABEL: foo: 171; X86: ## %bb.0: ## %entry 172; X86-NEXT: pushl %ebp 173; X86-NEXT: .cfi_def_cfa_offset 8 174; X86-NEXT: .cfi_offset %ebp, -8 175; X86-NEXT: movl %esp, %ebp 176; X86-NEXT: .cfi_def_cfa_register %ebp 177; X86-NEXT: pushl %ebx 178; X86-NEXT: pushl %edi 179; X86-NEXT: pushl %esi 180; X86-NEXT: subl $12, %esp 181; X86-NEXT: .cfi_offset %esi, -20 182; X86-NEXT: .cfi_offset %edi, -16 183; X86-NEXT: .cfi_offset %ebx, -12 184; X86-NEXT: movl L_buf$non_lazy_ptr, %eax 185; X86-NEXT: movl (%eax), %eax 186; X86-NEXT: movl %ebp, (%eax) 187; X86-NEXT: movl %esp, 16(%eax) 188; X86-NEXT: movl $LBB1_4, 4(%eax) 189; X86-NEXT: xorl %ecx, %ecx 190; X86-NEXT: rdsspd %ecx 191; X86-NEXT: movl %ecx, 12(%eax) 192; X86-NEXT: #EH_SjLj_Setup LBB1_4 193; X86-NEXT: ## %bb.1: ## %entry 194; X86-NEXT: xorl %eax, %eax 195; X86-NEXT: testl %eax, %eax 196; X86-NEXT: jne LBB1_3 197; X86-NEXT: jmp LBB1_5 198; X86-NEXT: LBB1_4: ## Block address taken 199; X86-NEXT: ## %entry 200; X86-NEXT: movl $1, %eax 201; X86-NEXT: testl %eax, %eax 202; X86-NEXT: je LBB1_5 203; X86-NEXT: LBB1_3: ## %if.end 204; X86-NEXT: movl 8(%ebp), %eax 205; X86-NEXT: shll $2, %eax 206; X86-NEXT: leal (%eax,%eax,2), %eax 207; X86-NEXT: addl $12, %esp 208; X86-NEXT: popl %esi 209; X86-NEXT: popl %edi 210; X86-NEXT: popl %ebx 211; X86-NEXT: popl %ebp 212; X86-NEXT: retl 213; X86-NEXT: LBB1_5: ## %if.then 214; X86-NEXT: calll _bar 215; X86-NEXT: ud2 216entry: 217 %0 = load i8*, i8** @buf, align 8 218 %1 = bitcast i8* %0 to i8** 219 %2 = tail call i8* @llvm.frameaddress(i32 0) 220 store i8* %2, i8** %1, align 8 221 %3 = tail call i8* @llvm.stacksave() 222 %4 = getelementptr inbounds i8, i8* %0, i64 16 223 %5 = bitcast i8* %4 to i8** 224 store i8* %3, i8** %5, align 8 225 %6 = tail call i32 @llvm.eh.sjlj.setjmp(i8* %0) 226 %tobool = icmp eq i32 %6, 0 227 br i1 %tobool, label %if.then, label %if.end 228 229if.then: ; preds = %entry 230 %call = tail call i32 @bar(i32 undef) 231 unreachable 232 233if.end: ; preds = %entry 234 %add2 = mul nsw i32 %i, 12 235 ret i32 %add2 236} 237 238declare i8* @llvm.frameaddress(i32) 239declare i8* @llvm.stacksave() 240declare i32 @llvm.eh.sjlj.setjmp(i8*) 241 242!llvm.module.flags = !{!0} 243 244!0 = !{i32 4, !"cf-protection-return", i32 1} 245