[llvm] [bolt][x86] Fixed process indirect branch instruction (PR #179663)

Alexey Moksyakov via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 4 06:04:39 PST 2026


https://github.com/yavtuk created https://github.com/llvm/llvm-project/pull/179663

Hi folks, during libc processing there is the crash when analyzing indirect branch instruction which is part of JT with fixed entry load instruction. 

JT pattern as:
`
    //    movslq En(%rip), {%r2|%r1}              <- FixedEntryLoadInstr
    //    lea PIC_JUMP_TABLE(%rip), {%r1|%r2}  
    //    add %r2, %r1
    //    jmp *%r1
`

I extend the existing unit test to reproduce the error and found that we leave processing little bit early,
Print CFG function with the this JT pattern shows that indirect branch instruction has "UNKNOWN CONTROL FLOW" annotation.

libc.so binary can be found in the issue [](https://github.com/llvm/llvm-project/pull/178578)
thanks to @Jianghibo for PR where he suggest the solution but  from my point of view it's better to re-create JT if the one is already exist and add the instruction offset to JTs call sites list.

https://github.com/llvm/llvm-project/issues/122828

__GI___res_context_query function contains 3 jump tables, before this patch bolt recognized only 2 JT.



>From 16843ca71ddeae8280a9c6d3b31c0d3782a38894 Mon Sep 17 00:00:00 2001
From: yavtuk <yavtuk at ya.ru>
Date: Wed, 4 Feb 2026 16:23:58 +0300
Subject: [PATCH] [bolt][x86] Fixed process indirect branch instruction

This patch adds checking that JT is already exist for pattern
with fixed indirect branch instruction. if JT is not exist or
deleted need to create new one based on snippet type update Imm
value to label for fixed entry load instruction.
---
 bolt/lib/Core/BinaryFunction.cpp              | 39 ++++++++++++-------
 .../X86/Inputs/jump-table-fixed-ref-pic.s     |  2 +-
 bolt/test/X86/jump-table-fixed-ref-pic.test   | 19 +++++++--
 3 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index 255f3d734bdb4..e484b8dc7b021 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -938,20 +938,12 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
               << " the destination value is 0x"
               << Twine::utohexstr(ArrayStart + *Value) << '\n';
 
-    TargetAddress = ArrayStart + *Value;
-
-    // Remove spurious JumpTable at EntryAddress caused by PIC reference from
-    // the load instruction.
-    BC.deleteJumpTable(EntryAddress);
-
-    // Replace FixedEntryDispExpr used in target address calculation with outer
-    // jump table reference.
-    JumpTable *JT = BC.getJumpTableContainingAddress(ArrayStart);
-    assert(JT && "Must have a containing jump table for PIC fixed branch");
-    BC.MIB->replaceMemOperandDisp(*FixedEntryLoadInstr, JT->getFirstLabel(),
-                                  EntryAddress - ArrayStart, &*BC.Ctx);
-
-    return BranchType;
+    JumpTable *JT = BC.getJumpTableContainingAddress(EntryAddress);
+    if (JT) {
+        // Remove spurious JumpTable at EntryAddress caused by PIC reference from
+        // the load instruction.
+        BC.deleteJumpTable(EntryAddress);
+    }
   }
 
   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: addressed memory is 0x"
@@ -1009,7 +1001,8 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
 
   // Check that jump table type in instruction pattern matches memory contents.
   JumpTable::JumpTableType JTType;
-  if (BranchType == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE) {
+  if (BranchType == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE ||
+      BranchType == IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH) {
     if (MemType != MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE)
       return IndirectBranchType::UNKNOWN;
     JTType = JumpTable::JTT_PIC;
@@ -1031,6 +1024,22 @@ BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size,
 
   JTSites.emplace_back(Offset, ArrayStart);
 
+  if (FixedEntryLoadInstr) {
+    assert(BranchType == IndirectBranchType::POSSIBLE_PIC_FIXED_BRANCH &&
+           "Invalid IndirectBranch type");
+    JumpTable *JT = BC.getJumpTableContainingAddress(ArrayStart);
+    if (!JT)
+        return BranchType;
+    MCInst::iterator FixedEntryDispOperand =
+        BC.MIB->getMemOperandDisp(*FixedEntryLoadInstr);
+    assert(FixedEntryDispOperand != FixedEntryLoadInstr->end() &&
+           "Invalid memory instruction");
+    const MCExpr *FixedEntryDispExpr = FixedEntryDispOperand->getExpr();
+    const uint64_t EntryAddress = getExprValue(FixedEntryDispExpr);
+    BC.MIB->replaceMemOperandDisp(*FixedEntryLoadInstr, JT->getFirstLabel(),
+                                  EntryAddress - ArrayStart, &*BC.Ctx);
+  }
+
   return BranchType;
 }
 
diff --git a/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s
index 6407964593e2d..887281e582867 100644
--- a/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s
+++ b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s
@@ -6,7 +6,7 @@ main:
   jae .L4
   cmpq $0x1, %rdi
   jne .L4
-  movslq .Ljt_pic+8(%rip), %rax
+  movslq .Ljt_pic+JT_ENTRY_OFFSET(%rip), %rax
   lea .Ljt_pic(%rip), %rdx
   add %rdx, %rax
   jmpq *%rax
diff --git a/bolt/test/X86/jump-table-fixed-ref-pic.test b/bolt/test/X86/jump-table-fixed-ref-pic.test
index d215c565b31e5..1be994761f615 100644
--- a/bolt/test/X86/jump-table-fixed-ref-pic.test
+++ b/bolt/test/X86/jump-table-fixed-ref-pic.test
@@ -1,13 +1,26 @@
 ## Verify that BOLT detects fixed destination of indirect jump for PIC
 ## case.
 
-RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t
+RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t \
+RUN:    -Wa,--defsym,JT_ENTRY_OFFSET=8
 RUN: llvm-bolt %t --relocs -o %t.null -print-cfg 2>&1 | FileCheck %s
 
 CHECK: BOLT-INFO: fixed PIC indirect branch detected in main {{.*}} the destination value is 0x[[#TGT:]]
 CHECK: Binary Function "main" after building cfg
 
-CHECK:      movslq ".rodata/1"+8(%rip), %rax
+CHECK:      movslq ".rodata/1"+[[#OFFSET:8]](%rip), %rax
 CHECK-NEXT: leaq ".rodata/1"(%rip), %rdx
 CHECK-NEXT: addq %rdx, %rax
-CHECK-NEXT: jmpq *%rax # UNKNOWN CONTROL FLOW
+CHECK-NEXT: jmpq *%rax # JUMPTABLE
+
+RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t \
+RUN:    -Wa,--defsym,JT_ENTRY_OFFSET=0
+RUN: llvm-bolt %t --relocs -o %t.null -print-cfg 2>&1 | FileCheck %s
+
+CHECK-LABEL: BOLT-INFO: fixed PIC indirect branch detected in main {{.*}} the destination value is 0x[[#TGT:]]
+CHECK: Binary Function "main" after building cfg
+
+CHECK:      movslq ".rodata/1"(%rip), %rax
+CHECK-NEXT: leaq ".rodata/1"(%rip), %rdx
+CHECK-NEXT: addq %rdx, %rax
+CHECK-NEXT: jmpq *%rax # JUMPTABLE



More information about the llvm-commits mailing list