Препроцессорная конструкция %if позволяет проверить значение некоторое условие - обычно значение препроцессорного символа и зависимости от результата проверки выполнить некоторые действия.
Такая директива также обрабатывается препроцессором и заменяется на код ассемблера до собственно компиляции. Эта директива аналогичная конструкции if..else
во ряде высокоуровневых языков программирования. В простейшем виде она имеет следующий синтаксис:
%if условие действия, которые выполняются при истинности условия %endif
Например:
global _start %define STATUS_CODE 22 section .text _start: %if STATUS_CODE == 22 mov rdi, 44 %endif mov rax, 60 syscall
Здесь проверяется значение константы STATUS_CODE. Если она равна 22, то в регистр rdi будет помещаться число 44. То есть в реальности к стадии компиляции мы получим текст программы:
global _start section .text _start: mov rdi, 44 mov rax, 60 syscall
В качестве условия можно использовать стандартные операции сравнения:
Проверка на равенство - оператор ==
Проверка на неравенство - оператор !=
Другие операции сравнения (больше чем, меньше чем и т.д.) <
, <=
, >
, >=
Логические операции, которые объединяют несколько операций сравнения - &&
(операция И - истинны должны быть оба условия), ||
(операция ИЛИ - истинным может быть хотя бы одно условие)
Пример:
%define STATUS_CODE 22 %if STATUS_CODE != 23 && STATUS_CODE > 10 mov rdi, 41 %endif
Здесь условие истинно, если STATUS_CODE не равен 23 и больше 10.
Если нам надо добавить альтернативные действия на случай, если условие ложно, то применяется директива %else:
global _start %define STATUS_CODE 22 section .text _start: %if STATUS_CODE == 23 mov rdi, 23 ; если STATUS_CODE равно 23, то в rdi число 23 %else mov rdi, 46 ; если STATUS_CODE не равно 23, то в rdi число 46 %endif mov rax, 60 syscall
С помощью директивы %elif можно вводить альтернативные действия для дополнительных условий:
global _start %define STATUS_CODE 22 section .text _start: %if STATUS_CODE == 21 mov rdi, 1 %elif STATUS_CODE == 22 mov rdi, 2 %elif STATUS_CODE == 23 mov rdi, 3 %else mov rdi, 4 %endif mov rax, 60 syscall
NASM позволяет во время компиляции решать, будет ли та или иная часть файла участвовать в сборке приложения. Для этого применяется директива %ifdef. Она проверяет определение некоторого препроцессорного символа. Если символ определен, то в файл при компиляции добавляется код, который расположен между %ifdef и %endif. Например:
global _start %define SET_STATUS 1 section .data %ifdef SET_STATUS status_code: db 8 %endif section .text _start: %ifdef SET_STATUS mov rdi, [status_code] %endif mov rax, 60 syscall
Здесь, если определен символ SET_STATUS, то в секции data определяется переменная status_code, а инструкция mov помещает ее значение в регистр rdi.