- •Вычислительные системы, сети и телекоммуникации: руководство к лабораторным и практическим занятиям
- •1. Арифметические команды
- •2. Логические команды
- •3. Сдвиговые команды
- •4. Команды передачи управления и управления флагами
- •5. Формат строк ассемблера. Метки и их использование
- •6. Директивы распределения памяти
- •7. Сегменты
- •8. Прерывания
- •9. Директивы порядка загрузки сегментов
- •10. Директивы управления программным счетчиком
- •11. Условия
- •12. Процедуры
- •13. Глобальные объявления
- •14. Макроопределения
- •15. Выражения
- •16. Директивы управления файлами
- •17. Резидентные программы
- •Библиографический список
- •Вычислительные системы, сети и телекоммуникации: руководство к лабораторным и практическим занятиям
- •400005, Волгоград, просп. Ленина, 28, корп.1
- •400005, Волгоград, ул. Советская, 35, корп.7
8. Прерывания
В архитектуре всех современных процессоров предусмотрены особые ситуации, когда процессор прекращает (прерывает) выполнение текущей программы и немедленно передает управление программе-обработчику, специально написанной для обработки этой конкретной ситуации. Такие особые ситуации делятся на два типа: прерывания и исключения, в зависимости от того, вызвало ли эту ситуацию какое-нибудь внешнее устройство или выполняемая процессором команда.
Исключения делятся на три типа: ошибки, ловушки и остановки, в зависимости от того, когда по отношению к вызвавшей их команде они происходят. Ошибки происходят перед выполнением команды, так что обработчик такого исключения получит в качестве адреса возврата адрес ошибочной команды. Ловушки происходят сразу после выполнения команды, так что обработчик получает в качестве адреса возврата адрес следующей команды. Остановки могут происходить в любой момент и вообще не предусматривать средств возврата управления в программу.
Команда INT используется в программах как раз для того, чтобы вызывать обработчики прерываний (или исключений), делая это следующим образом:
INT номер прерывания
INT помещает в стек содержимое регистра флагов, CS и IP, после чего передает управление программе, называемой «обработчик прерывания» с указанным в качестве операнда номером (число от 0 до 0FFh), аналогично команде CALL. Как правило, вызовы прерываний используются для выполнения большинства системных функций – работы с файлами, вводом/выводом и т.д. Например ниже показан вызов функции системного времени 2Ch 21-го прерывания, работающего с функциями DOS:
МОV AH 2Ch
INT 21h
Как после вызова подпрограммы существует команда возврата RET, так и для возврата из обработчика прерывания используется команда IRET. Она загружает из стека значения IP, CS и FLAGS, передавая управление в место возникновения прерывания.
Команда INTO или «прерывание по переполнению», вызывает обработчик прерывания 4, если флаг переполнения установлен (OF=1).
Фактически в большинстве случаев используемые прерывания они являются исключениями ловушки, поскольку адрес возврата, который передается обработчику, указывает на следующую команду, но так как эти команды были введены до разделения особых ситуаций на прерывания и исключения, их практически всегда называют командами вызова прерываний. Ввиду того, что обработчики прерываний и исключений обычно не различают механизм вызова, с помощью команды INT можно передавать управление как на обработчики прерываний, так и исключений.
Следует помнить, что программные прерывания, то есть передача управления при помощи команды INT, являются основным средством вызова процедур DOS и BIOS, потому что в отличие от вызова через команду CALL здесь не нужно знать адреса вызываемой процедуры – достаточно только номера.
Существует такое понятие, как обработчики прерываний. Их используют для того, чтобы обрабатывать прерывания от внешних устройств или чтобы обслуживать запросы других программ.
Необходимо знать, как реализуют обработчики программных прерываний. Когда выполняется команда INT, управление передается по адресу, который считывается из специального массива, таблицы векторов прерываний. Он располагается в памяти по адресу 0000h:0000h.
Команда INT помещает в стек регистр флагов и дальний адрес возврата, поэтому, чтобы завершить обработчик, надо выполнить команды popf и retf или одну команду iret, которая в реальном режиме полностью им аналогична.
После того как обработчик написан, следующий шаг – привязка его к выбранному номеру прерывания. Это можно сделать, прямо записав его адрес в таблицу векторов прерываний.
Перед завершением работы программа должна восстанавливать все старые обработчики прерываний, даже если это были неиспользуемые прерывания типа 87h – автор какой-нибудь другой программы мог подумать точно так же. Для этого надо перед предыдущим фрагментом кода сохранить адрес старого обработчика.
Хотя прямое изменение таблицы векторов прерываний и кажется достаточно удобным, все-таки это не лучший подход к установке обработчика прерывания, и пользоваться им следует только в случаях крайней необходимости, например внутри обработчиков прерываний. Для обычных программ DOS предоставляет две системные функции: 25h и 35h – установить и считать адрес обработчика прерывания, которые и рекомендуются к использованию в обычных условиях:
Выше были упомянуты функции 25h и 35h. Обе они относятся к прерыванию 21h, отвечающему за работу с функциями дисковой операционной системы DOS. На его примере удобно будет разобрать сам механизм работы с прерываниями и их функциями, чем сейчас и займемся.
Чтобы программным образом обратиться к функции какого-либо прерывания, необходимо выполнить следующие действия:
1. Занести номер требуемой функции интересующего нас прерывания в старшую часть регистра-аккумулятора.
2. Записать необходимые для работы функции параметры в те или иные регистры (регистр данных, регистр-счетчик и т.д.).
3. Произвести собственно вызов прерывания.
В качестве примера приведем классическую задачу вывода строки символов на экран. Руководствуясь приведенным выше алгоритмом и информацией, что это делает функция 09h 21-го прерывания, получим.
MOV AH, 09h
MOV DX, OFFSET strokа
INT 21h
Здесь вторая строка работает с меткой stroke, ассоциированной со строкой что объявлена в сегменте данных. Адрес начала строки помещается в регистр данных DX, после чего с помощью выражения смещения OFFSET выводим на экран всю строку.
Следует знать, что недопустимой является запись
MOV AX, 09h
INT 21h
Это связано с тем, что в таком случае номер функции запишется не в AH, а в AL, младшую часть аккумулятора. Если хотим использовать именно AX, то поступаем следующим образом
MOV AX, 0900h
INT 21h
Тогда в AL, запишутся нули, а 09h, как и полагается, уйдет в AH.
Для написания более сложных программ требуется изучить дополнительные инструменты языка ассемблер. Они и будут рассмотрены в следующих разделах.
