Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Финогенов-основы_языка_ассемблера.doc
Скачиваний:
26
Добавлен:
17.09.2019
Размер:
3.35 Mб
Скачать

Глава 3

Команды и алгоритмы^

119

;Функция «завершить и ;оставить в памяти»

AX,3100Ii 21h

ти, так как он известен DOS. Для определения размера резидентной сек­ции ее можно завершить предложением вида

ressize=S-main

где main — смещение начала программы, а при вызове функции 31h в регистр DX заслать результат вычисления выражения (ressize+10Fli)/16.

Разность S — main представляет собой размер главной процедуры. Од­нако перед главной процедурой размещается префикс программы, имею­щий размер lOOh байт, который тоже надо оставить в памяти. Далее, при целочисленном делении отбрасывается остаток, т.е. происходит округле­ние результата в сторону уменьшения. Для компенсации этого дефекта можно прибавить к делимому число 15 = FU. Деление всего этого выраже­ния на 16 даст требуемый размер резидентной части программы в пара­графах (возможно, с небольшим кусочком секции инициализации вели­чиной до 15 байт).

Функция 31h, закрепив за резидентной программой необходимую для ее функционирования память, передает управление командному процес­сору COMMAND.COM, и вычислительная система переходит, таким об­разом, в исходное состояние. Наличие программы, резидентной в памя­ти, никак не отражается на ходе вычислительного процесса за исключе­нием того, что уменьшается объем свободной памяти. Одновременно может быть загружено несколько резидентных программ.

Для того, чтобы активизировать резидентную профамму, ей надо как-то передать управление и, возможно, параметры. Как правило, активиза­ция резидентной программы осуществляется с помощью механизма пре­рываний.

Кроме того, специально для взаимодействия с резидентными про­граммами в DOS предусмотрено мультиплексное прерывание 2Fli.

Рассмотрим типичную структуру резидентной программы и систем­ные средства оставления ее в памяти. Как уже отмечалось, резидентные программы чаще всего пишутся в формате .СОМ:

code segment

assume CS:text,DS:text - <

org lOOh -

jmp init entry:

iret

main endp ressize=S - my proc init proc

main proc

; Переход на секцию инициализации ;Данные резидентной секции программы ;Точка входа при активизации ;Текст резидентной секции программы ,

;Размер (в байтах) резидентной секции •; ;Секция инициализации ?.

mov DX,(ressize+10Fh)/16 ;Размер в параграфах

mov

int

init endp code ends

end main

При первом запуске программы с клавиатуры управление передается на начало процедуры main (первый байт после префикса программы). Командой jmp осуществляется переход на секцию инициализации, в ко­торой, в частности, подготавливаются условия для дальнейшей активиза­ции программы уже в резидентном состоянии. Последними строками сек­ции инициализации вызывается функция 31h, которая выполняет завер­шение программы с оставлением в памяти указанной ее части. С целью экономии памяти секция инициализации располагается в конце программы и отбрасывается при ее завершении.

Содержательная часть резидентной программы, начинающаяся с мет­ки entry, активизируется, как уже отмечалось выше, с помощью аппарат­ного или программного прерывания и заканчивается командой iret. На рис. 3.7 приведена типичная структура резидентной программы.

PSP

mam proc jmp init

Резидентные данные

Точка входа при —^ загрузке

entry:

Резидентная часть программы

~>

Точка входа при активизации

Резидентные команды

main endp

init proc

Часть программы, отбрасываемая после установки в памяти

Секция инициализации

movAH.31h int 21h init endp

end main Рис. 3,7. Структура резидентной программы.

Как видно из рис. 3.7, резидентная программа имеет по крайней мере две точки входа. После загрузки программы в память командой оператора, вводимой на командной строке, управление передается в точку, указанную в поле завершающего текст программы оператора end (на рисунке — нача­ло процедуры main). Для программ типа .СОМ эта точка входа должна соот­ветствовать самой первой строке программы, идущей вслед за префиксом программы. Поскольку при загрузке программы должна выполниться ее

120

121

Глава 3

установка в памяти, первой командой программы всегда является команда перехода на секцию инициализации и установки (jmp init на рисунке).

После установки в памяти резидентная программа остается пассив­ной и никак не проявляет своего существования, пока не будет активизи­рована предусмотренным в ней для этого способом. Эта, вторая точка вызова обозначена на рисунке меткой entry.

