| # REQUIRES: system-linux |
| |
| # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o |
| # RUN: llvm-strip --strip-unneeded %t.o |
| # RUN: %clang %cflags -no-pie -nostartfiles -nostdlib -lc %t.o -o %t.exe -Wl,-q |
| |
| # RUN: llvm-bolt %t.exe -o %t.exe.bolt --relocs=1 --lite=0 |
| |
| # RUN: %t.exe.bolt |
| |
| ## Check that BOLT's jump table detection diffrentiates between |
| ## __builtin_unreachable() targets and function pointers. |
| |
| ## The test case was built from the following two source files and |
| ## modiffied for standalone build. main became _start, etc. |
| ## $ $(CC) a.c -O1 -S -o a.s |
| ## $ $(CC) b.c -O0 -S -o b.s |
| |
| ## a.c: |
| |
| ## typedef int (*fptr)(int); |
| ## void check_fptr(fptr, int); |
| ## |
| ## int foo(int a) { |
| ## check_fptr(foo, 0); |
| ## switch (a) { |
| ## default: |
| ## __builtin_unreachable(); |
| ## case 0: |
| ## return 3; |
| ## case 1: |
| ## return 5; |
| ## case 2: |
| ## return 7; |
| ## case 3: |
| ## return 11; |
| ## case 4: |
| ## return 13; |
| ## case 5: |
| ## return 17; |
| ## } |
| ## return 0; |
| ## } |
| ## |
| ## int main(int argc) { |
| ## check_fptr(main, 1); |
| ## return foo(argc); |
| ## } |
| ## |
| ## const fptr funcs[2] = {foo, main}; |
| |
| ## b.c.: |
| |
| ## typedef int (*fptr)(int); |
| ## extern const fptr funcs[2]; |
| ## |
| ## #define assert(C) { if (!(C)) (*(unsigned long long *)0) = 0; } |
| ## void check_fptr(fptr f, int i) { |
| ## assert(f == funcs[i]); |
| ## } |
| |
| |
| .text |
| .globl foo |
| .type foo, @function |
| foo: |
| .LFB0: |
| .cfi_startproc |
| pushq %rbx |
| .cfi_def_cfa_offset 16 |
| .cfi_offset 3, -16 |
| movl %edi, %ebx |
| movl $0, %esi |
| movl $foo, %edi |
| call check_fptr |
| movl %ebx, %ebx |
| jmp *.L4(,%rbx,8) |
| .L8: |
| movl $5, %eax |
| jmp .L1 |
| .L7: |
| movl $7, %eax |
| jmp .L1 |
| .L6: |
| movl $11, %eax |
| jmp .L1 |
| .L5: |
| movl $13, %eax |
| jmp .L1 |
| .L3: |
| movl $17, %eax |
| jmp .L1 |
| .L10: |
| movl $3, %eax |
| .L1: |
| popq %rbx |
| .cfi_def_cfa_offset 8 |
| ret |
| .cfi_endproc |
| .LFE0: |
| .size foo, .-foo |
| .globl _start |
| .type _start, @function |
| _start: |
| .LFB1: |
| .cfi_startproc |
| pushq %rbx |
| .cfi_def_cfa_offset 16 |
| .cfi_offset 3, -16 |
| movl %edi, %ebx |
| movl $1, %esi |
| movl $_start, %edi |
| call check_fptr |
| movl $1, %edi |
| call foo |
| popq %rbx |
| .cfi_def_cfa_offset 8 |
| callq exit@PLT |
| .cfi_endproc |
| .LFE1: |
| .size _start, .-_start |
| .globl check_fptr |
| .type check_fptr, @function |
| check_fptr: |
| .LFB2: |
| .cfi_startproc |
| pushq %rbp |
| .cfi_def_cfa_offset 16 |
| .cfi_offset 6, -16 |
| movq %rsp, %rbp |
| .cfi_def_cfa_register 6 |
| movq %rdi, -8(%rbp) |
| movl %esi, -12(%rbp) |
| movl -12(%rbp), %eax |
| cltq |
| movq funcs(,%rax,8), %rax |
| cmpq %rax, -8(%rbp) |
| je .L33 |
| movl $0, %eax |
| movq $0, (%rax) |
| .L33: |
| nop |
| popq %rbp |
| .cfi_def_cfa 7, 8 |
| ret |
| .cfi_endproc |
| |
| .section .rodata |
| .align 8 |
| .align 4 |
| .L4: |
| .quad .L10 |
| .quad .L8 |
| .quad .L7 |
| .quad .L6 |
| .quad .L5 |
| .quad .L3 |
| |
| .globl funcs |
| .type funcs, @object |
| .size funcs, 16 |
| funcs: |
| .quad foo |
| .quad _start |