|
| 1 | +## This test checks that disassemble stage works properly |
| 2 | +## JT with indirect branch |
| 3 | +## 1) nop + adr pair instructions |
| 4 | +## 2) sub + ldr pair instructions |
| 5 | +## 3) adrp + ldr pair instructions |
| 6 | +## 4) pic jt with relive offsets packed to 1-byte entry size |
| 7 | +## 5) fixed indirect branch |
| 8 | +## 6) normal jt |
| 9 | + |
| 10 | +# REQUIRES: system-linux |
| 11 | + |
| 12 | +# RUN: rm -rf %t && split-file %s %t |
| 13 | + |
| 14 | +## Prepare binary (1) |
| 15 | +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/jt_nop_adr.s \ |
| 16 | +# RUN: -o %t/jt_nop_adr.o |
| 17 | +# RUN: %clang %cflags --target=aarch64-unknown-linux %t/jt_nop_adr.o \ |
| 18 | +# RUN: -Wl,-q -Wl,-z,now, -Wl,-T,%t/within-adr-range.t -o %t/jt_nop_adr.exe |
| 19 | +# RUN: llvm-objdump --no-show-raw-insn -d %t/jt_nop_adr.exe | FileCheck \ |
| 20 | +# RUN: --check-prefix=JT-RELAXED %s |
| 21 | + |
| 22 | +# JT-RELAXED: <_start>: |
| 23 | +# JT-RELAXED-NEXT: nop |
| 24 | +# JT-RELAXED-NEXT: adr {{.*}}x3 |
| 25 | + |
| 26 | +# RUN: llvm-bolt %t/jt_nop_adr.exe -o %t/jt_nop_adr.bolt -v 3 2>&1 | FileCheck \ |
| 27 | +# RUN: --check-prefix=JT-BOLT-RELAXED %s |
| 28 | + |
| 29 | +# JT-BOLT-RELAXED: failed to match indirect branch |
| 30 | + |
| 31 | +## This linker script ensures that .rodata and .text are sufficiently (<1M) |
| 32 | +## close to each other so that the adrp + ldr pair can be relaxed to nop + adr. |
| 33 | +#--- within-adr-range.t |
| 34 | +SECTIONS { |
| 35 | + .rodata 0x1000: { *(.rodata) } |
| 36 | + .text 0x2000: { *(.text) } |
| 37 | + .rela.rodata : { *(.rela.rodata) } |
| 38 | +} |
| 39 | + |
| 40 | +## Prepare binary (2) |
| 41 | +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/jt_sub_ldr.s \ |
| 42 | +# RUN: -o %t/jt_sub_ldr.o |
| 43 | +# RUN: %clang %cflags --target=aarch64-unknown-linux %t/jt_sub_ldr.o \ |
| 44 | +# RUN: -Wl,-q -Wl,-z,now -o %t/jt_sub_ldr.exe |
| 45 | +# RUN: llvm-objdump --no-show-raw-insn -d %t/jt_sub_ldr.exe | FileCheck \ |
| 46 | +# RUN: --check-prefix=JT-SUB-LDR %s |
| 47 | + |
| 48 | +# JT-SUB-LDR: <_start>: |
| 49 | +# JT-SUB-LDR-NEXT: sub |
| 50 | +# JT-SUB-LDR-NEXT: ldr |
| 51 | + |
| 52 | +# RUN: llvm-bolt %t/jt_sub_ldr.exe -o %t/jt_sub_ldr.bolt -v 3 2>&1 | FileCheck \ |
| 53 | +# RUN: --check-prefix=JT-BOLT-SUBLDR %s |
| 54 | +# JT-BOLT-SUBLDR: failed to match indirect branch |
| 55 | + |
| 56 | +## Prepare binary (3) |
| 57 | +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/jt_adrp_ldr.s \ |
| 58 | +# RUN: -o %t/jt_adrp_ldr.o |
| 59 | +# RUN: %clang %cflags --target=aarch64-unknown-linux %t/jt_adrp_ldr.o \ |
| 60 | +# RUN: -Wl,-q -Wl,-z,now -Wl,--no-relax -o %t/jt_adrp_ldr.exe |
| 61 | +# RUN: llvm-objdump --no-show-raw-insn -d %t/jt_adrp_ldr.exe | FileCheck \ |
| 62 | +# RUN: --check-prefix=JT-ADRP-LDR %s |
| 63 | + |
| 64 | +# JT-ADRP-LDR: <_start>: |
| 65 | +# JT-ADRP-LDR-NEXT: adrp |
| 66 | +# JT-ADRP-LDR-NEXT: ldr |
| 67 | + |
| 68 | +# RUN: llvm-bolt %t/jt_adrp_ldr.exe -o %t/jt_adrp_ldr.bolt -v 3 2>&1 | FileCheck \ |
| 69 | +# RUN: --check-prefix=JT-BOLT-ADRP-LDR %s |
| 70 | +# JT-BOLT-ADRP-LDR: failed to match indirect branch |
| 71 | + |
| 72 | +## Prepare binary (4) |
| 73 | +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \ |
| 74 | +# RUN: --position-independent %t/jt_pic_with_relative_offset.s \ |
| 75 | +# RUN: -o %t/jt_pic_with_relative_offset.o |
| 76 | +# RUN: %clang %cflags -fPIC -O0 %t/jt_pic_with_relative_offset.o \ |
| 77 | +# RUN: -o %t/jt_pic_with_relative_offset.exe -Wl,-q -Wl,--no-relax |
| 78 | +# RUN: llvm-bolt %t/jt_pic_with_relative_offset.exe \ |
| 79 | +# RUN: -o %t/jt_pic_with_relative_offset.bolt -v 3 2>&1 | FileCheck \ |
| 80 | +# RUN: --check-prefix=JT-BOLT-JT-PIC-OFFSETS %s |
| 81 | + |
| 82 | +# JT-BOLT-JT-PIC-OFFSETS: failed to match indirect branch |
| 83 | + |
| 84 | +## Prepare binary (5) |
| 85 | +# RUN: %clang %cflags %t/jt_fixed_branch.s -Wl,-q -Wl,--no-relax \ |
| 86 | +# RUN: -o %t/jt_fixed_branch.exe |
| 87 | + |
| 88 | +# RUN: llvm-bolt %t/jt_fixed_branch.exe \ |
| 89 | +# RUN: -o %t/jt_fixed_branch.bolt -v 3 2>&1 | FileCheck \ |
| 90 | +# RUN: --check-prefix=JT-BOLT-FIXED-BR %s |
| 91 | + |
| 92 | +# JT-BOLT-FIXED-BR: failed to match indirect branch |
| 93 | + |
| 94 | +## Prepare binary (6) |
| 95 | +# RUN: %clang %cflags -no-pie %t/jt_type_normal.c \ |
| 96 | +# RUN: -Wl,-q -Wl,-z,now -Wl,--no-relax \ |
| 97 | +# RUN: -o %t/jt_type_normal.exe |
| 98 | +# RUN: llvm-objdump --no-show-raw-insn -d %t/jt_type_normal.exe | FileCheck \ |
| 99 | +# RUN: --check-prefix=JT-OBJDUMP-NORMAL %s |
| 100 | + |
| 101 | +# JT-OBJDUMP-NORMAL: <handleOptionJumpTable>: |
| 102 | +# JT-OBJDUMP-NORMAL: adrp |
| 103 | +# JT-OBJDUMP-NORMAL-NEXT: add |
| 104 | +# JT-OBJDUMP-NORMAL-NEXT: ldr |
| 105 | +# JT-OBJDUMP-NORMAL-NEXT: blr |
| 106 | + |
| 107 | +# RUN: llvm-bolt %t/jt_type_normal.exe --dyno-stats \ |
| 108 | +# RUN: -o %t/jt_type_normal.bolt -v 3 2>&1 | FileCheck \ |
| 109 | +# RUN: --check-prefix=JT-BOLT-NORMAL %s |
| 110 | + |
| 111 | +# JT-BOLT-NORMAL: 0{{.*}}: indirect calls |
| 112 | + |
| 113 | +#--- jt_nop_adr.s |
| 114 | + .globl _start |
| 115 | + .type _start, %function |
| 116 | +_start: |
| 117 | + adrp x3, :got:jump_table |
| 118 | + ldr x3, [x3, #:got_lo12:jump_table] |
| 119 | + ldrh w3, [x3, x1, lsl #1] |
| 120 | + adr x1, test2_0 |
| 121 | + add x3, x1, w3, sxth #2 |
| 122 | + br x3 |
| 123 | +test2_0: |
| 124 | + ret |
| 125 | +test2_1: |
| 126 | + ret |
| 127 | + |
| 128 | + .section .rodata,"a",@progbits |
| 129 | +jump_table: |
| 130 | + .hword (test2_0-test2_0)>>2 |
| 131 | + .hword (test2_1-test2_0)>>2 |
| 132 | + |
| 133 | + |
| 134 | +#--- jt_sub_ldr.s |
| 135 | + .globl _start |
| 136 | + .type _start, %function |
| 137 | +_start: |
| 138 | + sub x1, x29, #0x4, lsl #12 |
| 139 | + ldr x1, [x1, #14352] |
| 140 | + ldrh w1, [x1, w3, uxtw #1] |
| 141 | + adr x3, test2_0 |
| 142 | + add x1, x3, w1, sxth #2 |
| 143 | + br x1 |
| 144 | +test2_0: |
| 145 | + ret |
| 146 | +test2_1: |
| 147 | + ret |
| 148 | + |
| 149 | + .section .rodata,"a",@progbits |
| 150 | +jump_table: |
| 151 | + .hword (test2_0-test2_0)>>2 |
| 152 | + .hword (test2_1-test2_0)>>2 |
| 153 | + |
| 154 | + |
| 155 | +#--- jt_adrp_ldr.s |
| 156 | + .globl _start |
| 157 | + .type _start, %function |
| 158 | +_start: |
| 159 | + adrp x3, :got:jump_table |
| 160 | + ldr x3, [x3, #:got_lo12:jump_table] |
| 161 | + ldrh w3, [x3, x1, lsl #1] |
| 162 | + adr x1, test2_0 |
| 163 | + add x3, x1, w3, sxth #2 |
| 164 | + br x3 |
| 165 | +test2_0: |
| 166 | + ret |
| 167 | +test2_1: |
| 168 | + ret |
| 169 | + |
| 170 | + .section .rodata,"a",@progbits |
| 171 | +jump_table: |
| 172 | + .hword (test2_0-test2_0)>>2 |
| 173 | + .hword (test2_1-test2_0)>>2 |
| 174 | + |
| 175 | + |
| 176 | +#--- jt_pic_with_relative_offset.s |
| 177 | +.text |
| 178 | +.global _start |
| 179 | +_start: |
| 180 | + mov x4, 3 // index in jmp table where offset related to adr instr |
| 181 | + adrp x0, funcTableSym |
| 182 | + add x0, x0, #:lo12:funcTableSym |
| 183 | + ldrb w0, [x0, w4, uxtw #0] |
| 184 | + adr x2, .LBB1 |
| 185 | + add x0, x2, w0, sxth #2 |
| 186 | + br x0 |
| 187 | + |
| 188 | +.LBB1: |
| 189 | + bl funcA |
| 190 | + b .test_exit |
| 191 | + |
| 192 | +.LBB2: |
| 193 | + bl funcB |
| 194 | + b .test_exit |
| 195 | + |
| 196 | +.LBB3: |
| 197 | + bl funcC |
| 198 | + b .test_exit |
| 199 | + |
| 200 | +.LBB4: |
| 201 | + bl funcD |
| 202 | + b .test_exit |
| 203 | + |
| 204 | +.test_exit: |
| 205 | + mov x8, #93 |
| 206 | + mov x0, #0 |
| 207 | + svc #0 |
| 208 | + |
| 209 | +.global funcA |
| 210 | +funcA: |
| 211 | + ret |
| 212 | + |
| 213 | +.global funcB |
| 214 | +funcB: |
| 215 | + ret |
| 216 | + |
| 217 | +.global funcC |
| 218 | +funcC: |
| 219 | + ret |
| 220 | + |
| 221 | +.global funcD |
| 222 | +funcD: |
| 223 | + ret |
| 224 | + |
| 225 | +.section .rodata,"a",@progbits |
| 226 | +.align 2 |
| 227 | +funcTableSym: |
| 228 | + .byte 0x00,0x02,0x04,0x06 // 1 - .LBB1, 3 - .LBB2 |
| 229 | + |
| 230 | +#--- jt_fixed_branch.s |
| 231 | + |
| 232 | +.text |
| 233 | +.global _start |
| 234 | +_start: |
| 235 | + mov x0, x13 |
| 236 | + mov x1, x4 |
| 237 | + mov x0, x2 |
| 238 | + movk x1, #0x0, lsl #48 |
| 239 | + movk x1, #0x0, lsl #32 |
| 240 | + movk x1, #0x0, lsl #16 |
| 241 | + movk x1, #0x12 |
| 242 | + stp x0, x1, [sp, #-16]! |
| 243 | + adrp x0, foo |
| 244 | + add x0, x0, #:lo12:foo |
| 245 | + br x0 |
| 246 | + mov x8, #93 |
| 247 | + mov x0, #0 |
| 248 | + svc #0 |
| 249 | + |
| 250 | +.global foo |
| 251 | +.type foo,%function |
| 252 | +foo: |
| 253 | + mov x8, #9 |
| 254 | + ret |
| 255 | +.size foo,.-foo |
| 256 | + |
| 257 | +#--- jt_type_normal.c |
| 258 | + |
| 259 | +void __attribute__ ((noinline)) option0() { |
| 260 | +} |
| 261 | + |
| 262 | +void __attribute__ ((noinline)) option1() { |
| 263 | +} |
| 264 | + |
| 265 | +void __attribute__ ((noinline)) option2() { |
| 266 | +} |
| 267 | + |
| 268 | +void __attribute__ ((noinline)) option3() { |
| 269 | +} |
| 270 | + |
| 271 | +void __attribute__ ((noinline)) option4() { |
| 272 | +} |
| 273 | + |
| 274 | +void __attribute__ ((noinline)) option5() { |
| 275 | +} |
| 276 | + |
| 277 | +void (*jumpTable[6])() = { option0, option1, option2, option3, option4, option5 }; |
| 278 | + |
| 279 | +void __attribute__ ((noinline)) handleOptionJumpTable(int option) { |
| 280 | + jumpTable[option](); |
| 281 | +} |
| 282 | + |
| 283 | +int main(int argc, char *argv[]) { |
| 284 | + handleOptionJumpTable(argc); |
| 285 | + return 0; |
| 286 | +} |
0 commit comments