Author: Zachary Yedidia
Date: 2025-12-16T12:51:02-08:00
New Revision: 2c05ae4b8f85927d55f862fdf61bea564e2ea944

URL: 
https://github.com/llvm/llvm-project/commit/2c05ae4b8f85927d55f862fdf61bea564e2ea944
DIFF: 
https://github.com/llvm/llvm-project/commit/2c05ae4b8f85927d55f862fdf61bea564e2ea944.diff

LOG: [LFI] Introduce AArch64 LFI Target (#167061)

This PR is the first step towards introducing LFI into LLVM as a new
sub-architecture backend of AArch64. For details, please see the
[RFC](https://discourse.llvm.org/t/rfc-lightweight-fault-isolation-lfi-efficient-native-code-sandboxing-upstream-lfi-target-and-compiler-changes/88380),
which has been approved for AArch64.

This patch creates the `aarch64_lfi` architecture, and marks the
appropriate registers as reserved when it is targeted (`x25`, `x26`,
`x27`, `x28`). It also adds a Clang driver toolchain for targeting LFI,
and updates the compiler-rt CMake to allow builds for the `aarch64_lfi`
target. The patch also includes documentation for LFI and the rewrites
that will be implemented in future patches.

I am planning to split the relevant modifications for LFI into a series
of patches, organized as described below (after this one). Please let me
know if you'd like me to split the changes in a different way, or
provide one big patch.

1. The next patch will introduce the `MCLFIExpander` mechanism for
applying the MC-level rewrites needed by LFI, along with the
`.lfi_expand` and `.lfi_no_expand` assembly directives when targeting
LFI. A preview can be seen on the `lfi-project`
[fork](https://github.com/llvm/llvm-project/compare/main...lfi-project:llvm-project:lfi-patchset/aarch64-pr-2).

2. The following patch will create an `MCLFIExpander` for the AArch64
backend that performs LFI expansions. This patch will contain the
majority of the LFI-specific logic.

3. The final patch will add an optimization to the rewriter that can
eliminate redundant guard instructions that occur within the same basic
block.

We plan to introduce x86-64 support after further discussion and once
the `MCLFIExpander` infrastructure is in place.

Please let me know your feedback, and thank you very much for your help
and guidance in the review process.

Added: 
    clang/lib/Driver/ToolChains/LFILinux.cpp
    clang/lib/Driver/ToolChains/LFILinux.h
    llvm/docs/LFI.rst

Modified: 
    clang/lib/Basic/Targets/AArch64.cpp
    clang/lib/Driver/CMakeLists.txt
    clang/lib/Driver/Driver.cpp
    compiler-rt/cmake/builtin-config-ix.cmake
    compiler-rt/lib/builtins/CMakeLists.txt
    llvm/docs/CodeGenerator.rst
    llvm/docs/UserGuides.rst
    llvm/include/llvm/TargetParser/Triple.h
    llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
    llvm/lib/Target/AArch64/AArch64Subtarget.h
    llvm/lib/TargetParser/Triple.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 476fa829bef61..ecd441be364c2 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -412,6 +412,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions 
&Opts,
     Builder.defineMacro("__aarch64__");
   }
 
+  if (getTriple().isLFI())
+    Builder.defineMacro("__LFI__");
+
   // Inline assembly supports AArch64 flag outputs.
   Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__");
 

diff  --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index d987111827597..0026ba8991719 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -65,6 +65,7 @@ add_clang_library(clangDriver
   ToolChains/Hexagon.cpp
   ToolChains/HLSL.cpp
   ToolChains/Hurd.cpp
+  ToolChains/LFILinux.cpp
   ToolChains/Linux.cpp
   ToolChains/Managarm.cpp
   ToolChains/MipsLinux.cpp

diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 802e02f061f9b..e63d5397d469b 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -29,6 +29,7 @@
 #include "ToolChains/Haiku.h"
 #include "ToolChains/Hexagon.h"
 #include "ToolChains/Hurd.h"
+#include "ToolChains/LFILinux.h"
 #include "ToolChains/Lanai.h"
 #include "ToolChains/Linux.h"
 #include "ToolChains/MSP430.h"
@@ -6916,6 +6917,8 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
         TC = std::make_unique<toolchains::OHOS>(*this, Target, Args);
       else if (Target.isWALI())
         TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args);
+      else if (Target.isLFI())
+        TC = std::make_unique<toolchains::LFILinux>(*this, Target, Args);
       else
         TC = std::make_unique<toolchains::Linux>(*this, Target, Args);
       break;

diff  --git a/clang/lib/Driver/ToolChains/LFILinux.cpp 
b/clang/lib/Driver/ToolChains/LFILinux.cpp
new file mode 100644
index 0000000000000..584a2eac93766
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/LFILinux.cpp
@@ -0,0 +1,24 @@
+//===-- LFILinux.cpp - LFI ToolChain Implementations ------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "LFILinux.h"
+#include "clang/Driver/Driver.h"
+
+using namespace clang::driver;
+using namespace clang::driver::toolchains;
+using namespace llvm::opt;
+
+ToolChain::CXXStdlibType LFILinux::GetDefaultCXXStdlibType() const {
+  return ToolChain::CST_Libstdcxx;
+}
+
+void LFILinux::AddCXXStdlibLibArgs(const ArgList &Args,
+                                   ArgStringList &CmdArgs) const {
+  ToolChain::AddCXXStdlibLibArgs(Args, CmdArgs);
+  CmdArgs.push_back("-lc++abi");
+}

diff  --git a/clang/lib/Driver/ToolChains/LFILinux.h 
b/clang/lib/Driver/ToolChains/LFILinux.h
new file mode 100644
index 0000000000000..1da494039bacf
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/LFILinux.h
@@ -0,0 +1,37 @@
+//===--- LFILinux.h - LFI ToolChain Implementations -------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H
+
+#include "Linux.h"
+
+namespace clang {
+namespace driver {
+namespace toolchains {
+
+class LLVM_LIBRARY_VISIBILITY LFILinux : public Linux {
+public:
+  LFILinux(const Driver &D, const llvm::Triple &Triple,
+           const llvm::opt::ArgList &Args)
+      : Linux(D, Triple, Args) {
+    ExtraOpts.push_back("-z");
+    ExtraOpts.push_back("separate-code");
+  }
+
+  CXXStdlibType GetDefaultCXXStdlibType() const override;
+
+  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
+                           llvm::opt::ArgStringList &CmdArgs) const override;
+};
+
+} // end namespace toolchains
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LFI_LINUX_H

diff  --git a/compiler-rt/cmake/builtin-config-ix.cmake 
b/compiler-rt/cmake/builtin-config-ix.cmake
index 238749681a6ca..fd815f841fec0 100644
--- a/compiler-rt/cmake/builtin-config-ix.cmake
+++ b/compiler-rt/cmake/builtin-config-ix.cmake
@@ -78,7 +78,7 @@ else()
 endif()
 
 set(AMDGPU amdgcn)
-set(ARM64 aarch64 arm64ec)
+set(ARM64 aarch64 arm64ec aarch64_lfi)
 set(ARM32 arm armhf armv4t armv5te armv6 armv6m armv7m armv7em armv7 armv7s 
armv7k armv8m.base armv8m.main armv8.1m.main)
 set(AVR avr)
 set(HEXAGON hexagon)

diff  --git a/compiler-rt/lib/builtins/CMakeLists.txt 
b/compiler-rt/lib/builtins/CMakeLists.txt
index 7e8621855eb84..a5ce9264d1c6b 100644
--- a/compiler-rt/lib/builtins/CMakeLists.txt
+++ b/compiler-rt/lib/builtins/CMakeLists.txt
@@ -741,6 +741,7 @@ set(arm64_SOURCES ${aarch64_SOURCES})
 set(arm64e_SOURCES ${aarch64_SOURCES})
 set(arm64_32_SOURCES ${aarch64_SOURCES})
 set(arm64ec_SOURCES ${aarch64_SOURCES})
+set(aarch64_lfi_SOURCES ${aarch64_SOURCES})
 
 # macho_embedded archs
 set(armv6m_SOURCES ${thumb1_SOURCES})

diff  --git a/llvm/docs/CodeGenerator.rst b/llvm/docs/CodeGenerator.rst
index a960ea13df60c..d5a019dcb06ba 100644
--- a/llvm/docs/CodeGenerator.rst
+++ b/llvm/docs/CodeGenerator.rst
@@ -2492,3 +2492,11 @@ The AMDGPU backend
 The AMDGPU code generator lives in the ``lib/Target/AMDGPU``
 directory. This code generator is capable of targeting a variety of
 AMD GPU processors. Refer to :doc:`AMDGPUUsage` for more information.
+
+The Lightweight Fault Isolation (LFI) sub-architecture
+------------------------------------------------------
+
+LFI is a sub-architecture available for certain backends that allows programs
+compiled for the target to run in a sandboxed environment that is within the
+same address space as host code. Refer to :doc:`LFI` for more information about
+LFI.

diff  --git a/llvm/docs/LFI.rst b/llvm/docs/LFI.rst
new file mode 100644
index 0000000000000..3c1cc96b2178d
--- /dev/null
+++ b/llvm/docs/LFI.rst
@@ -0,0 +1,414 @@
+=========================================
+Lightweight Fault Isolation (LFI) in LLVM
+=========================================
+
+.. contents::
+   :local:
+
+Introduction
+++++++++++++
+
+Lightweight Fault Isolation (LFI) is a compiler-based sandboxing technology for
+native code. Like WebAssembly and Native Client, LFI isolates sandboxed code 
in-process
+(i.e., in the same address space as a host application).
+
+LFI is designed from the ground up to sandbox existing code, such as C/C++
+libraries (including assembly code) and device drivers.
+
+LFI aims for the following goals:
+
+* Compatibility: LFI can be used to sandbox nearly all existing C/C++/assembly
+  libraries unmodified (they just need to be recompiled). Sandboxed libraries
+  work with existing system call interfaces, and are compatible with existing
+  development tools such as profilers, debuggers, and sanitizers.
+* Performance: LFI aims for minimal overhead vs. unsandboxed code.
+* Security: The LFI runtime and compiler elements aim to be simple and
+  verifiable when possible.
+* Usability: LFI aims to make it as easy as possible to retrofit sandboxing,
+  i.e., to migrate from unsandboxed to sandboxed libraries with minimal effort.
+
+When building a program for the LFI target the compiler is designed to ensure
+that the program will only be able to access memory within a limited region of
+the virtual address space, starting from where the program is loaded (the
+current design sets this region to a size of 4GiB of virtual memory). Programs
+built for the LFI target are restricted to using a subset of the instruction
+set, designed so that the programs can be soundly confined to their sandbox
+region. LFI programs must run inside of an "emulator" (usually called the LFI
+runtime), responsible for initializing the sandbox region, loading the program,
+and servicing system call requests, or other forms of runtime calls.
+
+LFI uses an architecture-specific sandboxing scheme based on the general
+technique of Software-Based Fault Isolation (SFI). Initial support for LFI in
+LLVM is focused on the AArch64 platform, with x86-64 support planned for the
+future. The initial version of LFI for AArch64 is designed to support the
+Armv8.1 AArch64 architecture.
+
+See `https://github.com/lfi-project <https://github.com/lfi-project/>`__ for
+details about the LFI project and additional software needed to run LFI
+programs.
+
+Compiler Requirements
++++++++++++++++++++++
+
+When building for the ``aarch64_lfi`` target, the compiler must restrict use of
+the instruction set to a subset of instructions, which are known to be safe
+from a sandboxing perspective. To do this, we apply a set of simple rewrites at
+the assembly language level to transform standard native AArch64 assembly into
+LFI-compatible AArch64 assembly.
+
+These rewrites (also called "expansions") are applied at the very end of the
+LLVM compilation pipeline (during the assembler step). This allows the rewrites
+to be applied to hand-written assembly, including inline assembly.
+
+Compiler Options
+================
+
+The LFI target has several configuration options.
+
+* ``+lfi-loads``: enable sandboxing for loads (default: true).
+* ``+lfi-stores``: enable sandboxing for stores (default: true).
+
+Use ``+nolfi-loads`` to create a "stores-only" sandbox that may read, but not
+write, outside the sandbox region.
+
+Use ``+nolfi-loads+nolfi-stores`` to create a "jumps-only" sandbox that may
+read/write outside the sandbox region but may not transfer control outside
+(e.g., may not execute system calls directly). This is primarily useful in
+combination with some other form of memory sandboxing, such as Intel MPK.
+
+Reserved Registers
+==================
+
+The LFI target uses a custom ABI that reserves additional registers for the
+platform. The registers are listed below, along with the security invariant
+that must be maintained.
+
+* ``x27``: always holds the sandbox base address.
+* ``x28``: always holds an address within the sandbox.
+* ``sp``: always holds an address within the sandbox.
+* ``x30``: always holds an address within the sandbox.
+* ``x26``: scratch register.
+* ``x25``: points to a thread-local virtual register file for storing runtime 
context information.
+
+Linker Support
+==============
+
+In the initial version, LFI only supports static linking, and only supports
+creating ``static-pie`` binaries. There is nothing that fundamentally precludes
+support for dynamic linking on the LFI target, but such support would require
+that the code generated by the linker for PLT entries be slightly modified in
+order to conform to the LFI architecture subset.
+
+Assembly Rewrites
+=================
+
+Terminology
+~~~~~~~~~~~
+
+In the following assembly rewrites, some shorthand is used.
+
+* ``xN`` or ``wN``: refers to any general-purpose non-reserved register.
+* ``{a,b,c}``: matches any of ``a``, ``b``, or ``c``.
+* ``LDSTr``: a load/store instruction that supports register-register 
addressing modes, with one source/destination register.
+* ``LDSTx``: a load/store instruction not matched by ``LDSTr``.
+
+Control flow
+~~~~~~~~~~~~
+
+Indirect branches get rewritten to branch through register ``x28``, which must
+always contain an address within the sandbox. An ``add`` is used to safely
+update ``x28`` with the destination address. Since ``ret`` uses ``x30`` by
+default, which already must contain an address within the sandbox, it does not
+require any rewrite.
+
++--------------------+---------------------------+
+|      Original      |         Rewritten         |
++--------------------+---------------------------+
+| .. code-block::    | .. code-block::           |
+|                    |                           |
+|    {br,blr,ret} xN |    add x28, x27, wN, uxtw |
+|                    |    {br,blr,ret} x28       |
+|                    |                           |
++--------------------+---------------------------+
+| .. code-block::    | .. code-block::           |
+|                    |                           |
+|    ret             |    ret                    |
+|                    |                           |
++--------------------+---------------------------+
+
+Memory accesses
+~~~~~~~~~~~~~~~
+
+Memory accesses are rewritten to use the ``[x27, wM, uxtw]`` addressing mode if
+it is available, which is automatically safe. Otherwise, rewrites fall back to
+using ``x28`` along with an instruction to safely load it with the target
+address.
+
++---------------------------------+-------------------------------+
+|            Original             |           Rewritten           |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM]               |    LDSTr xN, [x27, wM, uxtw]  |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM, #I]           |    add x28, x27, wM, uxtw     |
+|                                 |    LDSTr xN, [x28, #I]        |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM, #I]!          |    add xM, xM, #I             |
+|                                 |    LDSTr xN, [x27, wM, uxtw]  |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM], #I           |    LDSTr xN, [x27, wM, uxtw]  |
+|                                 |    add xM, xM, #I             |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM1, xM2]         |    add x26, xM1, xM2          |
+|                                 |    LDSTr xN, [x27, w26, uxtw] |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTr xN, [xM1, xM2, MOD #I] |    add x26, xM1, xM2, MOD #I  |
+|                                 |    LDSTr xN, [x27, w26, uxtw] |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTx ..., [xM]              |    add x28, x27, wM, uxtw     |
+|                                 |    LDSTx ..., [x28]           |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTx ..., [xM, #I]          |    add x28, x27, wM, uxtw     |
+|                                 |    LDSTx ..., [x28, #I]       |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTx ..., [xM, #I]!         |    add x28, x27, wM, uxtw     |
+|                                 |    LDSTx ..., [x28, #I]       |
+|                                 |    add xM, xM, #I             |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTx ..., [xM], #I          |    add x28, x27, wM, uxtw     |
+|                                 |    LDSTx ..., [x28]           |
+|                                 |    add xM, xM, #I             |
+|                                 |                               |
++---------------------------------+-------------------------------+
+| .. code-block::                 | .. code-block::               |
+|                                 |                               |
+|    LDSTx ..., [xM1], xM2        |    add x28, x27, wM1, uxtw    |
+|                                 |    LDSTx ..., [x28]           |
+|                                 |    add xM1, xM1, xM2          |
+|                                 |                               |
++---------------------------------+-------------------------------+
+
+Stack pointer modification
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the stack pointer is modified, we write the modified value to a temporary,
+before moving it back into ``sp`` with a safe ``add``.
+
++------------------------------+-------------------------------+
+|           Original           |           Rewritten           |
++------------------------------+-------------------------------+
+| .. code-block::              | .. code-block::               |
+|                              |                               |
+|    mov sp, xN                |    add sp, x27, wN, uxtw      |
+|                              |                               |
++------------------------------+-------------------------------+
+| .. code-block::              | .. code-block::               |
+|                              |                               |
+|    {add,sub} sp, sp, {#I,xN} |    {add,sub} x26, sp, {#I,xN} |
+|                              |    add sp, x27, w26, uxtw     |
+|                              |                               |
++------------------------------+-------------------------------+
+
+Link register modification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the link register is modified, we write the modified value to a
+temporary, before loading it back into ``x30`` with a safe ``add``.
+
++-----------------------+----------------------------+
+|       Original        |         Rewritten          |
++-----------------------+----------------------------+
+| .. code-block::       | .. code-block::            |
+|                       |                            |
+|    ldr x30, [...]     |    ldr x26, [...]          |
+|                       |    add x30, x27, w26, uxtw |
+|                       |                            |
++-----------------------+----------------------------+
+| .. code-block::       | .. code-block::            |
+|                       |                            |
+|    ldp xN, x30, [...] |    ldp xN, x26, [...]      |
+|                       |    add x30, x27, w26, uxtw |
+|                       |                            |
++-----------------------+----------------------------+
+| .. code-block::       | .. code-block::            |
+|                       |                            |
+|    ldp x30, xN, [...] |    ldp x26, xN, [...]      |
+|                       |    add x30, x27, w26, uxtw |
+|                       |                            |
++-----------------------+----------------------------+
+
+System instructions
+~~~~~~~~~~~~~~~~~~~
+
+System calls are rewritten into a sequence that loads the address of the first
+runtime call entrypoint and jumps to it. The runtime call entrypoint table is
+stored at the start of the sandbox, so it can be referenced by ``x27``. The
+rewrite also saves and restores the link register, since it is used for
+branching into the runtime.
+
++-----------------+----------------------------+
+|    Original     |         Rewritten          |
++-----------------+----------------------------+
+| .. code-block:: | .. code-block::            |
+|                 |                            |
+|    svc #0       |    mov w26, w30            |
+|                 |    ldr x30, [x27]          |
+|                 |    blr x30                 |
+|                 |    add x30, x27, w26, uxtw |
+|                 |                            |
++-----------------+----------------------------+
+
+Thread-local storage
+~~~~~~~~~~~~~~~~~~~~
+
+TLS accesses are rewritten into accesses offset from ``x25``, which is a
+reserved register that points to a virtual register file, with a location for
+storing the sandbox's thread pointer. ``TP`` is the offset into that virtual
+register file where the thread pointer is stored.
+
++----------------------+-----------------------+
+|       Original       |       Rewritten       |
++----------------------+-----------------------+
+| .. code-block::      | .. code-block::       |
+|                      |                       |
+|    mrs xN, tpidr_el0 |    ldr xN, [x25, #TP] |
+|                      |                       |
++----------------------+-----------------------+
+| .. code-block::      | .. code-block::       |
+|                      |                       |
+|    mrs tpidr_el0, xN |    str xN, [x25, #TP] |
+|                      |                       |
++----------------------+-----------------------+
+
+Optimizations
+=============
+
+Basic guard elimination
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If a register is guarded multiple times in the same basic block without any
+modifications to it during the intervening instructions, then subsequent guards
+can be removed.
+
++---------------------------+---------------------------+
+|         Original          |         Rewritten         |
++---------------------------+---------------------------+
+| .. code-block::           | .. code-block::           |
+|                           |                           |
+|    add x28, x27, wN, uxtw |    add x28, x27, wN, uxtw |
+|    ldur xN, [x28]         |    ldur xN, [x28]         |
+|    add x28, x27, wN, uxtw |    ldur xN, [x28, #8]     |
+|    ldur xN, [x28, #8]     |    ldur xN, [x28, #16]    |
+|    add x28, x27, wN, uxtw |                           |
+|    ldur xN, [x28, #16]    |                           |
+|                           |                           |
++---------------------------+---------------------------+
+
+Address generation
+~~~~~~~~~~~~~~~~~~
+
+Addresses to global symbols in position-independent executables are frequently
+generated via ``adrp`` followed by ``ldr``. Since the address generated by
+``adrp`` can be statically guaranteed to be within the sandbox, it is safe to
+directly target ``x28`` for these sequences. This allows the omission of a
+guard instruction before the ``ldr``.
+
++----------------------+-----------------------+
+|       Original       |       Rewritten       |
++----------------------+-----------------------+
+| .. code-block::      | .. code-block::       |
+|                      |                       |
+|    adrp xN, target   |    adrp x28, target   |
+|    ldr xN, [xN, imm] |    ldr xN, [x28, imm] |
+|                      |                       |
++----------------------+-----------------------+
+
+Stack guard elimination
+~~~~~~~~~~~~~~~~~~~~~~~
+
+**Note**: this optimization has not been implemented.
+
+If the stack pointer is modified by adding/subtracting a small immediate, and
+then later used to perform a memory access without any intervening jumps, then
+the guard on the stack pointer modification can be removed. This is because the
+load/store is guaranteed to trap if the stack pointer has been moved outside of
+the sandbox region.
+
++---------------------------+---------------------------+
+|         Original          |         Rewritten         |
++---------------------------+---------------------------+
+| .. code-block::           | .. code-block::           |
+|                           |                           |
+|    add x26, sp, #8        |    add sp, sp, #8         |
+|    add sp, x27, w26, uxtw |    ... (same basic block) |
+|    ... (same basic block) |    ldr xN, [sp]           |
+|    ldr xN, [sp]           |                           |
+|                           |                           |
++---------------------------+---------------------------+
+
+Guard hoisting
+~~~~~~~~~~~~~~
+
+**Note**: this optimization has not been implemented.
+
+In certain cases, guards may be hoisted outside of loops.
+
++-----------------------+-------------------------------+
+|       Original        |           Rewritten           |
++-----------------------+-------------------------------+
+| .. code-block::       | .. code-block::               |
+|                       |                               |
+|        mov w8, #10    |        mov w8, #10            |
+|        mov w9, #0     |        mov w9, #0             |
+|    .loop:             |        add x28, x27, wM, uxtw |
+|        add w9, w9, #1 |    .loop:                     |
+|        ldr xN, [xM]   |        add w9, w9, #1         |
+|        cmp w9, w8     |        ldr xN, [x28]          |
+|        b.lt .loop     |        cmp w9, w8             |
+|    .end:              |        b.lt .loop             |
+|                       |    .end:                      |
+|                       |                               |
++-----------------------+-------------------------------+
+
+References
+++++++++++
+
+For more information, please see the following resources:
+
+* `LFI project page <https://github.com/lfi-project/>`__
+* `LFI RFC 
<https://discourse.llvm.org/t/rfc-lightweight-fault-isolation-lfi-efficient-native-code-sandboxing-upstream-lfi-target-and-compiler-changes/88380>`__
+* `LFI paper <https://zyedidia.github.io/papers/lfi_asplos24.pdf>`__
+
+Contact info:
+
+* Zachary Yedidia - [email protected]
+* Tal Garfinkel - [email protected]
+* Sharjeel Khan - [email protected]

diff  --git a/llvm/docs/UserGuides.rst b/llvm/docs/UserGuides.rst
index 0551c8b60a62d..d3ca2f69016c1 100644
--- a/llvm/docs/UserGuides.rst
+++ b/llvm/docs/UserGuides.rst
@@ -49,6 +49,7 @@ intermediate LLVM representation.
    InstrProfileFormat
    InstrRefDebugInfo
    KeyInstructionsDebugInfo
+   LFI
    LinkTimeOptimization
    LoopTerminology
    MarkdownQuickstartTemplate
@@ -309,3 +310,6 @@ Additional Topics
 
 :doc:`Telemetry`
    This document describes the Telemetry framework in LLVM.
+
+:doc:`LFI <LFI>`
+    This document describes the Lightweight Fault Isolation (LFI) target in 
LLVM.

diff  --git a/llvm/include/llvm/TargetParser/Triple.h 
b/llvm/include/llvm/TargetParser/Triple.h
index 9480e7b36dc2c..fee8f36c369f7 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -153,6 +153,7 @@ class Triple {
 
     AArch64SubArch_arm64e,
     AArch64SubArch_arm64ec,
+    AArch64SubArch_lfi,
 
     KalimbaSubArch_v3,
     KalimbaSubArch_v4,
@@ -938,6 +939,12 @@ class Triple {
     return getArch() == Triple::arm || getArch() == Triple::armeb;
   }
 
+  /// Tests whether the target is LFI.
+  bool isLFI() const {
+    return getArch() == Triple::aarch64 &&
+           getSubArch() == Triple::AArch64SubArch_lfi;
+  }
+
   /// Tests whether the target supports the EHABI exception
   /// handling standard.
   bool isTargetEHABICompatible() const {

diff  --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp 
b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
index ab1df70d0cf53..34f492a35a451 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
@@ -439,6 +439,17 @@ AArch64RegisterInfo::getStrictlyReservedRegs(const 
MachineFunction &MF) const {
       markSuperRegs(Reserved, i);
   }
 
+  if (MF.getSubtarget<AArch64Subtarget>().isLFI()) {
+    markSuperRegs(Reserved, AArch64::W28);
+    markSuperRegs(Reserved, AArch64::W27);
+    markSuperRegs(Reserved, AArch64::W26);
+    markSuperRegs(Reserved, AArch64::W25);
+    if (!MF.getProperties().hasNoVRegs()) {
+      markSuperRegs(Reserved, AArch64::LR);
+      markSuperRegs(Reserved, AArch64::W30);
+    }
+  }
+
   for (size_t i = 0; i < AArch64::GPR32commonRegClass.getNumRegs(); ++i) {
     if (MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i))
       markSuperRegs(Reserved, AArch64::GPR32commonRegClass.getRegister(i));

diff  --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h 
b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index f4695589f7cdc..ee3f34a126d79 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -309,6 +309,7 @@ class AArch64Subtarget final : public 
AArch64GenSubtargetInfo {
   bool isTargetAndroid() const { return TargetTriple.isAndroid(); }
   bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); }
   bool isWindowsArm64EC() const { return TargetTriple.isWindowsArm64EC(); }
+  bool isLFI() const { return TargetTriple.isLFI(); }
 
   bool isTargetCOFF() const { return TargetTriple.isOSBinFormatCOFF(); }
   bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }

diff  --git a/llvm/lib/TargetParser/Triple.cpp 
b/llvm/lib/TargetParser/Triple.cpp
index 11ba9ee32f66a..2577b15b19992 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -116,6 +116,8 @@ StringRef Triple::getArchName(ArchType Kind, SubArchType 
SubArch) {
       return "arm64ec";
     if (SubArch == AArch64SubArch_arm64e)
       return "arm64e";
+    if (SubArch == AArch64SubArch_lfi)
+      return "aarch64_lfi";
     break;
   case Triple::spirv:
     switch (SubArch) {
@@ -594,6 +596,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
           .Case("aarch64", Triple::aarch64)
           .Case("aarch64_be", Triple::aarch64_be)
           .Case("aarch64_32", Triple::aarch64_32)
+          .Case("aarch64_lfi", Triple::aarch64)
           .Case("arc", Triple::arc)
           .Case("arm64", Triple::aarch64)
           .Case("arm64_32", Triple::aarch64_32)
@@ -832,6 +835,9 @@ static Triple::SubArchType parseSubArch(StringRef 
SubArchName) {
   if (SubArchName == "arm64ec")
     return Triple::AArch64SubArch_arm64ec;
 
+  if (SubArchName == "aarch64_lfi")
+    return Triple::AArch64SubArch_lfi;
+
   if (SubArchName.starts_with("spirv"))
     return StringSwitch<Triple::SubArchType>(SubArchName)
         .EndsWith("v1.0", Triple::SPIRVSubArch_v10)


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to