[an error occurred while processing this directive]

I.3.2 Дополнительные стандартные модули "Системы"

I.3.2.1 RELMODUL.ASM

Модуль настройки перемещаемых файлов. Был написан специально для работы в составе драйверов расширения возможностей интерпретатора "Бейсик", но может использоваться для работы в комплексе с любым перемещаемым файлом в среде DOS 3.3. Поддерживает работу только с перемещаемыми файлами, созданными в Ассемблере ДОК. Для того, чтобы объяснить алгоритм его работы, необходимо рассмотреть структуру перемещаемого файла и принцип его настройки на абсолютные адреса.

Как известно, обычная объектная (двоичная) программа (в DOS 3.3 это файлы типа "К" и "В") - это любая последовательность байтов, то есть информация, рассматриваимая как содержимое непрерывного участка машинной памяти. Это может быть, как программа в машинных кодах, так и любая другая (например, графическая) информация, а также любая их смесь. Абсолютная объектная программа считается связанной с определенным участком оперативной памяти. Она корректна только при размещении с некоторого начального адреса. Эта связь возникает, когда в объектной программе содержатся абсолютные адреса ее частей (например, в командах абсолютного перехода). При загрузке такой программы с другого стартового адреса ссылки внутри нее нарушаются.

Перемещаемая объектная программа (в DOS 3.3 это файлы имеющие тип "R" или "П") не зависит от места ее размещения в памяти. Она либо не содержит абсолютных ссылок внутрь себя (например, графическая информация), либо содержит дополнительную информацию, позволяющую при размещении программы с конкретного адреса выполнить их пересчет (настройку). DOS 3.3 не обладает возможностю работы с перемещаемыми файлами. Однако преимущества их использования значительны и очевидны. Пользуясь перемещаемыми программами, не пришлось бы задумываться о привязке их к конкретным адресам, так как можно расположить их с любого адреса, где имеется свободная память. Особенно выгодно использовать принцип перемещаемых файлов при создании драйверов системы расширения возможностей интерпретатора "Бейсик". Это позволяет программисту не только располагать драйвер в той зоне памяти, в которой ему удобно, но и пользоваться одновременно несколькими драйверами, загруженными в ОП с различных стартовых адресов и взаимодействующих через систему "Диспетчер". Итак, перемещаемый файл автоматически создается Ассемблером ДОК при ассемблировании исходного текста программы, имеющей в своем теле псевдокоманду Ассемблера "REL". При этом в объектный код программы кроме ее непосредственного машинного кода включается таблица перемещения (та дополнительная информация, которая необходима для настройки программы в произвольную зону памяти), содержащая в особом формате ссылки на абсолютные адреса внутри кодовой части, подлежащие пересчету.

Ниже приводится описание формата перемещаемого файла:

.цв

ФОРМАТ ПЕРЕМЕЩАЕМЫХ ФАЙЛОВ

.лв

══════════════╦══════════════════════════════════════════════
 Байты файла  |                  Значение
══════════════╬══════════════════════════════════════════════
              |
1. ТАБЛИЦА ЗАГРУЗКИ ПЕРЕМЕЩАЕМОГО ФАЙЛА
              |
              |
0-1           |адрес, заданный в ORG (начальный адрес), A
2-3           |общая длина файла, L
4-5           |длина кодовой части - 3, K - 3
              |
2. КОДОВАЯ ЧАСТЬ ФАЙЛА
              |
6...6+K-1     |кодовая часть
              |
3. ТАБЛИЦА ПЕРЕМЕЩЕНИЯ
   (состоит из 4-байтных полей перемещения и оканчивается
    нулевым полем)
              |
6+K ...       |таблица перемещения
              |
ФОРМАТ ТАБЛИЦЫ ПЕРЕМЕЩЕНИЯ
              |
1-й байт  -   |атрибут метки:
              |¤81 - адрес трехбайтовой команды (МЛ/СТ)
              |¤21 - прямой адрес, задаваемый DDB (СТ/МЛ)1
              |¤41 - адрес двубайтовой команды, старший байт
              |¤01 - адрес двубайтовой команды, младший байт
2-3 байты -   |смещение метки от начала кодовой части
4-й байт  -   |дополнительный байт (младший)
              |для полного адреса (для ¤41 атрибута)
              |
*1-в Ассемблере ДОК не реализовано из-за ошибки разработчиков
              |
4. ТАБЛИЦА ГЛОБАЛЬНЫХ МЕТОК
              |
...-...       |таблица глобальных меток.
              |
              |
Таблица создается только для программ, имеющих в теле исходного текста псевдокоманды EXTRN/ENTRY Ассемблера. Служит для связи отдельно подготовленных объектных программ при компоновке.
              |
══════════════╩══════════════════════════════════════════════

Какие же адреса программы требуют пересчета? Во-первых, это все, не являющиеся константами адреса трехбайтовых команд (например таких, как JMP XXYY, JSR XXYY, LDA XXYY, STA XXYY, CMP XXYY, BIT XXYY и.т.д...); во-вторых, это двухбайтовые команды, оперирующие данными тела самой программы и некоторые адреса, устанавливаемые псевдокомандами Ассемблера DW и DFB.

Например, в программе:

      LDX #SIT
      STX MOV+1
      LDA #<ADR
      PHA
      LDA #>ADR
      PHA
      RTS

ASER  LDA ¤C000
      BPL ASER
      STY ¤C010
MOV   LDX #¤00
SIT   RTS

DW    ASER-1
DFB   <MOV

перемещения требуют операнды команд STX MOV+1 (трехбайтовая команда с адресом операнда - меткой тела программы), LDX #SIT (так как младший байт метки SIT изменит свое значение при переносе программы на другие адреса), а также операнды команд LDA #<ADR и LDA #>ADR по той-же причине. Потребуют пересчета также, адрес, устанавливаемый псевдокомандой DW и байт, устанавливаемый командой DFB, так как они содержат адреса меток программы, которые также изменятся при перемещении. Если адреса заданы константами (например в команде LDA ¤C000) или метками-константами, определенными ранее с помощью псевдокоманды EQU, то они считаются неперемещаемыми адресами, и данные о них в таблицу перемещения не заносятся.

Примечание:

К сожалению, по вине разработчиков языка "Ассемблер", нельзя использовать в исходном тексте будущей перемещаемой программы псевдокоманды Ассемблера DDB метка (где "метка" - метка подпрограммы тела команды), т.к. Ассемблер не делает никаких различий в формате при записи соответствующей информации о перемещаемом адресе в командах DW и DDB. То есть, формат хранения их адресов в таблице перемещения одинаков. Использование "DDB метка" приведет к неправильному пересчету адреса новой "метки" настройщиком, что, естественно, отразится на работе программы. В сущности, это не так страшно, так как команду "DDB метка" всегда можно заменить в исходном тексте парой команд "DFB<метка", "DFB>метка". Использование констант в теле DDB (например, DDB ¤C000) разрешается.

Алгоритм работы самого настройщика перемещаемых файлов довольно сложен. Суть его заключается в определении точного адреса местоположения программы в памяти (путем выполнения команды "JSR" на системную точку и выталкивания адреса возврата из стека) и дальнейшего поиска адресов, подлежащих пересчету (согласно данным таблицы перемещения), вычислению их новых значений и соответствующей замены.

Далее приводится подробное описание алгорирма модуля настройки перемещаемых файлов. Исходный текст модуля см. в Приложении 5 к Разделу I.

Алгоритм настройки перемещаемых файлов; использующихся в модуле RELMODL2.ASM.

1) Установить текущий адрес с помощью обращения к какой-либо незначащей подпрограмме среды ДОС 3.3 или Бейсик командой "JSR" с извлечением адреса возврата из стека по указателю S:

    JSR SYSTEM
    TSX
    LDA ¤100,X    ML
    DEX
    LDA ¤100,X    ST

2) Вычислить физический адрес начала перемещаемого фала (адрес начала его таблицы загрузки) для чего прибавить к адресу, извлеченному из стека константу-длину кода модуля RELMODL2.ASM от точки TSX.

Сохранить полученный адрес в ячейках RADR и RADR+1.

3) Установить логический адрес запуска кодовой части перемещаемого файла ORGADR. Он находится в 0-1 байтах таблицы загрузки перемещаемого файла, адрес которой вычислен в пункте 2.

Сохранить логический адрес в ячейках LIR и LIR+1.

4) Вычислить физический адрес запуска рабочей программы (физический адрес начала кодовой части). Для этого следует к физическому адресу начала перемещаемого файла (хранится в RADR и RADR+1) прибавить длину таблицы загрузки перемещаемого файла (равна 6 байтам). Полученный адрес сохранить в ячейках NAS и NAS+1 нулевой страницы.

5) Вычислить физический адрес начала таблицы перемещения. Для этого сложить физический адрес начала кодовой части (хранится в NAS и NAS+1) с длиной кодовой части, уменьшенной на 3 (хранится в 4-5 байтах таблицы загрузки перемещаемого файла (адрес ее начала имеется в RADR и RADR+1)) и прибавить константу "4". Полученный адрес сохранить в ячейках ADR и ADR+1 нулевой страницы.

6) Пересчет команд и адресов псевдокоманд, заданных Ассемблером.

- используется пересчет адресов трехбайтовых команд (их операндов) и адресов, заданных псевдокомандой DW (атрибут ¤81 в таблице перемещения)

- используется пересчет прямых адресов формата старший/младший, задаваемых псевдокомандой DDB (атрибут ¤21; только для Ассемблера Громова С.; исходные тексты для Ассемблера ДОК ИКП-1 не должны иметь псевдокоманд DDB, иначе настройка будет произведена неправильно.

- используется пересчет двухбайтовых команд и полуадресов, заданных псевдокомандой DFB (как младших - атрибут ¤01; так и старших - атрибут ¤41)

* Алгоритм пересчета

6.A. Начиная с начала таблицы перемещения (в ADR и ADR+1) взять смещение операнда первой пересчитываемой команды (2-3 байты поля перемещения)

6.B. Прибавить к нему физический адрес начала кодовой части (храниться в ячейках NAS и NAS+1) для получения физического адреса младшего байта операнда смещаемой команды.

Сохранить полученный адрес в ячейках HRAN и HRAN+1.

6.C. Установить физический адрес старшего байта операнда смещаемой команды (этот адрес на 1 больше адреса его младшего байта, то есть адреса, хранимого в HRAN и HRAN+1; сохранить его в HRAN1 и HRAN1+1)

6.D. Установить атрибут пересчитываемого операнда (1й байт поля перемещения). От его значения зависит дальнейший алгоритм.

6.D.1. Трехбайтовый пересчет (атрибут ¤81)

- Считать байты, хранимые по адресам, лежащим в HRAN, HRAN+1, HRAN1 и HRAN1+1 и из них образовать логический адрес-операнд перемещаемой команды

- Вычесть из этого адреса логический адрес запуска кодовой части (хранится в LIR и LIR+1) для получения смещения логического адреса операнда смещаемой команды относительно логического начала кодовой части.

Поместить смещение в ячейки KOM и KOM+1 с физическим адресом начала кодовой части (имеется в NAS и NAS+1) для получения нового адреса-операнда перемещаемой команды

- Записать полученный адрес-операнд по его физическим адресам (HRAN и HRAN+1 - младший полуадрес; HRAN1 и HRAN1+1 - старший полуадрес)

Перейти к пункту 7.

6.D.2. Трехбайтовый пересчет (атрибут ¤21)

- Считать байты, хранимые по адресам HRAN, HRAN+1 (старший) и HRAN1, HRAN1+1 (младший) полубайты операнда смещаемого прямого адреса (формат старший/младший)

- Повторить шаги, аналогичные пункту 6.D.1

- "Перевернуть" полученный адрес-операнд и так же занести его по его новым физическим адресам (аналогично 6.D.1)

Перейти к пункту 7.

6.D.3. Двухбайтовый пересчет (атрибут ¤41)

- Считать байт, хранимый по адресу, лежащему в HRAN и HRAN+1 (старший логический полуадрес-операнд перемещаемой команды) и байт, хранимый в 4-м байте поля перемещения таблицы перемещения (младший его полуадрес). Из них образовать логический адрес-операнд перемещаемой команды

- Повторить шаги, аналогичные пункту 6.D.1

- Записать старший байт полученного адреса-операнда по его физическому адресу (хранится в HRAN HRAN+1)

Перейти к пункту 7.

6.D.4 Двухбайтовый пересчет (атрибут ¤01)

- Считать байт, хранимый по адресу, лежащему в HRAN и HRAN1 (младший логический полуадрес-опернд перемещаемой команды)

- Вычесть из него младший байт логического адреса начала кодовой части (LIR)

- Полученный результат сложить с младшим физическим полуадресом начала кодовой части (NAS)

- Записать полученный (младший) полуадрес в тело операнда смещаемой команды (физический адрес операнда имеется в HRAN и HRAN+1)

Перейти к пункту 7.

7) Перейти к следующему полю перемещения и повторить действия с пункта 6 до ее исчерпания (признаком исчерпания таблицы перемещения служит нулевой атрибут очередного поля перемещения).

8) По исчерпанию таблицы перемещения передать управление на начало кодовой части (по адресу, хранимому в NAS и NAS+1).

При использовании настройщика для создания перемещаемых драйверов процедур обычно не приходится пользоваться исходным текстом модуля RELMODUL.ASM. Для этого достаточно воспользоваться файлом, содержащим его объектный код RELOCAT1.BIN. Для создания перемещаемой программы, готовой к запуску в среде DOS 3.3 следует файл RELOCAT1.BIN соединить с подготовленным перемещаемым драйвером (R-файлом). Причем, машинный код файла RELOCAT1.BIN, естественно, должен располагаться перед кодом самого драйвера. После записи совмещенный файл (типа B или K) готов к запуску. При загрузке в ОП, настройщик, получив управление, осуществит необходимую настройку драйвера на абсолютные адреса загрузки и передает управление на его начало (как правило, это объектный код установщика драйвера в память модуля SETDRMOD.ASM). После настройки объектный код настройщика (занимает ¤C9 байт) и таблица перемещения драйвера могут быть утеряны в памяти (составляющие используемых зон; см. описание стандарта 1.08.94 в Приложении 2.

I.3.2.2 ERRORMOD.ASM

Модуль ERRORMOD.ASM является дополнительным модулем "Системы", включаемым в процесс сборки драйвера только по необходимости. Такой необходимостью является наличие в драйвере команд, требующих специальной подпрограммы обработки ошибок. Как правило, это команды, в которых требуется обрабатывать ошибочные ситуации и выдавать соощения об ошибках отличные от ошибок, которые способен обрабатывать интерпретатор "Бейсик". (Это могут быть сообщения об ошибках DOS или другие ошибки с произвольными диагностиками).

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

LDX  #8
LDA  #<ERR1
LDY  #>ERR1
JSR  DCERR
JMP  DCEXIT
ERR1 DCI "Ошибка обмена"

При обращении к подпрограмме обработки ошибок в регистре X следует передать код ошибки (байт в диапазоне 00-FF), который будет записан в ячейку ERRCOD интерпретатора "Бейсик" (¤DE) если включена обработка ошибок "Бейсика" по команде ONERR GOTO [Теоретически, Вы можете использовать любой код в качестве кода ошибки, однако, предпочтительно соблюдать совместимость с совпадающими по смыслу кодами ошибок DOS (если таковые имеются) или подробно описывать используемые коды обработки ошибок в документации вашего драйвера]. В регистрах A и Y (соответственно страший/младший) следует передать адрес, по которому будет храниться текст сообщения об ошибке. Причем текст должен храниться в формате псевдокоманды ассемблера DCI (то есть у всех символов текста (кроме последнего) старший бит сброшен). Длина текста не должна превышать 255 символов. В примере (см. выше) "ОШИБКА ОБМЕНА" имеет, как известно, код 8 (по таблице кодов ошибок DOS).

Примечание:

Для драйверов, работающих в дополнительных банках основного ОЗУ, подпрограмма DCEXIT должна быть вынесена в норм. ОЗУ и перед обращением к ней следует отключить банк с объектным кодом драйвера (как это реализовано, например, в драйвере DIR 4.06.EXE).

.ст Раздел I:4.1

[an error occurred while processing this directive]