Contoh Program
Sekarang mari kita lihat bagaimana register (r0-r10), region memori, dan instruksi bekerja bersama dalam program yang sebenarnya. Kita akan mulai dengan program sBPF paling sederhana untuk memahami alur eksekusi fundamental.
NoOp-program
Program "NoOp" (No Operation) sangat cocok untuk pembelajaran karena menunjukkan struktur program yang esensial tanpa kerumitan:
Bagaimana program menerima input (dalam register r1)
Bagaimana program mengembalikan hasil (dalam register r0)
Alur masuk/keluar dasar yang diikuti setiap program sBPF
Bagaimana Rust dikompilasi menjadi assembly sBPF
Meskipun program ini "tidak melakukan apa-apa," program ini menunjukkan dasar yang menjadi landasan setiap program Solana.
Sekarang kita telah mengetahui operasi dasar sBPF, mari kita lihat seperti apa operasi tersebut dalam program nyata (meskipun sangat kecil).
Pinocchio NoOp
Di bawah ini adalah "noop" berkinerja tinggi yang ditulis dengan Pinocchio. Yang dilakukannya hanyalah mengembalikan keberhasilan:
#![no_std]
use pinocchio::{entrypoint::InstructionContext, lazy_program_entrypoint, no_allocator, nostd_panic_handler, ProgramResult};
lazy_program_entrypoint!(process_instruction);
nostd_panic_handler!();
no_allocator!();
fn process_instruction(
_context: InstructionContext, // wrapper around the input buffer
) -> ProgramResult {
Ok(())
}Jika kita membangun kode ini dengan cargo build-sbf --dump, kita akan mendapatkan dump ELF yang memberikan informasi tentang binary kita di direktori /target/deploy/.
Kemudian kita perlu mencari bagian .text — bagian dari binary kita tempat kode yang dapat dieksekusi disimpan.
Disassembly of section .text
0000000000000120 <entrypoint>
120 b7 00 00 00 00 00 00 00 mov64 r0, 0x0
128 95 00 00 00 00 00 00 00 exitMari kita uraikan apa arti byte-byte heksadesimal ini menggunakan format instruksi yang telah kita pelajari:
Ini adalah instruksi pertama: 120 b7 00 00 00 00 00 00 00
Alamat:
0x120(dalam region teks yang dimulai pada 0x100000000)Opcode:
0xb7=mov64dengan nilai immediatedst:
0x00= registerr0src:
0x00= tidak digunakan (operasi immediate)offset:
0x0000= tidak digunakanimm:
0x00000000= nilai immediate 0
Dan ini adalah instruksi kedua: 128 95 00 00 00 00 00 00 00
Alamat:
0x128(8 byte setelah instruksi pertama)Opcode:
0x95= exit/returnSemua field lainnya:
0x00= tidak digunakan untuk exit
Assembly NoOp
Jika kita mendisassembly binary untuk mengubahnya kembali menjadi sBPF Assembly yang dapat dikompilasi, kodenya akan terlihat seperti ini:
.globl entrypoint
entrypoint:
mov64 r0, 0x00 // r0 <- success
exit // finish, return r0Mari kita uraikan kodenya:
.globl entrypoint: Ini adalah direktif assembler yang memberi tahu linker untuk membuat simbol entrypoint terlihat secara global. Runtime Solana mencari simbol ini untuk mengetahui di mana harus mulai mengeksekusi program Anda.entrypoint: Ini adalah label yang menandai alamat memori di mana eksekusi program dimulai. Ketika runtime memuat program Anda, ia melompat ke alamat ini.mov64 r0, 0x00: Memindahkan nilai langsung 0 ke register r0. Karena r0 adalah register return, ini menyiapkan kode return sukses.exit: Mengakhiri eksekusi program dan mengembalikan nilai dalam r0 ke runtime.
Ini adalah program yang sangat kecil, dengan hanya 2 instruksi yang mengkonsumsi hanya 2 compute unit (CU) untuk dieksekusi yang memetakan dengan sempurna ke kode Rust kita:
Kita mendefinisikan fungsi entrypoint
Kita mengembalikan Ok(()) yang dievaluasi menjadi 0
Compiler menghasilkan instruksi
mov64danexityang sesuai
Optimized Assembly NoOp
Namun, kita dapat mengoptimalkan ini lebih lanjut. Karena runtime Solana menginisialisasi r0 ke 0 secara default, kita dapat menghilangkan instruksi mov64 yang redundan:
.globl entrypoint
entrypoint:
exitVersi yang dioptimalkan ini:
Hanya membutuhkan 1 unit komputasi (pengurangan 50%!)
Menghasilkan hasil yang identik (
r0masih berisi 0)
Optimasi ini dimungkinkan karena kita mengetahui status register awal — sesuatu yang tidak selalu dimanfaatkan oleh compiler Rust. Memahami assembly sBPF memungkinkan Anda mengidentifikasi dan menghilangkan inefisiensi seperti ini dalam kode yang kritis terhadap performa.