Главная – flat assembler 1.66 Руководство программиста

flat assembler 1.66 Руководство программиста

См. также:
Официальное руководства программиста flat assembler (англ.)
Руководство к FASM на русском by Paranoik

Данный документ является переводом официального руководства программиста flat assembler. На русский язык преведена только часть документа, в основном, разделы, не вошедшие в перевод от Paranoik'а

2.2 Управляющие директивы (Control directives)

В данном разделе описываются директивы, которые управляют процессом ассемблирования. Они обрабатываются во время транслирования и определяют, как будет транслирован блок инструкций и будет ли он транслирован вообще.

2.2.1 Численные константы (Numerical constants)

Численные константы определяются с помощью директивы =. Сначала пишется имя константы, затем директива = и выражение, определяющее значение константы. Значением может быть число или адрес, но в отличие от меток, в численных константах нельзя использовать регистровую адресацию. В целом же численные константы ведут себя, так же как и метки. Вы даже можете обратиться к константе до того, как она была определена (forward-reference).

Hо есть и другой вид численных констант. Если определить константу с именем, которое уже использовалось ранее для определения численной константы, то ассемблер будет рассматривать данную константу как переменную времени транслирования (assembly-time variable). Такой переменной можно присваивать новые значения, но, по вполне понятной причине, на нее нельзя ссылаться до ее определения. Давайте рассмотрим два варианта численных констант в одном примере:

dd sum
x = 1
x = x+2
sum = x

Здесь x - переменная времени транслирования. Всякий раз при обращении к ней используется последнее присвоенное этой переменной значение. Если бы мы попытались использовать x до его определения, например, написав dd x вместо dd sum, это вызвало бы ошибку. Когда мы определяем x = x+2, предыдущее значение x используется для вычисления нового. Когда определяется константа sum, значение x равно 3. Это значение и присваивается sum. Так как константа sum определяется один раз, она является стандартной численной константой, и ее можно использовать до определения. Таким образом, dd sum ассемблируется как dd 3. Чтобы узнать больше см. 2.2.6

Значению численной константы может предшествовать оператор размера, гарантирующий, что значение находится в допустимом для заданного размера диапазоне. Оператор размера может также повлиять на некоторые вычисления с константами. Следующий пример определяет две разные константы: первую размером 8 бит, вторую - 32 бита

c8 = byte -1
c32 = dword -1

Если вам надо определить константу со значением адреса, вы можете использовать расширенный синтаксис директивы label (описывалась ранее в разделе 1.2.3). Hапример,

label myaddr at ebp+4

определяет метку по адресу ebp+4. Метки, в отличие от численных констант, могут определять адрес на основе регистров, но не могут становиться переменными времени транслирования.

2.2.2 Условное ассемблирование (Conditional assembly)

Директива if выделяет блок инструкций, который будет ассемблирован только при определенном условии. За директивой if должно следовать логическое выражение, определяющее это условие. Инструкции в следующих строках будут ассемблированы, только если выполняется условие, в противном случае они будут пропущены. Hеобязательная директива else if, за которой следует логическое выражение, определяющее дополнительное условие, начинает блок инструкций, который будет ассемблирован, если дополнительное условие выполняется, а все предыдущие - не выполняются. Hеобязательная директива else начинает блок инструкций, который будет ассемблирован, если ни одно условие не выполняется. Директива end if завершает последний блок инструкций.

Следует заметить, что директива if обрабатывается на этапе ассемблирования и поэтому не затрагивает директивы препроцессора, такие как определение символьных констант и макроинструкций. Когда ассемблер распознает директиву if, препроцессорная обработка уже завершена.

Логическое выражение состоит из логических значений и логических операторов. Логические операторы: ~ (логическое отрицание), & (логическое и), | (логическое или). Отрицание имеет наивысший приоритет. Логическим значением может быть численное выражение. Выражение расценивается как ложь, если оно равно 0. Любое значение, отличное от нуля, расценивается как истина. Два численных выражения можно сравнивать, используя следующие операторы:  = (равно), < (меньше), > (больше), <= (меньше либо равно), >= (больше либо равно), <> (не равно).

Оператор used, за которым следует символьное имя, проверяет, используется ли где-то указанное имя (имя может использоваться и после проверки). Оператор defined, за которым следует выражение, (обычно это одно символьное имя) проверяет, все ли имена в выражении определены в исходном тексте и доступны из текущей позиции. Следующий пример использует константу count, которая должна быть объявлена где-то в исходном коде:

if count>0
     mov cx,count
     rep movsb
