| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | |
| ; RUN: llc -mtriple x86_64-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86_64 | |
| ; RUN: llc -mtriple i386-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86 | |
| ; The MacOS tripples are used to get trapping behavior on the "unreachable" IR | |
| ; instruction, so that the placement of the ud2 instruction could be verified. | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| ;; The IR was created using the following C code: | |
| ;; typedef void *jmp_buf; | |
| ;; jmp_buf buf; | |
| ;; | |
| ;; __attribute__((noinline)) int bar(int i) { | |
| ;; int j = i - 111; | |
| ;; __builtin_longjmp(&buf, 1); | |
| ;; return j; | |
| ;; } | |
| ;; | |
| ;; int foo(int i) { | |
| ;; int j = i * 11; | |
| ;; if (!__builtin_setjmp(&buf)) { | |
| ;; j += 33 + bar(j); | |
| ;; } | |
| ;; return j + i; | |
| ;; } | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
| @buf = common local_unnamed_addr global i8* null, align 8 | |
| ; Functions that use LongJmp should fix the Shadow Stack using previosuly saved | |
| ; ShadowStackPointer in the input buffer. | |
| ; The fix requires unwinding the shadow stack to the last SSP. | |
| define i32 @bar(i32 %i) local_unnamed_addr { | |
| ; X86_64-LABEL: bar: | |
| ; X86_64: ## %bb.0: ## %entry | |
| ; X86_64-NEXT: pushq %rbp | |
| ; X86_64-NEXT: .cfi_def_cfa_offset 16 | |
| ; X86_64-NEXT: .cfi_offset %rbp, -16 | |
| ; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax | |
| ; X86_64-NEXT: movq (%rax), %rax | |
| ; X86_64-NEXT: xorq %rdx, %rdx | |
| ; X86_64-NEXT: rdsspq %rdx | |
| ; X86_64-NEXT: testq %rdx, %rdx | |
| ; X86_64-NEXT: je LBB0_5 | |
| ; X86_64-NEXT: ## %bb.1: ## %entry | |
| ; X86_64-NEXT: movq 24(%rax), %rcx | |
| ; X86_64-NEXT: subq %rdx, %rcx | |
| ; X86_64-NEXT: jbe LBB0_5 | |
| ; X86_64-NEXT: ## %bb.2: ## %entry | |
| ; X86_64-NEXT: shrq $3, %rcx | |
| ; X86_64-NEXT: incsspq %rcx | |
| ; X86_64-NEXT: shrq $8, %rcx | |
| ; X86_64-NEXT: je LBB0_5 | |
| ; X86_64-NEXT: ## %bb.3: ## %entry | |
| ; X86_64-NEXT: shlq %rcx | |
| ; X86_64-NEXT: movq $128, %rdx | |
| ; X86_64-NEXT: LBB0_4: ## %entry | |
| ; X86_64-NEXT: ## =>This Inner Loop Header: Depth=1 | |
| ; X86_64-NEXT: incsspq %rdx | |
| ; X86_64-NEXT: decq %rcx | |
| ; X86_64-NEXT: jne LBB0_4 | |
| ; X86_64-NEXT: LBB0_5: ## %entry | |
| ; X86_64-NEXT: movq (%rax), %rbp | |
| ; X86_64-NEXT: movq 8(%rax), %rcx | |
| ; X86_64-NEXT: movq 16(%rax), %rsp | |
| ; X86_64-NEXT: jmpq *%rcx | |
| ; | |
| ; X86-LABEL: bar: | |
| ; X86: ## %bb.0: ## %entry | |
| ; X86-NEXT: pushl %ebp | |
| ; X86-NEXT: .cfi_def_cfa_offset 8 | |
| ; X86-NEXT: .cfi_offset %ebp, -8 | |
| ; X86-NEXT: movl L_buf$non_lazy_ptr, %eax | |
| ; X86-NEXT: movl (%eax), %eax | |
| ; X86-NEXT: xorl %edx, %edx | |
| ; X86-NEXT: rdsspd %edx | |
| ; X86-NEXT: testl %edx, %edx | |
| ; X86-NEXT: je LBB0_5 | |
| ; X86-NEXT: ## %bb.1: ## %entry | |
| ; X86-NEXT: movl 12(%eax), %ecx | |
| ; X86-NEXT: subl %edx, %ecx | |
| ; X86-NEXT: jbe LBB0_5 | |
| ; X86-NEXT: ## %bb.2: ## %entry | |
| ; X86-NEXT: shrl $2, %ecx | |
| ; X86-NEXT: incsspd %ecx | |
| ; X86-NEXT: shrl $8, %ecx | |
| ; X86-NEXT: je LBB0_5 | |
| ; X86-NEXT: ## %bb.3: ## %entry | |
| ; X86-NEXT: shll %ecx | |
| ; X86-NEXT: movl $128, %edx | |
| ; X86-NEXT: LBB0_4: ## %entry | |
| ; X86-NEXT: ## =>This Inner Loop Header: Depth=1 | |
| ; X86-NEXT: incsspd %edx | |
| ; X86-NEXT: decl %ecx | |
| ; X86-NEXT: jne LBB0_4 | |
| ; X86-NEXT: LBB0_5: ## %entry | |
| ; X86-NEXT: movl (%eax), %ebp | |
| ; X86-NEXT: movl 4(%eax), %ecx | |
| ; X86-NEXT: movl 8(%eax), %esp | |
| ; X86-NEXT: jmpl *%ecx | |
| entry: | |
| %0 = load i8*, i8** @buf, align 8 | |
| tail call void @llvm.eh.sjlj.longjmp(i8* %0) | |
| unreachable | |
| } | |
| declare void @llvm.eh.sjlj.longjmp(i8*) | |
| ; Functions that call SetJmp should save the current ShadowStackPointer for | |
| ; future fixing of the Shadow Stack. | |
| define i32 @foo(i32 %i) local_unnamed_addr { | |
| ; X86_64-LABEL: foo: | |
| ; X86_64: ## %bb.0: ## %entry | |
| ; X86_64-NEXT: pushq %rbp | |
| ; X86_64-NEXT: .cfi_def_cfa_offset 16 | |
| ; X86_64-NEXT: .cfi_offset %rbp, -16 | |
| ; X86_64-NEXT: movq %rsp, %rbp | |
| ; X86_64-NEXT: .cfi_def_cfa_register %rbp | |
| ; X86_64-NEXT: pushq %r15 | |
| ; X86_64-NEXT: pushq %r14 | |
| ; X86_64-NEXT: pushq %r13 | |
| ; X86_64-NEXT: pushq %r12 | |
| ; X86_64-NEXT: pushq %rbx | |
| ; X86_64-NEXT: pushq %rax | |
| ; X86_64-NEXT: .cfi_offset %rbx, -56 | |
| ; X86_64-NEXT: .cfi_offset %r12, -48 | |
| ; X86_64-NEXT: .cfi_offset %r13, -40 | |
| ; X86_64-NEXT: .cfi_offset %r14, -32 | |
| ; X86_64-NEXT: .cfi_offset %r15, -24 | |
| ; X86_64-NEXT: ## kill: def $edi killed $edi def $rdi | |
| ; X86_64-NEXT: movq %rdi, {{[-0-9]+}}(%r{{[sb]}}p) ## 8-byte Spill | |
| ; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax | |
| ; X86_64-NEXT: movq (%rax), %rax | |
| ; X86_64-NEXT: movq %rbp, (%rax) | |
| ; X86_64-NEXT: movq %rsp, 16(%rax) | |
| ; X86_64-NEXT: leaq {{.*}}(%rip), %rcx | |
| ; X86_64-NEXT: movq %rcx, 8(%rax) | |
| ; X86_64-NEXT: xorq %rcx, %rcx | |
| ; X86_64-NEXT: rdsspq %rcx | |
| ; X86_64-NEXT: movq %rcx, 24(%rax) | |
| ; X86_64-NEXT: #EH_SjLj_Setup LBB1_4 | |
| ; X86_64-NEXT: ## %bb.1: ## %entry | |
| ; X86_64-NEXT: xorl %eax, %eax | |
| ; X86_64-NEXT: testl %eax, %eax | |
| ; X86_64-NEXT: jne LBB1_3 | |
| ; X86_64-NEXT: jmp LBB1_5 | |
| ; X86_64-NEXT: LBB1_4: ## Block address taken | |
| ; X86_64-NEXT: ## %entry | |
| ; X86_64-NEXT: movl $1, %eax | |
| ; X86_64-NEXT: testl %eax, %eax | |
| ; X86_64-NEXT: je LBB1_5 | |
| ; X86_64-NEXT: LBB1_3: ## %if.end | |
| ; X86_64-NEXT: movq {{[-0-9]+}}(%r{{[sb]}}p), %rax ## 8-byte Reload | |
| ; X86_64-NEXT: shll $2, %eax | |
| ; X86_64-NEXT: leal (%rax,%rax,2), %eax | |
| ; X86_64-NEXT: addq $8, %rsp | |
| ; X86_64-NEXT: popq %rbx | |
| ; X86_64-NEXT: popq %r12 | |
| ; X86_64-NEXT: popq %r13 | |
| ; X86_64-NEXT: popq %r14 | |
| ; X86_64-NEXT: popq %r15 | |
| ; X86_64-NEXT: popq %rbp | |
| ; X86_64-NEXT: retq | |
| ; X86_64-NEXT: LBB1_5: ## %if.then | |
| ; X86_64-NEXT: callq _bar | |
| ; X86_64-NEXT: ud2 | |
| ; | |
| ; X86-LABEL: foo: | |
| ; X86: ## %bb.0: ## %entry | |
| ; X86-NEXT: pushl %ebp | |
| ; X86-NEXT: .cfi_def_cfa_offset 8 | |
| ; X86-NEXT: .cfi_offset %ebp, -8 | |
| ; X86-NEXT: movl %esp, %ebp | |
| ; X86-NEXT: .cfi_def_cfa_register %ebp | |
| ; X86-NEXT: pushl %ebx | |
| ; X86-NEXT: pushl %edi | |
| ; X86-NEXT: pushl %esi | |
| ; X86-NEXT: subl $12, %esp | |
| ; X86-NEXT: .cfi_offset %esi, -20 | |
| ; X86-NEXT: .cfi_offset %edi, -16 | |
| ; X86-NEXT: .cfi_offset %ebx, -12 | |
| ; X86-NEXT: movl L_buf$non_lazy_ptr, %eax | |
| ; X86-NEXT: movl (%eax), %eax | |
| ; X86-NEXT: movl %ebp, (%eax) | |
| ; X86-NEXT: movl %esp, 16(%eax) | |
| ; X86-NEXT: movl $LBB1_4, 4(%eax) | |
| ; X86-NEXT: xorl %ecx, %ecx | |
| ; X86-NEXT: rdsspd %ecx | |
| ; X86-NEXT: movl %ecx, 12(%eax) | |
| ; X86-NEXT: #EH_SjLj_Setup LBB1_4 | |
| ; X86-NEXT: ## %bb.1: ## %entry | |
| ; X86-NEXT: xorl %eax, %eax | |
| ; X86-NEXT: testl %eax, %eax | |
| ; X86-NEXT: jne LBB1_3 | |
| ; X86-NEXT: jmp LBB1_5 | |
| ; X86-NEXT: LBB1_4: ## Block address taken | |
| ; X86-NEXT: ## %entry | |
| ; X86-NEXT: movl $1, %eax | |
| ; X86-NEXT: testl %eax, %eax | |
| ; X86-NEXT: je LBB1_5 | |
| ; X86-NEXT: LBB1_3: ## %if.end | |
| ; X86-NEXT: movl 8(%ebp), %eax | |
| ; X86-NEXT: shll $2, %eax | |
| ; X86-NEXT: leal (%eax,%eax,2), %eax | |
| ; X86-NEXT: addl $12, %esp | |
| ; X86-NEXT: popl %esi | |
| ; X86-NEXT: popl %edi | |
| ; X86-NEXT: popl %ebx | |
| ; X86-NEXT: popl %ebp | |
| ; X86-NEXT: retl | |
| ; X86-NEXT: LBB1_5: ## %if.then | |
| ; X86-NEXT: calll _bar | |
| ; X86-NEXT: ud2 | |
| entry: | |
| %0 = load i8*, i8** @buf, align 8 | |
| %1 = bitcast i8* %0 to i8** | |
| %2 = tail call i8* @llvm.frameaddress(i32 0) | |
| store i8* %2, i8** %1, align 8 | |
| %3 = tail call i8* @llvm.stacksave() | |
| %4 = getelementptr inbounds i8, i8* %0, i64 16 | |
| %5 = bitcast i8* %4 to i8** | |
| store i8* %3, i8** %5, align 8 | |
| %6 = tail call i32 @llvm.eh.sjlj.setjmp(i8* %0) | |
| %tobool = icmp eq i32 %6, 0 | |
| br i1 %tobool, label %if.then, label %if.end | |
| if.then: ; preds = %entry | |
| %call = tail call i32 @bar(i32 undef) | |
| unreachable | |
| if.end: ; preds = %entry | |
| %add2 = mul nsw i32 %i, 12 | |
| ret i32 %add2 | |
| } | |
| declare i8* @llvm.frameaddress(i32) | |
| declare i8* @llvm.stacksave() | |
| declare i32 @llvm.eh.sjlj.setjmp(i8*) | |
| !llvm.module.flags = !{!0} | |
| !0 = !{i32 4, !"cf-protection-return", i32 1} |