
Assembly Memo
在本单元中,我们将使用 sBPF 汇编语言为我们的程序创建一个日志机制。
一个简单的备忘录程序是您开始 sBPF 汇编之旅的完美起点!
如果您不熟悉汇编编程,请参阅汇编入门课程
Program Design
我们的程序将简单地将正确的内存位置放入正确的寄存器中,然后执行 sol_log_ 系统调用。它看起来像这样:
sbpf
.equ NUM_ACCOUNTS, 0x00
.equ DATA_LEN, 0x08
.equ DATA, 0x10
.globl entrypoint
entrypoint:
ldxdw r0, [r1+NUM_ACCOUNTS]
ldxdw r2, [r1+DATA_LEN]
add64 r1, DATA
call sol_log_
exitMemory Offsets
程序开始时声明了三个 .equ 常量,这些常量定义了指令数据的内存布局:
sbpf
.equ NUM_ACCOUNTS, 0x00 ; Offset for number of accounts
.equ DATA_LEN, 0x08 ; Offset for data length
.equ DATA, 0x10 ; Offset for actual data这些常量标记了相对于 r1 的入口缓冲区指针的字节偏移:
NUM_ACCOUNTS(0x0000):指向指令数据头中用于验证的账户计数DATA_LEN(0x08):指向指令数据头中的指令数据长度DATA(0x10):指向指令数据头中的指令数据
与抽象内存布局的高级语言不同,汇编语言需要确切知道每一部分数据的位置。
Entrypoint and Initial Validation
sbpf
.globl entrypoint
entrypoint:
ldxdw r0, [r1+NUM_ACCOUNTS] ; Load number of accounts into r0每个 sBPF 程序都从一个全局 .entrypoint 符号开始。Solana 运行时通过寄存器 r1 提供账户和指令数据。
第一条指令将账户数量加载到 r0 中。由于 r0 是虚拟机在退出时读取的寄存器,这样做有两个目的:
加载账户计数供我们使用
如果传递了任何账户(r0 中的非零值),程序将自动失败
Sol Log Syscall
接下来,我们为sol_log_系统调用准备参数:
sbpf
ldxdw r2, [r1+DATA_LEN] ; Load length of memo into r2
add64 r1, DATA ; Adjust r1 to point to memo bytes这些指令设置了sol_log_的参数:
r2接收备忘录数据的长度r1被调整为直接指向备忘录字节
然后,我们调用sol_log_并退出:
sbpf
call 16 ; Call sol_log_ (helper ID 16)
exit ; Return using r0 valueConclusion
该程序:
调用16(
sol_log_)将备忘录打印到验证器日志使用
r0中的值退出