154 lines · plain
1# This reproduces a bug with instrumentation when trying to instrument2# 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. When4# this does not happen, we need to duplicate the jump table safely, so5# we can split the edges correctly (each copy of the jump table may have6# different split edges). For this to happen, we need to correctly match7# the sequence of instructions that perform the indirect jump to identify8# the base address of the jump table and patch it to point to the new9# cloned JT.10#11# Here we test this variant:12# movq jt.2397(,%rax,8), %rax13# jmp *%rax14#15# Which is suboptimal since the compiler could've avoided using an intermediary16# register, but GCC does generate this code and it triggered a bug in our17# 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-runtime46 47# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \48# RUN: %s -o %t.o49# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q50 51# RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t.fdata \52# RUN: -o %t.instrumented53 54# Instrumented program needs to finish returning zero55# RUN: %t.instrumented 12056 57# Test that the instrumented data makes sense58# 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 %s61 62# RUN: %t.bolted 12063 64# Check that our two indirect jumps are recorded in the fdata file and that65# each has its own independent profile66# 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 .text71 .section .rodata.str1.1,"aMS",@progbits,172.LC0:73 .string "%d\n"74 .text75 .p2align 4,,1576 .globl interp77 .type interp, @function78interp:79.LFB11:80 .cfi_startproc81 pushq %rbp82 .cfi_def_cfa_offset 1683 .cfi_offset 6, -1684 xorl %ebp, %ebp85 pushq %rbx86 .cfi_def_cfa_offset 2487 .cfi_offset 3, -2488 leaq 1(%rdi), %rbx89 subq $8, %rsp90 .cfi_def_cfa_offset 3291 movsbl (%rdi), %eax92 subl $48, %eax93 cltq94 movq jt.2397(,%rax,8), %rax95 jmp *%rax96 .p2align 4,,1097 .p2align 398.L3:99 addl $1, %ebp100.L8:101 movl %ebp, %esi102 movl $.LC0, %edi103 xorl %eax, %eax104 addq $1, %rbx105 call printf106 movsbl -1(%rbx), %eax107 subl $48, %eax108 cltq109 movq jt.2397(,%rax,8), %rax110 jmp *%rax111 .p2align 4,,10112 .p2align 3113.L6:114 addq $8, %rsp115 .cfi_remember_state116 .cfi_def_cfa_offset 24117 movl %ebp, %eax118 popq %rbx119 .cfi_def_cfa_offset 16120 popq %rbp121 .cfi_def_cfa_offset 8122 ret123 .p2align 4,,10124 .p2align 3125.L4:126 .cfi_restore_state127 subl $1, %ebp128 jmp .L8129 .cfi_endproc130.LFE11:131 .size interp, .-interp132 .section .text.startup,"ax",@progbits133 .p2align 4,,15134 .globl main135 .type main, @function136main:137.LFB12:138 .cfi_startproc139 movq 8(%rsi), %rdi140 jmp interp141 .cfi_endproc142.LFE12:143 .size main, .-main144 .section .rodata145 .align 16146 .type jt.2397, @object147 .size jt.2397, 24148jt.2397:149 .quad .L6150 .quad .L3151 .quad .L4152 .ident "GCC: (GNU) 8"153 .section .note.GNU-stack,"",@progbits154