Ассемблер MASM поддерживает условную компиляцию, которая позволяет при определенных условиях компилировать определенный код. Для этого применяется конструкция if:
if условие текст endif
После слова if указывается условие. В качестве условия может принимае Это должно быть константное выражение (константа или операция над константами) или вызов функции на этапе компиляции,
результатом которого является целочисленное значение. Во время компиляции ассемблер оценивает это выражение.
Если выражение оценивается как истинное (не равно нулю), MASM обрабатывает код, который идет до endif
.
Если выражение оценивается как ложное (равно нулю), MASM обрабатывает весь текст между if и соответствующим предложением endif, как если бы это был комментарий. Причем поскольку условие
оценивается в момент сборки, то оно не должно вовлекать переменные, значение которых известно только во время выполнение, а не во время компиляции.
Конструкция if поддерживает необязательные выражения elseif
и else
, которые позволяют добавить альтернативные действия, если условие после if
неверно:
if условие1 текст elseif условие2 текст else текст endif
Если условие после if
оценивается как истинное, то MASM обрабатывает текст до выражения elseif
. Затем он пропускает весь текст (то есть обрабатывает его как комментарий) до тех пор, пока не встретит предложение endif
.
Если условие после if
оценивается неверно, MASM пропускает весь текст, пока не встретит выражение elseif
, else
или endif
.
Если встречается выражение elseif
, MASM оценивает условие после elseif
. Если оно верно, MASM обрабатывает текст между предложениями elseif
и
else
(или до выражения endif
, если выражение else
отсутствует). Конструкция if
может содержать множество выражений elseif
.
Если условие после elseif
неверно, MASM пропускает связанный с ними текст и начинает обрабатывать текст в выражении else
при его наличии.
Обычно условная компиляция применяется при необходимости разграничить компиляцию в зависимости от внешних условий. Например, в зависимости от процессора могут отличать возможности, которые нам предоставляются для создания программы. Так, если процессор не поддерживает 64-разрядные регистры, то соответственно мы не сможем их использовать. И тут мы могли бы применить условную компиляцию:
cpu64 = 1 .code main proc if cpu64 mov rax, 64 else mov eax, 32 endif ret main endp end
Здесь условие представлено константой cpu64. Будет считать, что если процессор - 64-разрядный, то для ее устанавливаем значение 1. Для простоты, если это условие равно 1, то используем 64-разрядный регистр RAX. Если условие равно 0 (то есть процессор 32-разрядный), то используем 32-разрядный регистр EAX.
Другое частое применение условной компиляции представляет тестирование или отладка, когда при тестировании и отладке выводится информация о состоянии регистров или переменных на консоль.
Операторы MASM while..endm, for..endm и forc..endm предоставляют циклические конструкции, которые выполняются во время компиляции.
Оператор while указывает MASM многократно обрабатывать одну и ту же последовательность операторов во время сборки. Это удобно для построения таблиц данных, а также для обеспечения традиционной циклической структуры для программ времени компиляции. Этот оператор имеет следующий синтаксис:
while условие код endm
Если условие после while
является неверным, MASM пропускает текст между выражениями while
и endm
(аналогично оператору if). Если выражение является истинным, MASM обработает операторы между выражениями while
и endm
, а затем
повторяет этот процесс, пока истинно условие. Рассмотрим простейший пример:
.data nums dword 1, 2, 3, 4 .code i = 0 main proc xor rax, rax while i LT lengthof nums add eax, nums[i * 4] ; константа i в качестве индекса i = i + 1 endm ret main endp end
Здесь оператор while
проверяет условие i LT lengthof nums
. Для определения условия применяется оператор LT
(меньше чем), то есть, чтобы
условие было истинным, левый операнд - значение константы i должно быть меньше правого операнда - lengthof nums
. Константа i представляет своего рода индекс для
обращения к элементам к числам в массиве nums. Правый операнд - lengthof nums
с помощью оператора lengthof
вычисляет количество элементов в массиве nums.
Поскольку в массиве nums 4 элемента, то действия внутри конструкции while
будут повторяться, покак значение константы i не окажется равным 4. Каждое повторение цикла называется итерацией,
то есть в данном случае выполняться 4 итерации.
Для примера внутри конструкции while
складываем каждое число из массива nums с содержимым регистра EAX и увеличиваем значение i на единицу. В итоге данная конструкция сработает 4 раза.
Стоит обратить внимание, что данный код срабатывает именно на этапе сборки, а не выполнения. И в итоге после сборки будет сгенерирован код:
.data nums dword 1, 2, 3, 4 .code i = 0 main proc xor rax, rax add eax, nums[0] ; константа i в качестве индекса add eax, nums[1] ; константа i в качестве индекса add eax, nums[2] ; константа i в качестве индекса add eax, nums[3] ; константа i в качестве индекса ret main endp end
Конструкция for имеют следующий синтаксис:
for идентификатор, <arg1, arg2, ..., argN> код endm
Циклическая конструкция for повторяет код один раз для каждого из аргументов - от arg1 до argN, которые указываются внутри угловых скобок <...>. При каждом повторении цикла текущий аргумент присваивается идентификатору: на первой итерации цикла идентификатору присваивается значение arg1, на второй итерации — arg2 и так далее до последней итерации, когда установлено значение argN. Например, следующий цикл for сгенерирует код, который помещает в стек регистры RAX, RBX, RCX и RDX:
for reg, <rax, rbx, rcx, rdx> push reg endm
Этот код фактически эквивалентен следующему коду:
push rax push rbx push rcx push rdx