mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 23:06:34 +00:00
133 lines
3.3 KiB
ArmAsm
133 lines
3.3 KiB
ArmAsm
## Check cases when the first PIC jump table entries of one function can be
|
|
## interpreted as valid last entries of the previous function.
|
|
|
|
## Conditions to trigger the bug: Function A and B have jump tables that
|
|
## are adjacent in memory. We run in lite relocation mode. Function B
|
|
## is not disassembled because it does not have profile. Function A
|
|
## triggers a special conditional that forced BOLT to rewrite its jump
|
|
## table in-place (instead of moving it) because it is marked as
|
|
## non-simple (in this case, containing unknown control flow). The
|
|
## first entry of B's jump table (a PIC offset) happens to be a valid
|
|
## address inside A when added to A's jump table base address. In this
|
|
## case, BOLT could overwrite B's jump table, corrupting it, thinking
|
|
## the first entry of it is actually part of A's jump table.
|
|
|
|
# REQUIRES: system-linux
|
|
|
|
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \
|
|
# RUN: %s -o %t.o
|
|
# RUN: link_fdata %s %t.o %t.fdata
|
|
# RUN: llvm-strip --strip-unneeded %t.o
|
|
# RUN: ld.lld %t.o -o %t.exe -q -T %S/Inputs/jt-pic-linkerscript.ld
|
|
# RUN: llvm-bolt %t.exe -relocs -o %t.out -data %t.fdata \
|
|
# RUN: -lite=1
|
|
# RUN: llvm-readelf -S %t.out | FileCheck --check-prefix=CHECK %s
|
|
# The output binary is runnable, but we check for test success with
|
|
# readelf. This is another way to check this bug:
|
|
# COM: %t.out
|
|
|
|
## BOLT needs to create a new rodata section, indicating that it
|
|
## successfully moved the jump table in _start.
|
|
# CHECK: [{{.*}}] .bolt.org.rodata
|
|
|
|
.globl _start
|
|
.type _start, %function
|
|
_start:
|
|
.cfi_startproc
|
|
# FDATA: 0 [unknown] 0 1 _start 0 0 1
|
|
push %rbp
|
|
mov %rsp, %rbp
|
|
mov 0x8(%rbp), %rdi
|
|
cmpq $3, %rdi
|
|
ja .L5
|
|
jmp .L6
|
|
## Unreachable code, here to mark this function as non-simple
|
|
## (containing unknown control flow) with a stray indirect jmp
|
|
jmp *%rax
|
|
.L6:
|
|
decq %rdi
|
|
leaq .LJT1(%rip), %rcx
|
|
movslq (%rcx, %rdi, 4), %rax
|
|
addq %rcx, %rax
|
|
jmp *%rax
|
|
.L1:
|
|
leaq str1(%rip), %rsi
|
|
jmp .L4
|
|
.L2:
|
|
leaq str2(%rip), %rsi
|
|
jmp .L4
|
|
.L3:
|
|
leaq str3(%rip), %rsi
|
|
jmp .L4
|
|
.L5:
|
|
leaq str4(%rip), %rsi
|
|
.L4:
|
|
movq $1, %rdi
|
|
movq $10, %rdx
|
|
movq $1, %rax
|
|
syscall
|
|
mov 0x8(%rbp), %rdi
|
|
decq %rdi
|
|
callq func_b
|
|
movq %rax, %rdi
|
|
movq $231, %rax
|
|
syscall
|
|
pop %rbp
|
|
ret
|
|
.cfi_endproc
|
|
.size _start, .-_start
|
|
|
|
.globl func_b
|
|
.type func_b, %function
|
|
func_b:
|
|
.cfi_startproc
|
|
push %rbp
|
|
mov %rsp, %rbp
|
|
cmpq $3, %rdi
|
|
ja .L2_6
|
|
# FT
|
|
leaq .LJT2(%rip), %rcx
|
|
movslq (%rcx, %rdi, 4), %rax
|
|
addq %rcx, %rax
|
|
jmp *%rax
|
|
.L2_1:
|
|
movq $0, %rax
|
|
jmp .L2_5
|
|
.L2_2:
|
|
movq $1, %rax
|
|
jmp .L2_5
|
|
.L2_3:
|
|
movq $2, %rax
|
|
jmp .L2_5
|
|
.L2_4:
|
|
movq $3, %rax
|
|
jmp .L2_5
|
|
.L2_6:
|
|
movq $-1, %rax
|
|
.L2_5:
|
|
popq %rbp
|
|
ret
|
|
.cfi_endproc
|
|
.size func_b, .-func_b
|
|
|
|
.rodata
|
|
str1: .asciz "Message 1\n"
|
|
str2: .asciz "Message 2\n"
|
|
str3: .asciz "Message 3\n"
|
|
str4: .asciz "Highrange\n"
|
|
## Special case where the first .LJT2 entry is a valid offset of
|
|
## _start when interpreted with .LJT1 as a base address.
|
|
.LJT1:
|
|
.long .L1-.LJT1
|
|
.long .L2-.LJT1
|
|
.long .L3-.LJT1
|
|
.long .L3-.LJT1
|
|
.long .L3-.LJT1
|
|
.long .L3-.LJT1
|
|
.long .L3-.LJT1
|
|
.LJT2:
|
|
.long .L2_1-.LJT2
|
|
.long .L2_2-.LJT2
|
|
.long .L2_3-.LJT2
|
|
.long .L2_4-.LJT2
|