
- •140010, Г. Люберцы, Московской обл., Октябрьский пр-т, 403.
- •Глава 1. Архитектура реального режима
- •1.1. Память и процессор
- •Глава 1
- •Глава 1
- •1.2. Распределение адресного пространства
- •Глава 1
- •1.3. Регистры процессора
- •Глава 1
- •Глава 1
- •9 7H Шестнадцатернчное обозначение числа
- •Глава 1
- •1.4. Сегментная структура программ
- •Глава 1
- •Глава 1
- •Глава 1
- •1.5. Стек
- •Глава 1
- •1.6. Система прерываний
- •Глава 1
- •Глава I
- •1.7. Система ввода-вывода
- •Глава I
- •Глава 1
- •Глава 2. Основы программирования
- •2.1. Подготовка и отладка программы
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.2. Представление данных
- •Глава 2
- •Глава 2
- •2.3. Описание данных
- •Глава 2
- •Глава 2
- •2.4. Структуры и записи
- •Глава 2
- •Глава 2
- •2.5. Способы адресации
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.7. Вызовы подпрограмм
- •Глава 2
- •2.8. Макросредства ассемблера
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 3. Команды и алгоритмы
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •3.2. Циклы и условные переходы
- •Глава 3
- •Глава 3
- •3.3. Обработка строк
- •Глава 3
- •3.4. Использование подпрограмм
- •Глава 3
- •Глава 3
- •3.5. Двоично-десятичные числа
- •Глава 3
- •Глава 3
- •3.6. Программирование аппаратных средств
- •Глава 3
- •37Ah Порт управлсш!я
- •Глава 3
- •Глава 3
- •Глава 4. Расширенные возможности
- •4.1. Архитектурные особенности
- •Глава 4
- •4.2. Дополнительные режимы адресации
- •Глава 4
- •4.3. Использование средств 32-разрядных процессоров в программировании
- •Глава 4
- •Глава 4
- •Глава 4
- •4.4. Основы защищенного режима
- •Глава 4
- •Глава 4
- •Глава 4
- •Глава 4
- •Idiv Деление целых чисел со знаком
- •Imul Умножение целых чисел со знаком
- •In Ввод из порта
- •Inc Инкремент (увеличение на 1)
- •Int Программное прерывание
- •Into Прерывание по переполнению
- •Iret Возврат из прерывания
- •1 Lods Загрузка операнда из строки : lodsb Загрузка байта из строки lodsw Загрузка слова из строки
- •Операнд
- •Xadd память, регистр
- •Xchg Обмен данными между операндами
- •Xlat Табличная трансляция
- •Xor Логическое исключающее или
- •Содержание
Глава 3
Команды и алгоритмы^
119
;Функция «завершить
и ;оставить в памяти»
AX,3100Ii
21h
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
установка в памяти, первой командой программы всегда является команда перехода на секцию инициализации и установки (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 |
2Ш |
;оставить в памяти» |
init |
endp |
|
|
code |
ends |
|
|
|
end |
main |
|
Структура программы соответствует описанной ранее. В секции ини-*ачизации выполняется установка обработчика прерывания 05h, при этом ^исходное содержимое вектора 5 не сохраняется. Это, разумеется, очень плохо, так как лишает нас возможности этот вектор восстановить. С другой стороны, восстанавливать перехваченные векторы надлежит при завершении программы, а применительно к резидентной программе — при се выгрузке из памяти. Однако в нашей простой программе не предусмотрено средств выгрузки (процедура выгрузки довольно сложна), и программе придется находиться в памяти до перезагрузки машины.
Установив вектор, программа завершается с оставлением в памяти ее ^резидентной части с помощью функции 31h.
Резидентная часть программы является классическим обработчиком ; программного прерывания. В первых же предложениях сохраняются регис-АХ и ВХ, используемые далее в программе, а затем содержимое сег->местного регистра CS переносится в регистр ВХ. С таким же успехом можно было скопировать содержимое любого из регистров DS, ES или SS, "так как в программе типа .СОМ все регистры настроены на один и тот же .сегментный адрес (см. рис. 3.2). Копирование из сегментного регистра в •'регистр общего назначения понадобился потому, что в дальнейшем нам [Придется работать с отдельными половинками сегментного адреса, а у 'сегментных регистров половинок нет.
'Команды и
алгоритмы
122