Макросы и условная сборка
Контекст: NASM. Макросы обрабатывает ассемблер при сборке, процессор их не выполняет. См. Основы про различие мнемоник и директив.
Макрос и подпрограмма
Подпрограмма (call) | Макрос (%macro) | |
|---|---|---|
| Когда разворачивается | при запуске | при сборке |
| Размер кода | один экземпляр в .text | копия на каждый вызов макроса |
| Стоимость | переход + стек | только инструкции тела |
| Отладка | одна метка | повторяющиеся блоки в листинге |
Макрос уместен для коротких шаблонов (пролог, обёртка над syscall, развёртка цикла). Длинную логику выносят в call.
Текстовые константы — %define
%define SYS_WRITE 1
%define SYS_EXIT 60
%define STDOUT 1
mov rax, SYS_WRITE
mov rdi, STDOUT
Препроцессор подставляет текст до разбора инструкций. Это не переменная в памяти и не символ линкера.
Параметризованный макрос — %macro
%macro exit 1
mov rax, 60
mov rdi, %1
syscall
%endmacro
_start:
; ...
exit 0
- Имя:
exit. - Число после имени: обязательное количество аргументов (
1). %1,%2… — подстановка аргументов.
Макрос с необязательными параметрами: %macro name min [-max+].
Локальные метки в макросах
Если макрос содержит метки, при повторном включении имена столкнутся. В NASM используют %% для метки, уникальной на каждое раскрытие:
%macro push_callee_saved 0
push rbx
push rbp
push r12
push r13
push r14
push r15
%endmacro
%macro pop_callee_saved 0
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
%endmacro
Внутри макроса с циклом:
%macro rep_zero 2
xor rax, rax
%%loop:
mov [%1 + %2 * 8 - 8], rax ; пример: обнулить массив слов
dec %2
jnz %%loop
%endmacro
Условная сборка — %if, %ifdef
%define ARCH_BITS 64
%if ARCH_BITS == 64
%define PTR_SIZE 8
%else
%define PTR_SIZE 4
%endif
Проверка наличия макроса:
%ifdef DEBUG
; вставить отладочный вывод
%endif
Так собирают разные варианты одного файла без ручного редактирования (отладка, платформа, размер слова).
%include — подключение файла
%include "macros.inc"
%include "syscall.inc"
Содержимое включается как будто вставлено в текущую позицию. Удобно для общих макросов и констант; исполняемый код чаще выносят в отдельные .asm с global/extern — см. несколько модулей.
Типичные ошибки
| Проблема | Решение |
|---|---|
Метка loop: в макросе, вызванном дважды | %%loop |
Ожидание, что %1 вычислится в runtime | аргументы макроса — константы сборки |
| Огромный макрос в горячем цикле | раздувает I-cache; заменить на call |
%define с выражением с запятой | использовать скобки или %assign для чисел |
%assign counter 0 — целочисленная переменная времени сборки (можно %assign counter counter+1 в макросе для генерации таблиц).
Макрос для системного вызова (Linux x86-64)
%macro syscall3 3
mov rax, %1
mov rdi, %2
mov rsi, %3
syscall
%endmacro
; syscall3 1, 1, msg ; write — для полного write нужен ещё rdx
Для четырёх и более аргументов расширяют шаблон (rdx, r10 … по ABI). Полная таблица номеров — в справочнике.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Полный отказ от высокоуровневых языков нецелесообразен. Поэтому большинство компиляторов поддерживают встроенный ассемблер — механизм вставки ассемблерных инструкций непосредственно в код на C/C++. Разделение программы на .asm-файлы, global и extern, сборка объектников и линковка в ELF. Вызов ассемблерных функций из C и наоборот — System V AMD64 ABI, выравнивание стека, сборка. Секции ELF, символы, objdump и сопоставление дизассемблирования с исходным NASM-кодом. REP, MOVS, SCAS, STOS, флаг DF и доступ к данным по индексу через таблицу. SSE2 для float и double, регистры XMM, выравнивание; кратко про стек x87 и AVX. Microsoft x64 calling convention, shadow space, вывод в консоль и файлы через API вместо syscall. Основы ассемблера - синтаксис Intel/AT&T, базовые инструкции и принципы низкоуровневого программирования. Архитектура ассемблерных программ - взаимодействие с ОС, вызовы библиотек и организация низкоуровневого кода. Типизация, набор правил определения типа данных значений языка. Управляющие конструкции и команды процессора в ассемблере - регистр команд, переходы и управление потоком исполнения. Команды и подпрограммы в ассемблере - передача параметров, соглашения вызовов и работа со стеком.История ассемблерных языков
Несколько модулей и линковка
Взаимодействие с C и C++
Чтение исполняемого файла и листинга
Строковые инструкции и таблицы поиска
Числа с плавающей точкой и SIMD
Windows x64, WinAPI и отличия от Linux
Основы ассемблера
Архитектура ассемблерных программ
Типы данных и регистры
Управляющие конструкции и команды процессора
Команды и подпрограммы