Assembly
Вступ до асемблера

Вступ до асемблера

Регістри sBPF та модель пам'яті

Коли ваша програма sBPF виконується, вона працює з двома основними механізмами зберігання: 11 високошвидкісними регістрами, вбудованими в процесор, та організованими областями пам'яті, які містять все інше.

Registers

Регістри — це ніби 11 пронумерованих комірок зберігання (від r0 до r10), вбудованих безпосередньо в процесор. Кожен містить одне 64-бітне значення і забезпечує миттєвий доступ без затримок. Коли ви виконуєте add64 r1, r2, процесор негайно отримує значення з обох регістрів і виконує обчислення.

Компроміс простий: у вас є лише 11 комірок загалом, тому вам потрібно використовувати їх стратегічно для значень, з якими ви активно працюєте.

sBPF призначає кожному регістру певну роль:

РегістрРольЗберігається викликаним?Примітки щодо використання
r0Значення, що повертаєтьсяНіРезультати функцій, значення, що повертаються системними викликами
r1Вказівник на вхідний буферНіВказує на 0x400000000 при вході
r2-r5Тимчасові/аргументиНіАргументи допоміжних функцій, тимчасові значення
r6-r9Загального призначенняТакПовинні зберігатися між викликами
r10Вказівник кадруТак, тільки для читанняОснова стеку, не можна змінювати напряму

Регістри від r6 до r9 є збереженими викликаним, що означає, що їхні значення зберігаються під час викликів функцій. Використовуйте їх для важливих даних, які повинні зберігатися під час викликів функцій.

Решта регістрів (r0-r5) перезаписуються під час системних викликів та викликів функцій.

Регістр r10 є "особливим", оскільки він служить вказівником кадру, вказуючи на основу вашого стекового простору і залишаючись доступним лише для читання. Ви отримуєте доступ до змінних стеку, використовуючи від'ємні зміщення, такі як [r10 - 8] та [r10 - 16].

Пам'ять

У той час як регістри зберігають активно використовувані значення, пам'ять зберігає все інше. sBPF організовує пам'ять у фіксовані регіони з однаковими макетами для всіх програм:

РегіонПочаткова адресаПризначенняРозмір/Примітки
Text0x100000000Код та дані тільки для читанняБінарний файл програми
Stack0x200000000Локальні змінні4 КіБ на кожен кадр стеку, з максимальною глибиною виклику 64
Heap0x300000000Динамічне виділення32 КіБ
Input0x400000000Параметри програмиСеріалізовані облікові записи та дані інструкцій
  • Текстовий регіон містить ваш виконуваний код та дані тільки для читання, такі як рядкові константи. Дані, визначені з директивами .quad, зазвичай розміщуються тут.
  • Регіон стеку містить локальні змінні. З r10, що вказує на базу стеку, ви отримуєте доступ до локальних змінних, використовуючи від'ємні зміщення: [r10 - 16], [r10 - 24] тощо.
  • Вхідний регіон містить параметри вашої програми. При вході 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 (вказівник на вхідні дані) для читання з пам'яті
  • Використовує регістри r0 та r2 для обчислень
  • Використовує регістр 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 (зазвичай точка входу). Початковий стан регістрів є мінімальним і передбачуваним:

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 як кодом результату.
  • На глибших рівнях виклику, вихід діє як оператор повернення, відновлюючи регістри, що зберігаються викликаючою стороною (r6-r9) та вказівник кадру викликаючої сторони (r10) перед продовженням виконання за адресою повернення.

Середовище виконання автоматично обробляє налаштування та завершення через неявний код прологу та епілогу, включаючи конфігурацію початкового стану регістрів та кінцеву обробку повернення.

Blueshift © 2025Commit: 6d01265