[llvm] [LFI][X86] Enable bundling for the LFI target (PR #214111)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 18:20:14 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-mc

Author: Zachary Yedidia (zyedidia)

<details>
<summary>Changes</summary>

This enables 32-byte bundling for the LFI x86-64 target, and uses bundle grouping for existing rewrites where appropriate.

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


7 Files Affected:

- (modified) llvm/docs/LFI.rst (+28-1) 
- (modified) llvm/include/llvm/MC/MCLFI.h (+2) 
- (modified) llvm/lib/MC/MCELFStreamer.cpp (+2) 
- (modified) llvm/lib/MC/MCLFI.cpp (+10) 
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp (+7) 
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86MCLFIRewriter.cpp (+5) 
- (modified) llvm/test/MC/X86/LFI/syscall.s (+3-1) 


``````````diff
diff --git a/llvm/docs/LFI.rst b/llvm/docs/LFI.rst
index 928079dd047de..094c488fe6e1b 100644
--- a/llvm/docs/LFI.rst
+++ b/llvm/docs/LFI.rst
@@ -562,6 +562,31 @@ The X86-64 LFI target reserves the following registers:
 * ``r15``: context register (see `Context Register`_).
 * ``r11``: scratch register.
 
+Bundling
+========
+
+The X86-64 LFI target confines control flow using 32-byte bundles. Indirect
+branch targets are masked to a 32-byte boundary, so control can only enter code
+at a bundle-aligned address. For this to constrain the instruction stream, no
+instruction may span a bundle boundary.
+
+LFI object files are therefore assembled with :doc:`aligned instruction
+bundling <AlignedBundling>` enabled, which inserts ``nop`` padding wherever an
+instruction would otherwise cross a boundary. Bundling is enabled implicitly
+for the ``x86_64_lfi`` target.
+
+A rewrite that expands one instruction into a sequence which must not be
+entered in the middle wraps that sequence in ``.bundle_lock`` /
+``.bundle_unlock``. This keeps the whole group within a single bundle, so no
+masked indirect branch can land between its instructions.
+
+**Note**: the masking of indirect branch targets is part of the control flow
+rewrites, which have not been implemented yet.
+
+Bundling is specific to X86-64. AArch64 instructions are fixed-width and
+naturally aligned, and the AArch64 LFI target confines indirect branches by
+guarding the target register instead.
+
 Assembly Rewrites
 =================
 
@@ -607,9 +632,11 @@ block below).
 +-------------------+-------------------------------+
 | .. code-block::   | .. code-block::               |
 |                   |                               |
-|    syscall        |    leaq .Ltmp(%rip), %r11     |
+|    syscall        |    .bundle_lock               |
+|                   |    leaq .Ltmp(%rip), %r11     |
 |                   |    jmpq *-8(%r14)             |
 |                   |    .Ltmp:                     |
+|                   |    .bundle_unlock             |
 |                   |                               |
 +-------------------+-------------------------------+
 
diff --git a/llvm/include/llvm/MC/MCLFI.h b/llvm/include/llvm/MC/MCLFI.h
index 4f941a16137ab..15176dedd8381 100644
--- a/llvm/include/llvm/MC/MCLFI.h
+++ b/llvm/include/llvm/MC/MCLFI.h
@@ -22,6 +22,8 @@ class Triple;
 LLVM_ABI void initializeLFIMCStreamer(MCStreamer &Streamer, MCContext &Ctx,
                                       const Triple &TheTriple);
 
+LLVM_ABI void emitLFIBundleAlign(MCStreamer &Streamer, MCContext &Ctx);
+
 LLVM_ABI void emitLFINoteSection(MCStreamer &Streamer, MCContext &Ctx);
 
 } // namespace llvm
diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
index 03bbf4e81120e..efe08d7e09a84 100644
--- a/llvm/lib/MC/MCELFStreamer.cpp
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -55,6 +55,8 @@ void MCELFStreamer::initSections(const MCSubtargetInfo &STI) {
   switchSection(Ctx.getObjectFileInfo()->getTextSection());
   emitCodeAlignment(Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()),
                     STI);
+  if (Ctx.getTargetTriple().isLFI())
+    emitLFIBundleAlign(*this, Ctx);
 }
 
 void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
