NASM — section, регистры, аргументы

Основные секции section в NASM Linux
 
Помимо стандартных, в программах могут использоваться следующие секции:

Секция Назначение Права доступа Какие данные там хранить
.text Код программы Чтение / Выполнение (R-X) Инструкции процессора, константные метки переходов.
.data Инициализированные данные Чтение / Запись (RW-) Переменные с начальным значением (строки, массивы, числа). Увеличивает размер бинарного файла.
.bss Неинициализированные данные Чтение / Запись (RW-) Буферы, массивы под вывод/ввод. Не занимает места в файле на диске, выделяется при старте.
.rodata Данные только для чтения Только чтение (R--) Строковые константы, неизменяемые переменные, математические константы (например, число Пи). Защищает от случайной перезаписи.

Пример использования .rodata:
nasm
section .rodata
    PI dq 3.141592653589793     ; Константа, которую нельзя изменить 
 
Регистры общего назначения и их роли при syscall
Когда вы делаете syscall в Linux x86-64, ядро ожидает параметры в строго определенных регистрах:
  • rax — Номер системного вызова (например, 1 для write, 60 для exit). Сюда же возвращается результат операции.
  • rdi — 1-й аргумент системного вызова (например, дескриптор файла).
  • rsi — 2-й аргумент (указатель на память).
  • rdx — 3-й аргумент (размер данных / счетчик).
  • r10 — 4-й аргумент.
  • r8 — 5-й аргумент.
  • r9 — 6-й аргумент.
Регистры при вызове функций (User-level ABI)
Если вы вызываете функции (свои или из внешних библиотек через call), правила немного меняются. Первые 6 аргументов передаются через:

rdi, rsi, rdx, rcx, r8, r9.

 
 
Какие регистры использовать в кодовой секции (.text)
 
В современной архитектуре x86-64 регистры общего назначения делятся в основном по логике системных вызовов (Linux ABI) и функций. Вы можете использовать их для любых вычислений, но при вызове syscall или функций из библиотек (например, C printf) они имеют строгое назначение.
1. Регистры для работы с .data, .bss и .rodata (Адресация)
Для загрузки адресов переменных или буферов в регистры используется инструкция mov или lea. Чаще всего для хранения указателей (адресов) используют:
  • rsi (Source Index) — традиционно используется как указатель на источник данных (например, адрес строки для вывода).
  • rdi (Destination Index) — используется как указатель на приемник данных.
  • rbp (Base Pointer) — базовый указатель на стек (для локальных переменных функций).
  • rbx, rcx, rdx — также могут хранить любые адреса.
  • Пример:
mov rsi, msg ; Поместить адрес строки из .data в rsi
mov rdi, buffer ; Поместить адрес буфера из .bss в rdi
 
Особые регистры: Стек и Указатель команд
В Linux есть регистры, которые неявно привязаны к специфичным областям памяти (но не к секциям .data/.bss):
  1. rsp (Stack Pointer) — Указатель стека. Стек — это отдельная динамическая область памяти. rsp всегда указывает на «вершину» стека. Изменять его напрямую нужно аккуратно (через push, pop, sub rsp, X).
  2. rip (Instruction Pointer) — Указатель на текущую инструкцию в секции .text. Вы не можете изменить его командой mov rip, rax. Он меняется автоматически при выполнении кода, а также командами переходов (jmp, je) и вызовов (call, ret).
    • Примечание: В x86-64 часто используется адресация относительно rip для доступа к секциям данных (RIP-relative addressing), например: mov rax, [rel msg]. NASM в Linux часто делает это автоматически.

 
Пример кода:

section .data
msg db «Моя информация о программе», 10 , 13
msg_len equ $-msg

section .text

global _start
_start:

;Вывод на экран в STDOUT

mov rax, 1
mov rdi,1
mov rsi, msg
mov rdx, msg_len
syscall

;Завершение программы

mov rax, 60
mov rdi, 0
syscall

 

 

Оставьте первый комментарий

Отправить ответ