К сожалению, резидентные программы, выполняющие полезную ра­боту, оказываются довольно сложными. Мы же в качестве примера можем рассмотреть только совсем простую резидентную программу, в принципе правильную и работоспособную, но не претендующую на практическую ценность. Программа активизируется прерыванием от клавиши Print Screen и выводит на экран содержимое сегментного регистра CS, что позволяет определить ее положение в памяти.

Как известно, клавиша Print Screen в DOS выполняет печать содер­жимого экрана на принтере. Каков механизм этой операции1 При нажатии на любую клавишу клавиатуры возникает сигнал прерывания, иницииру­ющий активизацию обработчика прерываний от клавиатуры, находяще­гося в ПЗУ BIOS. При нажатии на алфавитно-цифровые и некоторые дру­гие клавиши (например, функциональные клавиши <F1>...F<12>) обра­ботчик сохраняет в определенном месте памяти код нажатой клавиши и завершается. Текущая программа может с помощью соответствующих фун­кций DOS или BIOS извлечь этот код и использовать его в своих целях. Если же пользователь нажимает на клавишу Print Screen, то обработчик прерываний, в числе прочих действий, выполняет команду hit 5, переда­вая упраштсние через вектор 5 на обработчик этого программного преры­вания, который тоже располагается в ПЗУ BIOS. Задача обработчика пре­рывания 5 заключается в чтении содержимого видеобуфера и выводе его на устройство печати.

Таким образом, если мы напишем собственный обработчик прерыва­ния и поместим его адрес в вектор с номером 5, он будет активизиро­ваться нажатием клавиши Print Screen. Обратите внимание на то обстоя­тельство, что прерывание 5 является прерыванием программным; оно возбуждается командой hit 5 и не имеет отношения к контроллеру преры­ваний. Однако активизируется это прерывание не командой hit в приклад­ной программе, а нажатием клавиши, т.е., фактически, аппаратным пре­рыванием.

Перехват прерывания 5 осуществляется значительно проще, через пе­рехват «истинного» аппаратного прерывания от клавиш клавиатуры, из-за чего мы и воспользовались им в нашем примере.

Пример 3-4. Резидентная программа с обработчиком прерывания 05h code segment

assume CS:text

org lOOh main proc

jmp mil ;Переход на секцию инициализации

каанды и алгоритмы

new__05:

push AX

;Сохраним регистры АХ и ВХ,

push

BX

;используемые далее

mov

BX,CS

;ВХ=сегментный адрес программы

mov

AH,OEh

;Функция вывода на экран символа

mov

AL,BH

;Выведем старшую половину

;сегментного адреса

hit

lOh

; Вызов BIOS

mov

AL,BL

{Выведем младшую половину

;сегментного адреса

hit

lOh

;Вызов BIOS

pop

BX

восстановим

pop

AX

; регистры

iret

;3авершение обработчика

main

endp

hiit

proc

;Секция инициализации

mov

AX,2505h

;Функция установки вектора

mov

DX,offset

пеш_05;Смещение обработчика

hit

21h

; Вызов DOS

mov

DX,(mit-main+10Fh)/16 ;Размер в параграфах

mov

AX,3100h

; Функция «завершить и

hit

;оставить в памяти»

init

endp

code

ends

end

main

Структура программы соответствует описанной ранее. В секции ини-*ачизации выполняется установка обработчика прерывания 05h, при этом ^исходное содержимое вектора 5 не сохраняется. Это, разумеется, очень плохо, так как лишает нас возможности этот вектор восстановить. С дру­гой стороны, восстанавливать перехваченные векторы надлежит при за­вершении программы, а применительно к резидентной программе — при се выгрузке из памяти. Однако в нашей простой программе не предусмот­рено средств выгрузки (процедура выгрузки довольно сложна), и про­грамме придется находиться в памяти до перезагрузки машины.

Установив вектор, программа завершается с оставлением в памяти ее ^резидентной части с помощью функции 31h.

Резидентная часть программы является классическим обработчиком ; программного прерывания. В первых же предложениях сохраняются регис-АХ и ВХ, используемые далее в программе, а затем содержимое сег->местного регистра CS переносится в регистр ВХ. С таким же успехом мож­но было скопировать содержимое любого из регистров DS, ES или SS, "так как в программе типа .СОМ все регистры настроены на один и тот же .сегментный адрес (см. рис. 3.2). Копирование из сегментного регистра в •'регистр общего назначения понадобился потому, что в дальнейшем нам [Придется работать с отдельными половинками сегментного адреса, а у 'сегментных регистров половинок нет.

'Команды и алгоритмы

122