double arrow

Второй проход двухпроходного ассемблера

Обычно второй проход ассемблера читает ИМ с самого начала и частично повторяет действия первого прохода: лексический разбор оператора, распознавание команд и директив, подсчет адресов.

В современных ВС ассемблер создает промежуточный файл – результат первого прохода, который является входом для второго прохода. Каждому оператору ИМ соответствует по одной записи промежуточного файла.

Ассемблер на втором проходе использует только первые четыре поля записи, так как текст исходного оператора необходим только для печати листинга.

Первое поле позволяет исключить строки, целиком состоящие из комментария. Второе поле позволяет избежать подсчета адресов. Третье – поиска мнемоники в таблицах. Основная работа второго прохода состоит в разборе поля операндов и генерации объектного кода. Объектный код команды состоит из поля кода операции и одного или нескольких операндов. Код операции имеет размер 1 байт, а количество и формат полей операндов определяется для каждого типа команд данной аппаратной платформы. Операндом команды может быть: регистр, непосредственный операнд, адресное выражение. Виды адресных выражений зависят от способа адресации ВС.

Типовые способы операции:

1) Абсолютный адрес

2) [Базовый регистр] + смещение

3) [Базовый регистр] + [индексный регистр] + смещение

4) Имя + смещение

5) Литерал

[] означают содержимое того, что взято в скобки.

Адресное выражение может содержать арифметические операции, касающиеся адресной арифметики, те же, что и в адресной арифметике языка C (арифметика указателей). Имена в адресных выражениях должны заменяться значениями. Замена абсолютных имен (определенных в директиве EQU) – значение имени из таблицы символов подставляется вместо имени. Перемещаемые имена превращаются ассемблером в адресное выражение вида [Базовый регистр] + смещение.

В таблице символов значения этих имен определены, как смещение соответствующих ячеек памяти относительно начала программы. При трансляции имен необходимо, чтобы:

1. ассемблер знал, какой регистр он должен использовать в качестве базового.

2. Ассемблер знал, какое значение содержится в базовом регистре.

3. В базовом регистре действительно должно содержаться это значение.

Первые два требования обеспечиваются директивами. Третье – машинными командами.

Эти требования по-разному реализуются в разных ВС (Intel и RISC-архитектурах).

В Intel ассемблер использует в качестве базовых сегментные регистры: DS - при трансляции имен, CS - при трансляции меток. Для простой программы, состоящей из одной секции, загрузчик перед выполнением заносит во все сегментные регистры сегментный адрес начала программы и ассемблер считает все смещения относительно него. Сложная программа может состоять из нескольких секций и в сегментном регистре может содержаться адрес той или иной секции. Причем содержимое сегментного регистра может меняться по ходу выполнения программы. Загрузка в сегментный регистр адреса секции выполняется машинными командами:

MOV AX, секция

MOV сегментный_регистр, AX

Для того, чтобы ассемблер знал, что адрес секции находится в сегментном регистре применяется директива:

Assume сегментный_регистр:секция

При трансляции имен ассемблер превращает имена в адресные выражения вида:

[сегментный регистр]+смещение в секции

Отмена использования сегментного регистра в качестве базового задается директивой:

ASSUME сегментный_регистр:NOTHING

При трансляции команды mov AX, секция в поле операнда заносится относительный адрес секции. При выполнении должен быть ее абсолютный адрес, поэтому поля операндов таких типов обязательно модифицируются загрузчиком после размещения программы в оперативной памяти.

Более гибкой системой базовой адресации является относительная базовая общая адресация, применяемая на RISC-архитектурах (S/360, S/370, S/390). В качестве базового может быть использован любой РОН. Директива

USING относительный адрес, регистр

сообщает ассемблеру, что он может использовать указанный регистр в качестве базового и в данном регистре содержится адрес – первый операнд.

Чаще всего относительный адрес кодируется символом * (обозначение текущего значения счетчика адреса). Это означает, что в регистре содержится адрес первой команды, следующей за директивой Using. Занесение адреса в базовый регистр выполняется машинной командой BALR. Обычный контекст определения базового регистра:

BALR регистр,0

USING *,регистр

С такими операндами команда BALR заносит в регистр адрес следующей за собой команды. Зная смещение именованной ячейки относительно начала программы и смещение относительно начала программы содержимого базового регистра, ассемблер вычисляет смещение именованной ячейки относительно содержимого базового регистра.

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

Директива DROP регистр отменяет использование регистра в качестве базового. В качестве базовых могут быть назначены несколько регистров. Ассемблер сам выбирает, какой из них использовать в каждом случае.

Информация о базовом регистре и его содержимое хранится в таблице базовых регистров, содержащей строки для всех регистров, которые могут быть базовыми и признак «используется ли регистр в качестве базового».

Рассмотрим алгоритм выполнения второго прохода 2-проходного ассемблера, исходя из того, что второй проход использует промежуточный файл, сформированный первым проходом.

ORG – директива установки адреса. Операндом директивы является числовая константа или выражение, вычисляемое при ассемблировании. Ассемблер считает, что первая ячейка обрабатываемой им программы располагается по адресу 0. Директива ORG устанавливает счетчика адресов программы в значение, определяемое операндом. При создании программ для MS-DOS программа начинается с директивы ORG 100h. Этим оператором резервируется 256 байт в начале программы.

START/SECT – директива начала модуля, начала программной секции. Операндов директив является имя секции. Этой директивой устанавливается в 0 счетчик адресов программы. Программа может состоять из нескольких программных секций, в каждой секции счет адресов ведется от 0. При обработке этой директивы на первом проходе ассемблер создает таблицу программных секций.

На первом проходе ассемблер составляет список секций и только в конце первого прохода определяет их длины и относительные адреса программы. На втором проходе ассемблер использует таблицу секций при трансляции адресов.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: