Contenu source (brut)
<p>There is currently a parallel race to the bottom for program optimization playing out in the Solana ecosystem. </p><p>At a high level, libraries like <a href="https://github.com/anza-xyz/pinocchio"><span style="text-decoration: underline">Pinocchio</span></a> are revolutionizing Rust development, achieving orders-of-magnitude improvements in compute efficiency. Meanwhile, at the absolute lowest level, a group of dedicated developers, united by their mutual disrespect of the compiler, are taking it one step further. Instead of writing Solana programs in compiled languages like Rust or C, they direct their focus towards meticulously hand-rolling bytecode to squeeze the maximum performance out of every last instruction.</p><p>These low-level gains are only possible when we directly instruct the VM in its native language: sBPF Assembly, Solana's own variant of the extended Berkeley Packet Filter (eBPF), the bytecode used and executed within every single on-chain program.</p><p>Writing sBPF assembly gives developers direct access to the lowest level interface of the Solana Virtual Machine. While the Rust compiler and LLVM attempt optimizations, due to insufficient verbosity of language syntax or a lack of sufficient context to make better compilation choices, they often end up generating suboptimal bytecode in comparison to that of a skilled developer with the complete instruction-level control that assembly enables. </p><p>While this added level of control comes at the cost of ergonomics, the savings in compute unit usage and binary size (and thus rent) are significant. These savings become especially important in highly contentious, competitive, performance-critical operations.</p><p>Simultaneously, there is also an argument to be made that not all programs should be written in assembly. </p><p>Although things have improved drastically, historically, the tooling has been limited, and more importantly, performance gains often come with the significant tradeoff of manual verification of correctness and increased audit costs. This is due to a lack of automated tooling and the syntax being more cumbersome to read, write, and understand. </p><p>Conversely, it may also be argued that compiled languages are a black box, obscuring the choices made by the compiler. Thus, the added transparency and control of assembly can often reveal things that are not easily visible when working with compiled languages. In fact, the vast majority of recent performance breakthroughs in our Rust SDKs were actually discovered and informed by realising we could hand-roll more efficient bytecode than the compiler.</p><p><strong>In this article, you'll learn:</strong></p><ul class="list-bullet"><li value=1>What sBPF Assembly is and how it provides direct control over the virtual machine</li><li value=2>The evolution from Berkeley Packet Filter to eBPF and why Solana adopted it</li><li value=3>sBPF's virtual machine architecture, instruction set, and memory model</li><li value=4>How to set up your development environment and build sBPF programs</li><li value=5>Step-by-step assembly programming through a practical memo example</li><li value=6>Essential security considerations when writing low-level code</li></ul><h2><strong>What is Assembly?</strong></h2><p>Assembly is a human-readable variant of machine code: the lowest-level programming language that directly corresponds to the instruction set of a CPU or VM.</p><p>Instead of variables and functions, assembly operates on <strong>registers</strong> (fast, temporary storage locations in the CPU), <strong>memory addresses</strong> (physical locations in RAM or on disk), and fundamental <strong>operations</strong> such as load (read from memory), store (persist to memory), arithmetic, and jumps (control flow).</p><p>Each instruction in assembly maps one-to-one to an equivalent instruction in machine code. </p><p>This one-to-one mapping means programmers control precisely what the processor executes, including which registers hold data, how memory is accessed, and the exact sequence of operations. </p><p>Unlike high-level languages, where a single function might generate dozens of instructions, assembly offers complete transparency and control over the machine's behavior without opaque abstractions.</p><h2><strong>What is Berkeley Packet Filter (BPF) and eBPF?</strong></h2><p>Berkeley Packet Filter (BPF) originated in 1992 as a virtual machine for efficiently filtering network packets in Unix kernels. The original BPF used a simple instruction set and register-based architecture that could run sandboxed code safely within the kernel.</p><p>Extended Berkeley Packet Filter (eBPF) modernized this concept, expanding from a packet filter into a general-purpose virtual machine. eBPF introduced a 64-bit architecture, more registers, and richer instruction sets, enabling complex programs to run securely in kernel space for networking, security, and system monitoring.</p><p>Solana adopted eBPF because it provided a proven, secure execution environment with built-in sandboxing. The sandboxing prevents programs from accessing system resources, crashing nodes, or interfering with other programs, while deterministic execution ensures all validators produce identical results. </p><p>Additionally, the register-based architecture and mature toolchain made it ideal for high-performance on-chain execution, while the existing LLVM backend allowed developers to compile from high-level languages like Rust.</p><h3>sBPF Virtual Machine Architecture</h3><p>When a Solana program executes, the runtime loads the sBPF bytecode into memory, performs static verification to ensure safety (checking for infinite loops, invalid memory access, and proper instruction usage), and then executes it within the virtual machine. </p><p>The VM provides a controlled 64-bit execution environment where programs run in complete isolation from the host system and other programs, with all resource access mediated through the runtime.</p><h3>sBPF Instruction Set Architecture</h3><p>sBPF operates with eleven 64-bit registers (r0-r10), with r10 serving as a read-only frame pointer, and r0 serving as a return register. </p><p>Instructions follow a consistent format with <strong>opcodes</strong> specifying operations (arithmetic, logic, memory access, jumps) and <strong>operands</strong> indicating source/destination registers, offsets, and/or immediate values. </p><p>Key instruction categories include ALU operations (add, subtract, bitwise), memory operations (load/store), and control flow (conditional/unconditional jumps).</p><h3>sBPF Memory Model</h3><p>sBPF programs operate within a structured memory layout: a 4KB stack for local variables and function calls, a heap for dynamic allocations, read-only program data containing the bytecode and constants, and account data regions that map to Solana accounts, which the program can access during execution.</p><p>All memory access is bounds-checked, and programs cannot access memory outside their designated regions.</p><h3>Solana Syscalls in sBPF</h3><p>sBPF programs cannot directly access system resources or perform I/O operations. Instead, they request services through syscalls, which are special instructions that transfer control to the Solana runtime. </p><p>In sBPF assembly, syscalls are invoked using the call instruction and a call symbol that is modified to a call target by the compiler at the time of assembly. Currently, syscalls are invoked via text-based dynamic relocations; a complicated string lookup table system that maps symbols to a 32-bit Mumur3 hash at JIT compilation. However, there is an <a href="https://github.com/solana-foundation/solana-improvement-documents/pull/178/files"><span style="text-decoration: underline">active proposal</span></a> to replace this with static syscalls, drastically simplifying calling conventions. When a syscall is invoked, arguments are passed through registers 1 through 5, w