Assembly
Assembly簡介

Assembly簡介

sBPF 暫存器與記憶體模型

當你的 sBPF 程式執行時,它會使用兩種主要的儲存機制:處理器內建的 11 個高速暫存器,以及組織化的記憶體區域來存放其他所有內容。

Registers

暫存器就像處理器內建的 11 個編號儲存槽(r0r10)。每個暫存器可存放一個 64 位元的值,並能即時存取,毫無延遲。當你執行 add64 r1, r2 時,處理器會立即從兩個暫存器中檢索值並執行計算。

權衡很簡單:你總共只有 11 個儲存槽,因此需要策略性地使用它們來存放你正在處理的值。

sBPF 為每個暫存器分配了特定的角色:

暫存器角色是否由被呼叫方保存?使用說明
r0返回值函數結果、系統呼叫返回值
r1輸入緩衝區指標進入時指向 0x400000000
r2-r5暫存/參數輔助函數參數、臨時值
r6-r9通用用途必須在呼叫間保留
r10幀指標是,只讀堆疊基底,不能直接修改

暫存器 r6r9由被呼叫方保存 的,這意味著它們的值在函數呼叫期間會保持不變。使用這些暫存器來存放需要在函數調用中保留的重要數據。

其餘的暫存器(r0-r5)在系統呼叫和函數呼叫期間會被覆蓋。

暫存器 r10 是「特殊的」,因為它作為你的幀指標,指向你的堆疊空間基底並保持只讀。你可以使用負偏移量(例如 [r10 - 8][r10 - 16])來訪問堆疊變數。

記憶體

雖然暫存器保存活躍使用的值,但記憶體則存儲其他所有內容。sBPF 將記憶體組織成固定區域,並在所有程式中具有相同的佈局:

區域起始地址用途大小/備註
Text0x100000000程式碼和唯讀數據程式二進制文件
Stack0x200000000局部變量每個堆疊框架 4 KiB,最大呼叫深度為 64
Heap0x300000000動態分配32 KiB
Input0x400000000程式參數序列化的帳戶和指令數據
  • Text 區域 包含可執行程式碼和唯讀數據,例如字串常量。使用 .quad 指令定義的數據通常位於此處。

  • Stack 區域 存放局部變量。r10 指向堆疊基址,您可以使用負偏移量訪問局部變量,例如 [r10 - 16][r10 - 24] 等。

  • Input 區域 包含程式的參數。在進入時,r1 指向此區域 (0x400000000),允許您讀取序列化的帳戶數據和傳遞給程式的指令參數。

這種固定佈局提供了三個主要優勢:通過程式間記憶體隔離實現安全性,通過在所有驗證器中使用相同地址實現確定性,以及通過編譯器針對已知位置的優化提升性能。

嘗試訪問未映射的地址會觸發 AccessViolation,並導致交易失敗。

使用暫存器和記憶體

以下是暫存器和記憶體如何在實踐中協同工作的方式:

sbpf
.globl entrypoint
entrypoint:
    // On entry: r1 points to input data at 0x400000000
    
    ldxdw r0, [r1 + 0]      // Load first 8 bytes from input into r0
    mov64 r2, 42            // Put 42 in register r2
    add64 r0, r2            // Add them: r0 = r0 + r2
    
    stxdw [r10 - 8], r0     // Store result on stack
    mov64 r0, 0             // Return success
    exit

此程式展示了典型模式:

  • 使用暫存器 r1(輸入指針)從記憶體中讀取

  • 使用暫存器 r0r2 進行計算

  • 使用暫存器 r10(框架指針)訪問堆疊記憶體

  • 在暫存器 r0 中返回結果

工作流程遵循一致的模式:將數據從記憶體加載到暫存器,使用暫存器進行計算,然後在需要時將結果存回記憶體。

堆疊使用

堆疊使用 r10 作為框架指標,指向當前堆疊框架的基址(最高地址)。局部變量使用負偏移量:

sbpf
// Store a value on the stack
mov64 r0, 42
stxdw [r10 - 8], r0         // Store at first stack slot

// Load it back
ldxdw r1, [r10 - 8]         // Load from first stack slot

堆疊槽通常為 8 字節寬,因此連續的變量使用類似 [r10 - 8][r10 - 16][r10 - 24] 等偏移量。

程式的進入與退出

程式從標記為 .globl(通常是 entrypoint)的符號開始執行。初始暫存器狀態是最小且可預測的:

sbpf
.globl entrypoint
entrypoint:
    // On entry:
    // r1 = 0x400000000 (input buffer pointer)
    // r10 = 0x200001000 (0x200000000 stack start + 0x1000 4KiB frame size)
    // r0, r2-r9 = 0 (all other registers zeroed)

    // Your program logic here

    mov64 r0, 0     // Success code (0 = SUCCESS)
    exit            // Return to runtime

退出行為取決於呼叫深度:

  • 在呼叫深度為 0 時,退出會以 r0 作為結果代碼終止程式。

  • 在更深的呼叫層次,退出的行為類似於 return 語句,恢復呼叫者保存的暫存器(r6-r9)和呼叫者的框架指標(r10),然後在返回地址繼續執行。

運行時通過隱式的序言和尾聲代碼自動處理設置和拆卸,包括初始暫存器狀態配置和最終返回處理。

Blueshift © 2025Commit: e573eab