[llvm-branch-commits] [ELF] Move CFI jump table only if all entries match the last one (PR #222234)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Sep 8 21:56:23 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Vitaly Buka (vitalybuka)

<details>
<summary>Changes</summary>

In CFI jump table relaxation (relaxCFIJumpTables), moving the jump table
before the last entry moves the entire jump table into the output section
of that last entry.

If jump table entries target functions in different output sections
(for example, some in .text.hot and some in .text.unlikely or a different
section), moving the jump table before the last entry can drag the jump
table and its other entries into a section that does not match them.

Only allow moving the jump table before the last entry if every entry
in the jump table targets a section whose parent output section matches
the last entry's output section.

Assisted-by: Gemini


---
Full diff: https://github.com/llvm/llvm-project/pull/222234.diff


2 Files Affected:

- (modified) lld/ELF/Arch/X86_64.cpp (+17-1) 
- (modified) lld/test/ELF/x86-64-relax-jump-tables.s (+24) 


``````````diff
diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index f172080dc2b6a..c49c5e0d54530 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -355,6 +355,12 @@ void X86_64::relaxCFIJumpTables() const {
       // Figure out the movable section for the last entry. We do this first
       // because the last entry controls which output section the jump table is
       // placed into, which affects move eligibility for other sections.
+      //
+      // The compiler can assign the jump table to a hot section (e.g.
+      // .text.hot). We prefer to keep it that way and avoid dragging the jump
+      // table into the output section of the last entry if other entries
+      // reside elsewhere. However, moving the jump table is likely fine if all
+      // entries are from that same output section.
       auto *lastSec = [&]() -> InputSection * {
         // If the jump table section is more aligned than the entry size, skip
         // this because there's no guarantee that we'll be able to emit a
@@ -369,7 +375,17 @@ void X86_64::relaxCFIJumpTables() const {
         if (rels.size() >= 2 &&
             rels[rels.size() - 2].offset >= sec->size - sec->entsize)
           return nullptr;
-        return getMovableSection(rels.back());
+        InputSection *last = getMovableSection(rels.back());
+        if (!last)
+          return nullptr;
+
+        for (Relocation &r : rels) {
+          InputSection *target = getMovableSection(r);
+          if (!target || target->getParent() != last->getParent())
+            return nullptr;
+        }
+
+        return last;
       }();
       OutputSection *targetOutputSec;
       if (lastSec) {
diff --git a/lld/test/ELF/x86-64-relax-jump-tables.s b/lld/test/ELF/x86-64-relax-jump-tables.s
index a19ab19f9c1c8..b2c98691afabf 100644
--- a/lld/test/ELF/x86-64-relax-jump-tables.s
+++ b/lld/test/ELF/x86-64-relax-jump-tables.s
@@ -198,6 +198,30 @@ jmp f21.cfi
 f21.cfi:
 ret $21
 
+## All entries must match the last entry's output section.
+## f22 and f23 are in different output sections, so jt10 should not be moved
+## before f23.
+# CHECK:      <f22>:
+# CHECK-NEXT:   jmp {{.*}} <f22.cfi>
+# CHECK:      <f23>:
+# CHECK-NEXT:   jmp {{.*}} <f23.cfi>
+.section .text.jt10,"ax", at llvm_cfi_jump_table,8
+f22:
+jmp f22.cfi
+.balign 8, 0xcc
+f23:
+jmp f23.cfi
+.balign 8, 0xcc
+
+.section .text.f22,"ax", at progbits
+f22.cfi:
+ret $22
+.zero 16
+
+.section foo2,"ax", at progbits
+f23.cfi:
+ret $23
+
 # CHECK:      <f1>:
 # CHECK-NEXT: <f1.cfi>:
 # CHECK-NEXT:   retq   $0x1

``````````

</details>


https://github.com/llvm/llvm-project/pull/222234


More information about the llvm-branch-commits mailing list