end if

Две ассемблерные инструкции будут ассемблированы, только если значение константы count будет больше 0. Следующий пример показывает более сложную структуру условий:

if count & ~ count mod 4
     mov cx,count/4
     rep movsd
else if count>4
     mov cx,count/4
     rep movsd
     mov cx,count mod 4
     rep movsb
else
     mov cx,count
     rep movsb
end if

Первый блок инструкций будет ассемблирован, когда count не равно 0 и делится на 4. Если это условие не выполняется, тогда проверяется второе логическое выражение, которое следует за else if. Если оно истинно, ассемблируется второй блок инструкций. Если нет, тогда ассемблируется последний блок, который находится после строки else.

Существуют так же операторы, позволяющие сравнивать значения, представленные последовательностью символов. Оператор eq сравнивает два таких значения. Оператор in проверяет, находится ли заданное значение в заданном списке значений. Список следует за оператором и выделяется символами < и >. Члены списка разделяются запятыми. Символы считаются одинаковыми, когда они имеют одинаковое значение для ассемблера. Hапример, pword и fword для ассемблера - одно и то же, и, поэтому не различаются перечисленными выше операторами. Таким образом, 16 eq 10h - это истинное условие, a 16 eq 10 + 4 - нет.

Оператор eqtype проверяет, имеют ли два сравниваемых значения одинаковую структуру, и являются ли структурные элементы элементами одного типа. Различаемыми типами являются: численные выражения, отдельные заключенные в кавычки(individual quoted strings), числа с плавающей точкой, адресные выражения (выражения, заключенные в квадратные скобки или с предшествующим оператором ptr), мнемоники инструкций, регистры, операторы размера, jump type and code type operators. Специальные символы, играющие роль разделителей (например, запятая или двоеточие) представляют отдельный тип. Hапример, два выражения, каждое из которых состоит из имени регистра, за которым следует запятая и численное выражение, будут рассматриваться как выражения одного типа, независимо от назначения регистра и сложности численного выражения. Исключениями являются строки, заключенные в кавычки и числа с плавающей точкой. Они являются отдельным типом численных констант. Таким образом, условие eax,16 eqtype fs,3+7 истинно, а условие eax,16 eqtype eax,1.6 - ложно.

2.2.3 Повтрение блоков инструкций (Repeating blocks of instructions)

Директива times повторяет одну инструкцию заданное число раз. За директивой должны следовать численное выражение, определяющее число повторений, и сама инструкция. (Можно использовать двоеточие для разделения числа и инструкции). Если внутри инструкции используется специальный символ %, то он заменяется текущим номером повтора. Например, times 5 db % определит пять байт со значениями: 1, 2, 3, 4, 5. Директиву times можно использовать рекурсивно. Так, times 3 times % db %, определит шесть байт со значениями: 1, 1, 2, 1, 2, 3.

Директива repeat повторяет целый блок инструкций. За директивой должно следовать численное выражение, определяющее число повторений. Инструкции, подлежащие повтору, должны находиться в следующих строках. Блок инструкций завершается директивой end repeat. Пример:

    repeat 8
        mov byte [bx],%
        inc bx
    end repeat

Полученный код запишет 8 байт со значениями от одного до восьми по адресу, находящемуся в регистре bx.

Число повторений может быть и нулем, в таком случае, инструкции вообще не ассемблируются. Директива break позволяет остановить повтор раньше и продолжить ассемблирование, начиная с первой строки после end repeat. В сочетании с директивой if, break позволяет остановить повторение при определенном условии.

Например:

    s = x/2
    repeat 100
        if x/s = s
            break
        end if
        s = (s+x/s)/2
    end repeat

Директива while повторяет блок инструкций до тех пор, пока истинно условие в виде логического выражения, заданное после директивы. Блок инструкций завершается директивой end while. Перед каждым повторением проверяется логическое выражение. Если оно ложно, то ассемблирование продолжается со строки после end while. Как и для директивы repeat, символ % означает текущий номер повтора, а директива break останавливает повторение. Предыдущий пример может быть переписан с использованием while следующим образом:

    s = x/2
    while x/s <> s
        s = (s+x/s)/2
        if % = 100
            break
        end if
    end while

Блоки, определенные с помощью if, repeat и while, могут входить один в другой в любой последовательности, но должны быть закрыты в том порядке, в котором они были начаты. Директива break завершает обработку последнего блока, начатого с помощью директив repeat или while.


Если вы заметили какие-либо ошибки или неточности, пожалуйста, сообщите мне: