| ; 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} |