Условная компиляция и циклы

Последнее обновление: 03.07.2023

Ассемблер 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 имеют следующий синтаксис:

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
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850