diff --git a/bolt/include/bolt/Core/JumpTable.h b/bolt/include/bolt/Core/JumpTable.h --- a/bolt/include/bolt/Core/JumpTable.h +++ b/bolt/include/bolt/Core/JumpTable.h @@ -120,7 +120,7 @@ MCSymbol *NewDest); /// Update jump table at its original location. - void updateOriginal(); + void updateOriginal(bool Zero); /// Print for debugging purposes. void print(raw_ostream &OS) const override; diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -745,7 +745,7 @@ if (opts::PrintJumpTables) JT.print(outs()); if (opts::JumpTables == JTS_BASIC && BC.HasRelocations) { - JT.updateOriginal(); + JT.updateOriginal(/*Zero=*/false); } else { MCSection *HotSection, *ColdSection; if (opts::JumpTables == JTS_BASIC) { @@ -768,6 +768,7 @@ HotSection = BF.hasProfile() ? ReadOnlySection : ReadOnlyColdSection; ColdSection = HotSection; } + JT.updateOriginal(/*Zero=*/true); } emitJumpTable(JT, HotSection, ColdSection); } diff --git a/bolt/lib/Core/JumpTable.cpp b/bolt/lib/Core/JumpTable.cpp --- a/bolt/lib/Core/JumpTable.cpp +++ b/bolt/lib/Core/JumpTable.cpp @@ -79,7 +79,7 @@ return Patched; } -void bolt::JumpTable::updateOriginal() { +void bolt::JumpTable::updateOriginal(bool Zero) { BinaryContext &BC = getSection().getBinaryContext(); const uint64_t BaseOffset = getAddress() - getSection().getAddress(); uint64_t EntryOffset = BaseOffset; @@ -92,6 +92,8 @@ // to the original jump table. if (BC.HasRelocations) getOutputSection().removeRelocationAt(EntryOffset); + if (Zero) + Entry = BC.registerNameAtAddress("Zero", 0, 0, 0); getOutputSection().addRelocation(EntryOffset, Entry, RelType, RelAddend); EntryOffset += EntrySize; } diff --git a/bolt/test/X86/normalize-jump-table-target.s b/bolt/test/X86/normalize-jump-table-target.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/normalize-jump-table-target.s @@ -0,0 +1,41 @@ +# This test reproduces an issue with removing a basic block which is referenced +# from rodata section ("externally referenced offset"/jump table target). +# If the block is removed (by remove-nops + NormalizeCFG), and BOLT updates the +# original jump table (with jump-tables=move), this causes an emission error +# (undefined temporary symbol). + +# REQUIRES: system-linux,bolt-runtime + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang -no-pie %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.out --instrument --instrumentation-file=%t.tmp \ +# RUN: 2>&1 | FileCheck %s --check-prefix=CHECK-BOLT + +# CHECK-BOLT-NOT: undefined temporary symbol + +# Grab the jump table address in original text section (.bolt.org.text) +# RUN: llvm-objdump -dj.bolt.org.text %t.out > %t.log +# Inspect jump table entries, should be two zero values +# RUN: llvm-objdump -sj.rodata %t.out >> %t.log +# RUN: FileCheck %s --input-file %t.log --check-prefix=CHECK-OBJDUMP + +# CHECK-OBJDUMP: jmpq *0x[[#%x,JTADDR:]](,%rax,8) +# CHECK-OBJDUMP: [[#JTADDR]] 00000000 00000000 00000000 00000000 + + .globl main +main: + .cfi_startproc + jmp main + jmpq *JT(,%rax,8) +a: + shlq %rax +.Ltmp: + nop +c: + ret + .cfi_endproc + +.rodata +JT: + .quad .Ltmp + .quad a