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,81 @@ +# 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 uncommon to end up with dynamic relocations against .rodata, +# but it can happen. In these cases we cannot corrupt the +# output binary by writing out dynamic relocs incorrectly. The linker +# avoids emitting relocs against read-only sections but we override +# this behvior with the -z notext flag. During runtime, these pages +# are mapped with write permission and then changed to read-only after +# the dynamic linker finishes processing the dynamic relocs. + +# In this test, we create a reference to a dynamic object that will +# imply in R_X86_64_64 being used for .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 -shared +# RUN: ld.lld -z notext %t.o -o %t.exe -q %t.so +# 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. + .section .rodata + .align 4 + # We will have a R_X86_64_64 here or R_X86_64_COPY if this section + # is non-writable. We use -z notext to force the linker to accept dynamic + # relocations in read-only sections 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