diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1860,6 +1860,40 @@ if (HasFixedIndirectBranch) return false; + // Validate that all data references to function offsets are claimed by + // recognized jump tables. Register externally referenced blocks as entry + // points. + if (!opts::StrictMode && hasInternalReference()) { + SmallPtrSet JTTargets; + for (const JumpTable *JT : llvm::make_second_range(JumpTables)) + JTTargets.insert(JT->Entries.begin(), JT->Entries.end()); + + bool UnclaimedReference = false; + for (uint64_t Destination : ExternallyReferencedOffsets) { + // Ignore __builtin_unreachable(). + if (Destination == getSize()) + continue; + + if (BinaryBasicBlock *BB = getBasicBlockAtOffset(Destination)) { + bool Found = JTTargets.contains(BB->getLabel()); + if (Found) + continue; + + if (opts::Verbosity >= 1) { + outs() << "BOLT-WARNING: unclaimed data to code reference (possibly " + << "an unrecognized jump table entry) to " << BB->getName() + << " in " << *this << ".\n"; + } + } else if (opts::Verbosity >= 1) { + outs() << "BOLT-WARNING: unknown data to code reference to offset " + << Twine::utohexstr(Destination) << " in " << *this << ".\n"; + } + UnclaimedReference = true; + } + if (UnclaimedReference) + return false; + } + if (HasUnknownControlFlow && !BC.HasRelocations) return false; diff --git a/bolt/test/X86/unclaimed-jt-entries.s b/bolt/test/X86/unclaimed-jt-entries.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/unclaimed-jt-entries.s @@ -0,0 +1,66 @@ +# This test ensures that "unclaimed" jump table entries are accounted later +# in postProcessIndirectBranches and the function is marked as non-simple. + +# The test is compiled from the following source using GCC 12.2 -O3: +# https://godbolt.org/z/YcPG131s6 +# int func(long long Input) { +# switch(Input) { +# case 3: return 1; +# case 4: return 2; +# case 6: return 3; +# case 8: return 4; +# case 13: return 5; +# default: __builtin_unreachable(); +# } +# } + +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -v=1 -o %t.out |& FileCheck %s + +# CHECK: BOLT-WARNING: unclaimed data to code reference (possibly an unrecognized jump table entry) to .Ltmp[[#]] in main +# CHECK: BOLT-WARNING: unclaimed data to code reference (possibly an unrecognized jump table entry) to .Ltmp[[#]] in main +# CHECK: BOLT-WARNING: unclaimed data to code reference (possibly an unrecognized jump table entry) to .Ltmp[[#]] in main +# CHECK: BOLT-WARNING: unclaimed data to code reference (possibly an unrecognized jump table entry) to .Ltmp[[#]] in main +# CHECK: BOLT-WARNING: unclaimed data to code reference (possibly an unrecognized jump table entry) to .Ltmp[[#]] in main +# CHECK: BOLT-WARNING: failed to post-process indirect branches for main + + .text + .globl main + .type main, %function + .size main, .Lend-main +main: + jmp *L4-24(,%rdi,8) +.L5: + movl $4, %eax + ret +.L9: + movl $2, %eax + ret +.L8: + movl $1, %eax + ret +.L3: + movl $5, %eax + ret +.L6: + movl $3, %eax + ret +.Lend: + +.section .rodata + .globl L4 +L4: + .quad .L8 + .quad .L9 + .quad .L3 + .quad .L6 + .quad .L3 + .quad .L5 + .quad .L3 + .quad .L3 + .quad .L3 + .quad .L3 + .quad .L3