diff --git a/bolt/test/X86/Inputs/define_bar.s b/bolt/test/X86/Inputs/define_bar.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/Inputs/define_bar.s @@ -0,0 +1,7 @@ +# Mocks a vtable object weak def in the C++ stdlib. + .data.rel.ro + .weak bar + .type bar, %object +bar: + .space 20 + .size bar, 20 diff --git a/bolt/test/X86/dynrelocs.s b/bolt/test/X86/dynrelocs.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/dynrelocs.s @@ -0,0 +1,88 @@ +# This reproduces a bug when rewriting dynamic relocations in X86 as +# BOLT incorrectly attributes R_X86_64_64 dynamic relocations +# to the wrong section when the -jump-tables=move flag is used. We +# expect the relocations to belong to the .bolt.org.rodata section but +# it is attributed to a new .rodata section that only contains jump +# table entries, created by BOLT. BOLT will only create this new .rodata +# section if both -jump-tables=move is used and a hot function with +# jt is present in the input binary, triggering a scenario where the +# dynamic relocs rewriting gets confused on where to put .rodata relocs. + +# It is hard and perhaps even technically incorrect to end up with +# dynamic relocations against .rodata, but because this happens in the +# wild, we need to at least do not corrupt the output binary by +# writing out dynamic relocs incorrectly. That's why we use a linker +# script below, otherwise it won't accept outputting R_X86_64_64 in +# a read-only section. .data.rel.ro can alternatively be used to put +# constants at start time after the dynamic linker runs (it will run +# and map pages as read-only after patching relocs), so it is a +# section that accepts direct references to dynamic symbols and does +# not need to create PLT entries or COPY relocs. In this test, we +# create a reference to a dynamic object that will imply in +# R_X86_64_64 being used for .data.rel.ro, and we when rename the +# section via linker script to .rodata. Now BOLT, when creating a new +# .rodata to hold jump table entries, needs to remember to emit these +# dynamic relocs against the original .rodata, and not the new one it +# just created. + +# REQUIRES: system-linux +# Currently XFAIL as we do not support it. +# XFAIL: * + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux \ +# RUN: %s -o %t.o +# RUN: link_fdata %s %t.o %t.fdata +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux \ +# RUN: %p/Inputs/define_bar.s -o %t.2.o +# RUN: llvm-strip --strip-unneeded %t.o +# RUN: ld.lld %t.2.o -o %t.so -q -shared +# RUN: echo "SECTIONS { \ +# RUN: .rodata : { *(.data.rel.ro) } \ +# RUN: }" > %t.script +# RUN: ld.lld --script %t.script %t.o -o %t.exe -q %t.so -z text +# RUN: llvm-bolt -data %t.fdata %t.exe -relocs -o %t.out -lite=0 \ +# RUN: -jump-tables=move +# RUN: llvm-readobj -rs %t.out | FileCheck --check-prefix=READOBJ %s + +# Verify that BOLT outputs the dynamic reloc at the correct address, +# which is the start of the .bolt.org.rodata section. +# READOBJ: Relocations [ +# READOBJ: Section ([[#]]) .rela.dyn { +# READOBJ-NEXT: 0x[[#%X,ADDR:]] R_X86_64_64 bar 0x10 +# READOBJ: Symbols [ +# READOBJ: Name: .bolt.org.rodata +# READOBJ-NEXT: Value: 0x[[#ADDR]] + + # Create a hot function with jump table + .text + .globl _start + .type _start, %function +_start: + .cfi_startproc +# FDATA: 0 [unknown] 0 1 _start 0 0 6 + movq .LJUMPTABLE(,%rdi,8), %rax +b: jmpq *%rax +# FDATA: 1 _start #b# 1 _start #c# 0 3 +c: + mov $1, %rax +d: + xorq %rax, %rax + ret + .cfi_endproc + .size _start, .-_start + + # This is the section that needs to be tested. This is transformed into .rodata + # via linker script. + .section .data.rel.ro + .align 4 + # We will have a R_X86_64_64 here or R_X86_64_COPY if this section + # is non-writable. We name it .data.rel.ro to give it write access + # and make it a R_X86_64_64. + .quad bar + 16 # Reference a dynamic object (such as a vtable ref) + # Add other contents to this section: a hot jump table that will be + # copied by BOLT into a new section. +.LJUMPTABLE: + .quad c + .quad c + .quad d + .quad d