1# This reproduces a bug with instrumentation when trying to instrument 2# functions that share a jump table with multiple indirect jumps. Usually, 3# each indirect jump that uses a JT will have its own copy of it. When 4# this does not happen, we need to duplicate the jump table safely, so 5# we can split the edges correctly (each copy of the jump table may have 6# different split edges). For this to happen, we need to correctly match 7# the sequence of instructions that perform the indirect jump to identify 8# the base address of the jump table and patch it to point to the new 9# cloned JT. 10# 11# Here we test this variant: 12# movq jt.2397(,%rax,8), %rax 13# jmp *%rax 14# 15# Which is suboptimal since the compiler could've avoided using an intermediary 16# register, but GCC does generate this code and it triggered a bug in our 17# matcher. Usual jumps in non-PIC code have this format: 18# 19# jmp *jt.2397(,%rax,8) 20# 21# This is the C code fed to GCC: 22# #include <stdio.h> 23#int interp(char* code) { 24# static void* jt[] = { &&op_end, &&op_inc, &&do_dec }; 25# int pc = 0; 26# int res = 0; 27# goto *jt[code[pc++] - '0']; 28# 29#op_inc: 30# res += 1; 31# printf("%d\n", res); 32# goto *jt[code[pc++] - '0']; 33#do_dec: 34# res -= 1; 35# printf("%d\n", res); 36# goto *jt[code[pc++] - '0']; 37#op_end: 38# return res; 39#} 40#int main(int argc, char** argv) { 41# return interp(argv[1]); 42#} 43 44 45# REQUIRES: system-linux,bolt-runtime 46 47# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ 48# RUN: %s -o %t.o 49# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q 50 51# RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t.fdata \ 52# RUN: -o %t.instrumented 53 54# Instrumented program needs to finish returning zero 55# RUN: %t.instrumented 120 56 57# Test that the instrumented data makes sense 58# RUN: llvm-bolt %t.exe -o %t.bolted --data %t.fdata \ 59# RUN: --reorder-blocks=ext-tsp --reorder-functions=hfsort+ \ 60# RUN: --print-only=interp --print-finalized | FileCheck %s 61 62# RUN: %t.bolted 120 63 64# Check that our two indirect jumps are recorded in the fdata file and that 65# each has its own independent profile 66# CHECK: Successors: .Ltmp1 (mispreds: 0, count: 1), .Ltmp0 (mispreds: 0, count: 0), .Ltmp2 (mispreds: 0, count: 0) 67# CHECK: Successors: .Ltmp0 (mispreds: 0, count: 1), .Ltmp2 (mispreds: 0, count: 1), .Ltmp1 (mispreds: 0, count: 0) 68 69 .file "test.c" 70 .text 71 .section .rodata.str1.1,"aMS",@progbits,1 72.LC0: 73 .string "%d\n" 74 .text 75 .p2align 4,,15 76 .globl interp 77 .type interp, @function 78interp: 79.LFB11: 80 .cfi_startproc 81 pushq %rbp 82 .cfi_def_cfa_offset 16 83 .cfi_offset 6, -16 84 xorl %ebp, %ebp 85 pushq %rbx 86 .cfi_def_cfa_offset 24 87 .cfi_offset 3, -24 88 leaq 1(%rdi), %rbx 89 subq $8, %rsp 90 .cfi_def_cfa_offset 32 91 movsbl (%rdi), %eax 92 subl $48, %eax 93 cltq 94 movq jt.2397(,%rax,8), %rax 95 jmp *%rax 96 .p2align 4,,10 97 .p2align 3 98.L3: 99 addl $1, %ebp 100.L8: 101 movl %ebp, %esi 102 movl $.LC0, %edi 103 xorl %eax, %eax 104 addq $1, %rbx 105 call printf 106 movsbl -1(%rbx), %eax 107 subl $48, %eax 108 cltq 109 movq jt.2397(,%rax,8), %rax 110 jmp *%rax 111 .p2align 4,,10 112 .p2align 3 113.L6: 114 addq $8, %rsp 115 .cfi_remember_state 116 .cfi_def_cfa_offset 24 117 movl %ebp, %eax 118 popq %rbx 119 .cfi_def_cfa_offset 16 120 popq %rbp 121 .cfi_def_cfa_offset 8 122 ret 123 .p2align 4,,10 124 .p2align 3 125.L4: 126 .cfi_restore_state 127 subl $1, %ebp 128 jmp .L8 129 .cfi_endproc 130.LFE11: 131 .size interp, .-interp 132 .section .text.startup,"ax",@progbits 133 .p2align 4,,15 134 .globl main 135 .type main, @function 136main: 137.LFB12: 138 .cfi_startproc 139 movq 8(%rsi), %rdi 140 jmp interp 141 .cfi_endproc 142.LFE12: 143 .size main, .-main 144 .section .rodata 145 .align 16 146 .type jt.2397, @object 147 .size jt.2397, 24 148jt.2397: 149 .quad .L6 150 .quad .L3 151 .quad .L4 152 .ident "GCC: (GNU) 8" 153 .section .note.GNU-stack,"",@progbits 154