xref: /llvm-project/bolt/test/X86/jump-table-pic-conflict.s (revision 11791ae7b0b05b8bd8d806331ff51da618912cf8)
1## Check cases when the first PIC jump table entries of one function can be
2## interpreted as valid last entries of the previous function.
3
4## Conditions to trigger the bug:  Function A and B have jump tables that
5## are adjacent in memory. We run in lite relocation mode. Function B
6## is not disassembled because it does not have profile. Function A
7## triggers a special conditional that forced BOLT to rewrite its jump
8## table in-place (instead of moving it) because it is marked as
9## non-simple (in this case, containing unknown control flow). The
10## first entry of B's jump table (a PIC offset) happens to be a valid
11## address inside A when added to A's jump table base address. In this
12## case, BOLT could overwrite B's jump table, corrupting it, thinking
13## the first entry of it is actually part of A's jump table.
14
15# REQUIRES: system-linux
16
17# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
18# RUN:   %s -o %t.o
19# RUN: link_fdata %s %t.o %t.fdata
20# RUN: llvm-strip --strip-unneeded %t.o
21# RUN: ld.lld %t.o -o %t.exe -q -T %S/Inputs/jt-pic-linkerscript.ld
22# RUN: llvm-bolt %t.exe -relocs -o %t.out -data %t.fdata \
23# RUN:     -lite=1
24# RUN: llvm-readelf -S %t.out | FileCheck --check-prefix=CHECK %s
25# The output binary is runnable, but we check for test success with
26# readelf. This is another way to check this bug:
27# COM: %t.out
28
29## BOLT needs to create a new rodata section, indicating that it
30## successfully moved the jump table in _start.
31# CHECK: [{{.*}}] .bolt.org.rodata
32
33  .globl _start
34  .type _start, %function
35_start:
36  .cfi_startproc
37# FDATA: 0 [unknown] 0 1 _start 0 0 1
38  push    %rbp
39  mov     %rsp, %rbp
40  mov     0x8(%rbp), %rdi
41  cmpq    $3, %rdi
42  ja      .L5
43  jmp     .L6
44## Unreachable code, here to mark this function as non-simple
45## (containing unknown control flow) with a stray indirect jmp
46  jmp     *%rax
47.L6:
48  decq    %rdi
49  leaq    .LJT1(%rip), %rcx
50  movslq  (%rcx, %rdi, 4), %rax
51  addq    %rcx, %rax
52  jmp     *%rax
53.L1:
54  leaq    str1(%rip), %rsi
55  jmp     .L4
56.L2:
57  leaq    str2(%rip), %rsi
58  jmp     .L4
59.L3:
60  leaq    str3(%rip), %rsi
61  jmp     .L4
62.L5:
63  leaq    str4(%rip), %rsi
64.L4:
65  movq    $1, %rdi
66  movq    $10, %rdx
67  movq    $1, %rax
68  syscall
69  mov     0x8(%rbp), %rdi
70  decq    %rdi
71  callq   func_b
72  movq    %rax, %rdi
73  movq    $231, %rax
74  syscall
75  pop     %rbp
76  ret
77  .cfi_endproc
78  .size _start, .-_start
79
80  .globl func_b
81  .type func_b, %function
82func_b:
83  .cfi_startproc
84  push    %rbp
85  mov     %rsp, %rbp
86  cmpq    $3, %rdi
87  ja      .L2_6
88# FT
89  leaq    .LJT2(%rip), %rcx
90  movslq  (%rcx, %rdi, 4), %rax
91  addq    %rcx, %rax
92  jmp     *%rax
93.L2_1:
94  movq    $0, %rax
95  jmp     .L2_5
96.L2_2:
97  movq    $1, %rax
98  jmp     .L2_5
99.L2_3:
100  movq    $2, %rax
101  jmp     .L2_5
102.L2_4:
103  movq    $3, %rax
104  jmp     .L2_5
105.L2_6:
106  movq    $-1, %rax
107.L2_5:
108  popq    %rbp
109  ret
110  .cfi_endproc
111  .size func_b, .-func_b
112
113  .rodata
114str1: .asciz "Message 1\n"
115str2: .asciz "Message 2\n"
116str3: .asciz "Message 3\n"
117str4: .asciz "Highrange\n"
118## Special case where the first .LJT2 entry is a valid offset of
119## _start when interpreted with .LJT1 as a base address.
120.LJT1:
121  .long .L1-.LJT1
122  .long .L2-.LJT1
123  .long .L3-.LJT1
124  .long .L3-.LJT1
125  .long .L3-.LJT1
126  .long .L3-.LJT1
127  .long .L3-.LJT1
128.LJT2:
129  .long .L2_1-.LJT2
130  .long .L2_2-.LJT2
131  .long .L2_3-.LJT2
132  .long .L2_4-.LJT2
133