diff --git a/llvm/lib/MC/MCLFI.cpp b/llvm/lib/MC/MCLFI.cpp
index 7b149f4b53b4b..baa9e04bf808e 100644
--- a/llvm/lib/MC/MCLFI.cpp
+++ b/llvm/lib/MC/MCLFI.cpp
@@ -26,6 +26,8 @@
 
 static const char NoteNamespace[] = "LFI";
 
+static constexpr unsigned X86BundleSize = 32;
+
 namespace llvm {
 
 cl::opt<bool> FlagEnableRewriting("lfi-enable-rewriter",
@@ -50,6 +52,14 @@ void initializeLFIMCStreamer(MCStreamer &Streamer, MCContext &Ctx,
   }
 }
 
+void emitLFIBundleAlign(MCStreamer &Streamer, MCContext &Ctx) {
+  const Triple &TheTriple = Ctx.getTargetTriple();
+  assert(TheTriple.isLFI());
+
+  if (TheTriple.getArch() == Triple::x86_64)
+    Streamer.emitBundleAlignMode(Align(X86BundleSize));
+}
+
 void emitLFINoteSection(MCStreamer &Streamer, MCContext &Ctx) {
   const Triple &TheTriple = Ctx.getTargetTriple();
   assert(TheTriple.isLFI());
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index 5d245f7f90cf3..acee4f524966a 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -23,6 +23,7 @@
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCLFIRewriter.h"
 #include "llvm/MC/MCObjectStreamer.h"
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -477,6 +478,12 @@ void X86_MC::emitInstruction(MCObjectStreamer &S, const MCInst &Inst,
     return;
   }
 
+  // Run the LFI rewriter outside of emitInstructionBegin/End so that nested
+  // instructions or bundle_lock/unlock directives do not corrupt the Begin/End
+  // bookkeeping for the original instruction.
+  if (S.getLFIRewriter() && S.getLFIRewriter()->rewriteInst(Inst, S, STI))
+    return;
+
   auto &Backend = static_cast<X86AsmBackend &>(S.getAssembler().getBackend());
   Backend.emitInstructionBegin(S, Inst, STI);
   S.MCObjectStreamer::emitInstruction(Inst, STI);
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCLFIRewriter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCLFIRewriter.cpp
index ac1577ee4d0c7..bf199791ed212 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCLFIRewriter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCLFIRewriter.cpp
@@ -71,11 +71,15 @@ static bool isGR64OrNone(MCRegister Reg) {
 
 // syscall
 // ->
+// .bundle_lock
 // leaq .Ltmp(%rip), %r11
 // jmpq *(%r14)
 // .Ltmp:
+// .bundle_unlock
 void X86::X86MCLFIRewriter::rewriteSyscall(const MCInst &Inst, MCStreamer &Out,
                                            const MCSubtargetInfo &STI) {
+  Out.emitBundleLock(/*AlignToEnd=*/false, STI);
+
   MCSymbol *Symbol = Out.getContext().createTempSymbol();
 
   // leaq .Ltmp(%rip), %r11
@@ -101,6 +105,7 @@ void X86::X86MCLFIRewriter::rewriteSyscall(const MCInst &Inst, MCStreamer &Out,
   Out.emitInstruction(Jmp, STI);
 
   Out.emitLabel(Symbol);
+  Out.emitBundleUnlock(STI);
 }
 
 // Emit: movq TPOffset(%r15), %Reg
diff --git a/llvm/test/MC/X86/LFI/syscall.s b/llvm/test/MC/X86/LFI/syscall.s
index b184bd481df17..7b47bfe96f8ff 100644
--- a/llvm/test/MC/X86/LFI/syscall.s
+++ b/llvm/test/MC/X86/LFI/syscall.s
@@ -1,6 +1,8 @@
 // RUN: llvm-mc -triple x86_64_lfi %s | FileCheck %s
 
 syscall
-// CHECK:      leaq .Ltmp0(%rip), %r11
+// CHECK:      .bundle_lock
+// CHECK-NEXT: leaq .Ltmp0(%rip), %r11
 // CHECK-NEXT: jmpq *-8(%r14)
 // CHECK-NEXT: .Ltmp0:
+// CHECK-NEXT: .bundle_unlock

``````````

</details>


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


More information about the llvm-commits mailing list