[llvm] [BOLT] Skip non-code relocs as function references (PR #215028)

Amir Ayupov via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 8 14:41:14 PDT 2026


https://github.com/aaupov created https://github.com/llvm/llvm-project/pull/215028

handleRelocation looked up the referenced function from the resolved "symbol + addend" address, ignoring the symbol's section. With biased array indexing the compiler folds a constant into the displacement, e.g.
```
movq const_int_rtx-0x3fe00(,%rax,8), %r14   # R_X86_64_32S const_int_rtx-0x3fe00
```
so the unbiased displacement is not a live address (only disp + rax*8 is), yet it can land inside an unrelated function. BOLT re-anchored the relocation onto that function and dropped the addend, then during disassembly registered an interprocedural reference to a mid-instruction address, producing:

```
BOLT-WARNING: corrupted control flow detected in function ...: an external
branch/call targets an invalid instruction in function ... ; ignoring both
```

With -use-old-text this causes "cannot ignore non-empty function in current mode". Observed on SPEC CPU2026 821.gcc_s built with clang15.

Check `IsToCode || IsSectionReference` prior to setting a ReferencedBF.

Test Plan:
Added bolt/test/X86/reloc-data-symbol-negative-addend.s

>From 04bff5038453f4275b3a050c87cd42f30db59776 Mon Sep 17 00:00:00 2001
From: Amir Ayupov <aaupov at fb.com>
Date: Thu, 6 Aug 2026 21:19:33 -0700
Subject: [PATCH] [BOLT] Skip non-code relocs as function references

Summary:
handleRelocation looked up the referenced function from the resolved
"symbol + addend" address, ignoring the symbol's section. With biased array
indexing the compiler folds a constant into the displacement, e.g.
```
movq const_int_rtx-0x3fe00(,%rax,8), %r14   # R_X86_64_32S const_int_rtx-0x3fe00
```
so the unbiased displacement is not a live address (only disp + rax*8 is), yet
it can land inside an unrelated function. BOLT re-anchored the relocation onto
that function and dropped the addend, then during disassembly registered an
interprocedural reference to a mid-instruction address, producing:

```
BOLT-WARNING: corrupted control flow detected in function ...: an external
branch/call targets an invalid instruction in function ... ; ignoring both
```

With -use-old-text this causes "cannot ignore non-empty function in
current mode". Observed on SPEC CPU2026 821.gcc_s built with clang15.

Check `IsToCode || IsSectionReference` prior to setting a ReferencedBF.

Test Plan:
Added bolt/test/X86/reloc-data-symbol-negative-addend.s

Fixes cc1_s with -use-old-text.

Reviewers:

Subscribers:

Tasks:

Tags:

Differential Revision: https://phabricator.intern.facebook.com/D115150876
---
 bolt/lib/Rewrite/RewriteInstance.cpp          |  9 ++++-
 .../X86/reloc-data-symbol-negative-addend.s   | 40 +++++++++++++++++++
 2 files changed, 47 insertions(+), 2 deletions(-)
 create mode 100644 bolt/test/X86/reloc-data-symbol-negative-addend.s

diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index c122614a5ee0f..a5de2b5733355 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -3318,8 +3318,13 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
 
   // Occasionally we may see a reference past the last byte of the function
   // typically as a result of __builtin_unreachable(). Check it here.
-  BinaryFunction *ReferencedBF = BC->getBinaryFunctionContainingAddress(
-      Address, /*CheckPastEnd*/ true, /*UseMaxSize*/ IsAArch64);
+  //
+  // Only look for a referenced function when the symbol itself denotes code
+  // or it is a section relocation.
+  BinaryFunction *ReferencedBF = nullptr;
+  if (IsToCode || IsSectionRelocation)
+    ReferencedBF = BC->getBinaryFunctionContainingAddress(
+        Address, /*CheckPastEnd*/ true, /*UseMaxSize*/ IsAArch64);
 
   if (!IsSectionRelocation) {
     if (BinaryFunction *BF =
diff --git a/bolt/test/X86/reloc-data-symbol-negative-addend.s b/bolt/test/X86/reloc-data-symbol-negative-addend.s
new file mode 100644
index 0000000000000..1c3a5cf21bd8f
--- /dev/null
+++ b/bolt/test/X86/reloc-data-symbol-negative-addend.s
@@ -0,0 +1,40 @@
+## Check that a relocation against a data symbol with a negative addend is not
+## mistaken for a reference into a function when "symbol + addend" happens to
+## resolve inside one. Compilers fold a bias into the displacement for indexed
+## accesses, e.g. "mov sym-0x3fe00(,%rax,8)", and the unbiased address is never
+## used on its own.
+
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
+# RUN: ld.lld %t.o -o %t.exe -q --nostdlib -e _start --image-base=0x200000 \
+# RUN:   --section-start=.text=0x200000 --section-start=.mydata=0x400000
+# RUN: llvm-bolt %t.exe -o %t.bolt --relocs 2>&1 | FileCheck %s
+
+## The biased displacement resolves into the middle of an instruction in
+## "target". BOLT used to report that as an external branch and ignore both
+## functions.
+# CHECK-NOT: corrupted control flow
+
+  .text
+  .globl target
+  .type target, @function
+target:
+## 10-byte instruction at 0x200000, so 0x200003 is not an instruction boundary.
+  movabsq $0x1122334455667788, %rax
+  retq
+  .size target, .-target
+
+  .globl _start
+  .type _start, @function
+_start:
+## datasym is at 0x400000, so datasym-0x1ffffd resolves to 0x200003, inside
+## "target" above.
+  movq datasym-0x1ffffd(,%rax,8), %r14
+  retq
+  .size _start, .-_start
+
+  .section .mydata, "aw", @progbits
+  .globl datasym
+datasym:
+  .quad 0



More information about the llvm-commits mailing list