|
В этом подразделе мы подробно обсудим ассемблер/компоновщик as88, который вместе с трассером поставляется на сопроводительном компакт-диске и имеется также на веб-сайте, посвященном книге. Этот ассемблер, входящий в набор АСК (Amsterdam Compiler Kit), больше похож на ассемблеры UNIX, чем на аналогичные продукты для MS-DOS и Windows. Символом комментария в нем является знак восклицания (!). Все символы, следующие за знаком восклицания вплоть до конца строки, считаются комментарием и не влияют на объектный файл. Пустые строки допустимы, но при формировании объектного файла не учитываются.
В ассемблере имеются три секции, в которых хранятся транслируемый код и данные. Разделение на секции соответствует сегментации памяти. Первая секция, секция текста, предназначена для хранения команд процессора. Следующая секция, секция данных, служит для инициализации памяти в сегменте данных, который к началу процесса становится известен. Последняя секция, секция BSS (Block Started by Symbol - блок с начальным символом), нужна для резервирования памяти в неинициализированном (точнее говоря, в инициализированном нулем) сегменте данных. В каждой из трех секций есть собственный счетчик адресов. Секции задумывались для того, чтобы ассемблер мог сгенерировать несколько команд, затем перейти к данным, затем вернуться к командам, потом снова к данным, и т. д., а компоновщик, в свою очередь, мог скомпоновать все эти блоки так, чтобы все команды оказались вместе в текстовом сегменте, а все слова данных - в сегменте данных. Результат обработки любой отдельно взятой строки на языке ассемблера попадает только в одну из секций, хотя строки кода и строки данных могут чередоваться. В период выполнения секция текста хранится в текстовом сегменте, а секции данных и BSS - последовательно в сегменте данных.
Как команда, так и слово данных в программе на языке ассемблера может начинаться с метки. Метка также может быть единственным содержанием строки, и в этом случае она считается относящейся к следующей команде или слову данных. Пример:
CMP АХ,ABC JE L
MOV AX.XYZ
L:
Здесь L - метка, связанная со следующей командой или словом. Метки бывают двух видов. Во-первых, существуют глобальные метки, представляющие собой буквенно-цифровые идентификаторы, после которых ставится двоеточие (:). Такие метки должны быть уникальными; они не могут совпадать с ключевыми словами и мнемоническими кодами команд. Во-вторых, в секции текста встречаются локальные метки, каждая из которых состоит из одной цифры с последующим двоеточием (:). Локальная метка может устанавливаться многократно. Например:
JE 2f
Эта команда означает операцию перехода JUMP EQUAL вперед до следующей локальной метки 2. Аналогично:
jne 4Ь
Эта команда означает операцию перехода JUMP NOT EQUAL назад к ближайшей локальной метке 4.
Ассемблер допускает присвоение константам символических имен в рамках синтаксической конструкции идентификатор = выражение
Здесь идентификатор является буквенно-цифровой строкой, как в следующем примере:
BLOCKSIZE = 1024
Во всех идентификаторах в рассматриваемом языке ассемблера значимыми являются только первые восемь символов. Таким образом, идентификаторы BLOCKSIZE, BLOCKSIZZ и BL0CKSIZ идентичны. Выражения могут состоять из констант, численных значений и операторов. Поскольку численные значения меток становятся известными к завершению первого прохода, они приравниваются к константам.
Численные значения могут быть восьмеричными (в таком случае они начинаются с нуля), десятеричными или шестнадцатеричными (начинаются с символов ОХ или Ох). В шестнадцатеричном представлении буквы а-£ и А-Б обозначают значения от 10 до 15. Целочисленные операторы +,-,*,/ и % выражают сложение, вычитание, умножение, деление и остаток о деления, соответственно. Логические операторы &, * и ~ обозначают поразрядное И, поразрядное ИЛИ и логическое отрицание (НЕ), соответственно. Для группировки в выражениях могут устанавливаться квадратные скобки. Во избежание путаницы круглые скобки в выражениях не используются (оставлены для задания режимов адресации).
К меткам в составе выражений следует относиться с осторожностью. Вычитание меток команд из меток данных недопустимо. Разность между однородными метками выражается в численных значениях, однако ни сами метки, ни их разности не могут выступать в качестве констант в мультипликативных и логических выражениях. Выражения, разрешенные к применению в определениях констант, могут быть задействованы в виде констант в командах процессора. В некоторых процессорах предусмотрены макросредства, позволяющие группировать множества команд и присваивать таким группам имена, но в аэ88 этой возможности нет.
В каждом языке ассемблера есть директивы, которые влияют на процесс ассемблирования, но не транслируются в двоичный код. Они называются псевдокомандами. Псевдокоманды ассемблера аэ88 перечислены в табл. В.5.
Таблица В.5. Псевдокоманды ассемблера ав88
Псевдокоманда Описание
|
.SECT .TEXT
|
Ассемблирование следующих строк в секции текста
|
|
.SECT.DATA
|
Ассемблирование следующих строк в секции данных
|
|
.SECT .BSS
|
Ассемблирование следующих строк в секции BSS
|
|
.BYTE
|
Ассемблирование аргументов в виде последовательности байтов
|
|
.WORD
|
Ассемблирование аргументов в виде последовательности слов
|
|
.LONG
|
Ассемблирование аргументов в виде последовательности длинных слов
|
|
.ASCII "str"
|
Сохранение строки str в виде ASCII-строки без завершающего нулевого
|
|
|
байта
|
|
.ASCIZ "str"
|
Сохранение строки str в виде ASCII-строки с завершающим нулевым
|
|
|
байтом
|
|
.SPACE n
|
Продвижение счетчика адресов на п позиций
|
|
.ALIGN n
|
Продвижение счетчика адресов до n-байтной границы
|
|
.EXTERN
|
Объявление идентификатора внешним
|
Псевдокоманды из первого блока формируют секцию, в которой все последующие строки обрабатываются ассемблером. Как правило, определение такой секции размещается на отдельной строке в произвольной части кода. По соображениям реализации первой должна быть секция текста, затем - секции данных и BBS. После этих исходных ссылок секции могут следовать в произвольном порядке. Помимо прочего, в первой строке секции должна быть установлена глобальная метка. Иных ограничений на порядок следования секций не существует.
Во втором блоке псевдокоманд содержатся указатели типов данных в сегменте данных. Таких типов всего четыре: .BYTE, .WORD, .LONG и строка. В первых трех типах после необязательной метки и ключевого слова псевдокоманды остаток строки занимает список константных выражений с разделением запятыми. Для строк предусмотрено два ключевых слова: ASCII и ASCIZ. Единственное различие между ними заключается в том, что ключевое слово ASCIZ добавляет к концу строки нулевой байт. Оба ключевых слова в обязательном порядке сопровождаются строкой, заключенной в двойные кавычки. В определениях строк допускается ряд символов-заменителей, которые перечислены в табл. В.6. Вдобавок к ним любой конкретный символ может предваряться обратной косой чертой и выражаться своим восьмеричным представлением, например, \377 (максимальное число символов - три, 0 в данном случае указывать не требуется).
Таблица В.6. Некоторые разрешенные в as88 символы-заменители
Символ-заменитель Описание
|
\п
|
Новая строка (перевод строки)
|
|
\t
|
Табуляция
|
|
\\
|
Обратная косая черта
|
|
\ь
|
Пробел
|
|
V
|
Подача страницы
|
|
V
|
Возврат каретки
|
|
V
|
Двойная кавычка
|
Псевдокоманда SPACE увеличивает значение указателя адресов на число байтов, определенное аргументами. Это ключевое слово может быть особенно полезным, если установить его после метки в секции BSS в целях резервирования памяти для переменной. Ключевое слово ALIGN позволяет продвинуть указатель адресов до первой 2-, 4- или 8-байтной границы в памяти, что упрощает ассемблирование слов, двойных слов и т. д. с размещением в подходящих ячейках памяти. Наконец, ключевое слово EXTERN объявляет о доступности указанной программы или ячейки памяти для компоновщика с целью установки внешних ссылок. Определение не обязательно должно находиться в текущем файле; оно может быть в любом месте в пределах досягаемости компоновщика.
Следует сделать ряд замечаний касательно совместного применения ассемблера и трассера. Ассемблер воспринимает ключевые слова как в верхнем, так и в нижнем регистрах; трассер выводит их только в верхнем регистре. Ассемблер воспринимает в качестве символа новой строки символы-заменители \г (возврат каретки) и \п (перевод строки), в то время как трассер использует только последний. Ассемблер способен работать с программами, разбитыми на несколько файлов, в то время как для обработки в трассере всю программу необходимо объединить в файл с расширением .$. Включенные в него файлы запрашиваются командой
#include имя_файла
Включаемый файл в таком случае также должен находиться на указанной позиции в рамках единого $-файла. Ассемблер проверяет, была ли ранее проведена обработка данного включаемого файла, и загружает одну его копию. Эта возможность особенно полезна в тех случаях, когда один заголовочный файл является общим для нескольких файлов. В такой ситуации в объединенный исходный файл включается только одна его копия. Для включения файла команда ^include должна быть первым маркером строки без предшествующих разделителей, а путь к файлу должен быть заключен в двойные кавычки.
При наличии одного исходного файла (например, pr.s) предполагается, что именем проекта являются символы рг, а объединенный файл должен называться рг.$. Если исходных файлов несколько, основа имени первого из них принимается за имя проекта, и она же применяется для определения $-файла, который генерируется ассемблером путем объединения исходных файлов. Этот механизм можно изменить, поместив в командной строке перед первым исходным файлом флаг -о projname; в таком случае объединенный файл получает имя projname.$.
Имейте в виду, что к применению включаемых файлов и нескольких исходных файлов выдвигается ряд условий. В частности, во всех исходных файлах имена меток, переменных и констант должны быть разными. Более того, в конечном счете, в загрузочный файл ассемблируется файл projname.$, поэтому номера строк, указываемые ассемблером при обнаружении ошибок и выводе предупреждений, отсчитываются именно от этого файла. При работе с небольшими проектами имеет смысл писать программу в одном файле, а не использовать команду ^include.
⇐Введение-a || Оглавление || Некоторые отличия от других ассемблеров 8088⇒
|