https://github.com/pcc updated https://github.com/llvm/llvm-project/pull/147424

>From 5bce06b0d8db161a2e09709bcfe15b4623e43d01 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <pe...@pcc.me.uk>
Date: Mon, 7 Jul 2025 16:41:10 -0700
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.6-beta.1
---
 lld/ELF/Arch/X86_64.cpp | 95 +++++++++++++++++++++++++++++++++++++++++
 lld/ELF/Relocations.cpp |  2 +-
 lld/ELF/Target.h        |  1 +
 3 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 488f4803b2cb4..04ca79befdc4a 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -318,6 +318,9 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, 
InputFile *file,
 }
 
 bool X86_64::relaxOnce(int pass) const {
+  if (pass == 0)
+    relaxJumpTables(ctx);
+
   uint64_t minVA = UINT64_MAX, maxVA = 0;
   for (OutputSection *osec : ctx.outputSections) {
     if (!(osec->flags & SHF_ALLOC))
@@ -1231,6 +1234,98 @@ void X86_64::applyBranchToBranchOpt() const {
                              redirectControlTransferRelocations);
 }
 
+void elf::relaxJumpTables(Ctx &ctx) {
+  // Relax CFI jump tables.
+  // - Split jump table into pieces and place target functions inside the jump
+  //   table if small enough.
+  // - Move jump table before last called function and delete last branch
+  //   instruction.
+  std::map<InputSection *, std::vector<InputSection *>> sectionReplacements;
+  SmallVector<InputSection *, 0> storage;
+  for (OutputSection *osec : ctx.outputSections) {
+    if (!(osec->flags & SHF_EXECINSTR))
+      continue;
+    for (InputSection *sec : getInputSections(*osec, storage)) {
+      if (!sec->name.starts_with(".text..L.cfi.jumptable"))
+        continue;
+      std::vector<InputSection *> replacements;
+      replacements.push_back(sec);
+      auto addSectionSlice = [&](size_t begin, size_t end, Relocation *rbegin,
+                                 Relocation *rend) {
+        if (begin == end)
+          return;
+        auto *slice = make<InputSection>(
+            sec->file, sec->name, sec->type, sec->flags, 1, sec->entsize,
+            sec->contentMaybeDecompress().slice(begin, end - begin));
+        for (const Relocation &r : ArrayRef<Relocation>(rbegin, rend)) {
+          slice->relocations.push_back(
+              Relocation{r.expr, r.type, r.offset - begin, r.addend, r.sym});
+        }
+        replacements.push_back(slice);
+      };
+      auto getMovableSection = [&](Relocation &r) -> InputSection * {
+        auto *sym = dyn_cast_or_null<Defined>(r.sym);
+        if (!sym || sym->isPreemptible || sym->isGnuIFunc() || sym->value != 0)
+          return nullptr;
+        auto *sec = dyn_cast_or_null<InputSection>(sym->section);
+        if (!sec || sectionReplacements.count(sec))
+          return nullptr;
+        return sec;
+      };
+      size_t begin = 0;
+      Relocation *rbegin = sec->relocs().begin();
+      for (auto &r : sec->relocs().slice(0, sec->relocs().size() - 1)) {
+        auto entrySize = (&r + 1)->offset - r.offset;
+        InputSection *target = getMovableSection(r);
+        if (!target || target->size > entrySize)
+          continue;
+        target->addralign = 1;
+        addSectionSlice(begin, r.offset - 1, rbegin, &r);
+        replacements.push_back(target);
+        sectionReplacements[target] = {};
+        begin = r.offset - 1 + target->size;
+        rbegin = &r + 1;
+      }
+      InputSection *lastSec = getMovableSection(sec->relocs().back());
+      if (lastSec) {
+        lastSec->addralign = 1;
+        addSectionSlice(begin, sec->relocs().back().offset - 1, rbegin,
+                        &sec->relocs().back());
+        replacements.push_back(lastSec);
+        sectionReplacements[sec] = {};
+        sectionReplacements[lastSec] = replacements;
+        for (auto *s : replacements)
+          s->parent = lastSec->parent;
+      } else {
+        addSectionSlice(begin, sec->size, rbegin, sec->relocs().end());
+        sectionReplacements[sec] = replacements;
+        for (auto *s : replacements)
+          s->parent = sec->parent;
+      }
+      sec->relocations.clear();
+      sec->size = 0;
+    }
+  }
+  for (OutputSection *osec : ctx.outputSections) {
+    if (!(osec->flags & SHF_EXECINSTR))
+      continue;
+    for (SectionCommand *cmd : osec->commands) {
+      auto *isd = dyn_cast<InputSectionDescription>(cmd);
+      if (!isd)
+        continue;
+      SmallVector<InputSection *> newSections;
+      for (auto *sec : isd->sections) {
+        auto i = sectionReplacements.find(sec);
+        if (i == sectionReplacements.end())
+          newSections.push_back(sec);
+        else
+          newSections.append(i->second.begin(), i->second.end());
+      }
+      isd->sections = std::move(newSections);
+    }
+  }
+}
+
 // If Intel Indirect Branch Tracking is enabled, we have to emit special PLT
 // entries containing endbr64 instructions. A PLT entry will be split into two
 // parts, one in .plt.sec (writePlt), and the other in .plt (writeIBTPlt).
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index cebd564036b2c..f7e3d54878395 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1674,7 +1674,7 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {
   // R_RISCV_PCREL_HI20, R_PPC64_ADDR64 and the branch-to-branch optimization.
   if (ctx.arg.emachine == EM_RISCV ||
       (ctx.arg.emachine == EM_PPC64 && sec->name == ".toc") ||
-      ctx.arg.branchToBranch)
+      ctx.arg.branchToBranch || 
sec->name.starts_with(".text..L.cfi.jumptable"))
     llvm::stable_sort(sec->relocs(),
                       [](const Relocation &lhs, const Relocation &rhs) {
                         return lhs.offset < rhs.offset;
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 6dd20b2f0cbaa..e6eb33fa5338c 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -195,6 +195,7 @@ void setSPARCV9TargetInfo(Ctx &);
 void setSystemZTargetInfo(Ctx &);
 void setX86TargetInfo(Ctx &);
 void setX86_64TargetInfo(Ctx &);
+void relaxJumpTables(Ctx &);
 
 struct ErrorPlace {
   InputSectionBase *isec;

>From afa726a766603c29393a6c3f0d3500a11c85d9e9 Mon Sep 17 00:00:00 2001
From: Peter Collingbourne <pe...@pcc.me.uk>
Date: Thu, 28 Aug 2025 15:34:34 -0700
Subject: [PATCH 2/2] Fix bug where overaligned jump tables are laid out
 incorrectly

Created using spr 1.3.6-beta.1
---
 lld/ELF/Arch/X86_64.cpp                 |  7 +++++++
 lld/test/ELF/x86_64-relax-jump-tables.s | 27 +++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp
index 2ced135a4d0c3..50026dabfeee5 100644
--- a/lld/ELF/Arch/X86_64.cpp
+++ b/lld/ELF/Arch/X86_64.cpp
@@ -376,6 +376,13 @@ void X86_64::relaxCFIJumpTables() const {
       // because the last entry controls which output section the jump table is
       // placed into, which affects move eligibility for other sections.
       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
+        // padding section that places the last entry at a correctly aligned
+        // address.
+        if (sec->addralign > sec->entsize)
+          return nullptr;
+
         Relocation *lastReloc = sec->relocs().end();
         while (lastReloc != sec->relocs().begin() &&
                (lastReloc - 1)->offset >= sec->size - sec->entsize)
diff --git a/lld/test/ELF/x86_64-relax-jump-tables.s 
b/lld/test/ELF/x86_64-relax-jump-tables.s
index 8c2394003bacb..50edf4c240ecc 100644
--- a/lld/test/ELF/x86_64-relax-jump-tables.s
+++ b/lld/test/ELF/x86_64-relax-jump-tables.s
@@ -109,6 +109,23 @@ jmp f12.cfi
 f13:
 jmp f13.cfi
 
+// Jumptable alignment > entsize prevents it from being moved before last
+// function, but moving non-last functions into the jumptable should work.
+// CHECK: <f14>:
+// CHECK-NEXT: <f14.cfi>:
+// CHECK-NEXT: retq $0xe
+.section .text.jt5,"ax",@llvm_cfi_jump_table,8
+.balign 16
+f14:
+jmp f14.cfi
+.balign 8, 0xcc
+
+// CHECK: <f15>:
+// CHECK-NEXT: jmp {{.*}} <f15.cfi>
+f15:
+jmp f15.cfi
+.balign 8, 0xcc
+
 // CHECK: <f1>:
 // CHECK-NEXT: <f1.cfi>:
 // CHECK-NEXT: retq $0x1
@@ -180,5 +197,15 @@ ret $12
 f13.cfi:
 ret $13
 
+.section .text.f14,"ax",@progbits
+f14.cfi:
+ret $14
+
+.section .text.f15,"ax",@progbits
+.balign 64
+f15.cfi:
+ret $15
+.zero 16
+
 // CHECK: <.iplt>:
 // CHECK-NEXT: [[IPLT]]:

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to