[clang] [llvm] [LFI][X86] Add X86 LFI target and system instruction rewrites (PR #189569)
Nick Desaulniers via cfe-commits
cfe-commits at lists.llvm.org
Thu May 21 09:53:52 PDT 2026
================
@@ -0,0 +1,211 @@
+//===- X86MCLFIRewriter.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the X86MCLFIRewriter class, which rewrites X86-64
+// instructions for LFI (Lightweight Fault Isolation) sandboxing.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86MCLFIRewriter.h"
+#include "X86BaseInfo.h"
+#include "X86MCTargetDesc.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+
+using namespace llvm;
+
+// LFI reserved registers.
+static constexpr MCRegister LFIBaseReg = X86::R14;
+static constexpr MCRegister LFIScratchReg = X86::R11;
+static constexpr MCRegister LFITPReg = X86::R15;
+
+// Byte offset into the context register file (pointed to by R15) where the
+// thread pointer is stored.
+static constexpr int TPOffset = 16;
+
+static bool isSyscall(const MCInst &Inst) {
+ return Inst.getOpcode() == X86::SYSCALL;
+}
+
+// Find the index of the first memory operand with %fs segment override.
+// Returns -1 if not found.
+static int findFSMemOperand(const MCInst &Inst, const MCInstrInfo &InstInfo) {
+ const MCInstrDesc &Desc = InstInfo.get(Inst.getOpcode());
+ for (unsigned I = 0, E = Desc.getNumOperands(); I < E; ++I) {
+ if (Desc.operands()[I].OperandType == MCOI::OPERAND_MEMORY) {
+ if (I + 4 < Inst.getNumOperands() && Inst.getOperand(I + 4).isReg() &&
+ Inst.getOperand(I + 4).getReg() == X86::FS)
+ return I;
+ I += 4;
+ }
+ }
+ return -1;
+}
+
+// syscall
+// ->
+// leaq .Ltmp(%rip), %r11
+// jmpq *(%r14)
+// .Ltmp:
+static void emitLFICall(MCStreamer &Out, const MCSubtargetInfo &STI) {
+ MCSymbol *Symbol = Out.getContext().createTempSymbol();
+
+ // leaq .Ltmp(%rip), %r11
+ MCInst Lea;
+ Lea.setOpcode(X86::LEA64r);
+ Lea.addOperand(MCOperand::createReg(LFIScratchReg));
+ Lea.addOperand(MCOperand::createReg(X86::RIP));
+ Lea.addOperand(MCOperand::createImm(1));
+ Lea.addOperand(MCOperand::createReg(X86::NoRegister));
+ Lea.addOperand(
+ MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, Out.getContext())));
+ Lea.addOperand(MCOperand::createReg(X86::NoRegister));
+ Out.emitInstruction(Lea, STI);
+
+ // jmpq *(%r14)
+ MCInst Jmp;
+ Jmp.setOpcode(X86::JMP64m);
+ Jmp.addOperand(MCOperand::createReg(LFIBaseReg));
+ Jmp.addOperand(MCOperand::createImm(1));
+ Jmp.addOperand(MCOperand::createReg(X86::NoRegister));
+ Jmp.addOperand(MCOperand::createImm(0));
+ Jmp.addOperand(MCOperand::createReg(X86::NoRegister));
+ Out.emitInstruction(Jmp, STI);
+
+ Out.emitLabel(Symbol);
+}
+
+void X86::X86MCLFIRewriter::rewriteSyscall(const MCInst &Inst, MCStreamer &Out,
+ const MCSubtargetInfo &STI) {
+ emitLFICall(Out, STI);
----------------
nickdesaulniers wrote:
One call site. Just inline it? Or do you plan to have other calls like this?
https://github.com/llvm/llvm-project/pull/189569
More information about the cfe-commits
mailing list