File: jump-table-pic-conflict.s

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (132 lines) | stat: -rw-r--r-- 3,338 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# 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