Tooprogram.ru

Компьютерный справочник
2 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Список прерываний ассемблер

ПРЕРЫВАНИЯ АССЕМБЛЕРА

Дата добавления: 2014-11-28 ; просмотров: 5320 ; Нарушение авторских прав

Ассемблер имеет возможность, которой завидуют все, кто программирует только на языках высокого уровня. Имеется ввиду возможность оптимальным образом использовать прерывания операционной системы. Ведь это ничто иное, как готовые процедуры. Однако вместо того, чтобы вызывать их по CALL, они вызываются командой INT.

INT 21H вызывает прерывание с шестнадцатеричным номером 21. Имеется ряд таких прерываний, как в базовой системе ввода/вывода, так и в операционной системе, причем некоторые из этих процедур необычайно мощны. На самом деле некоторые из них настолько тесно связаны с системой, что Вы практически не можете сами написать эквивалентную процедуру. Языки высокого уровня позволяют использовать многие из этих прерываний. Они используют их для вывода на экран, приема ввода с клавиатуры и доступа к дискам. Но многие действительно полезные прерывания игнорируются языками высокого уровня, например такие, которые позволяют запустить из одной программы другую.

Перед вызовом прерывания некоторая информация должна быть помещена в регистры процессора. Например, прерывание, вертикально сдвигающее экран, должно знать размеры сдвигаемого окна, число строк на которое его надо сдвинуть и т.д. Эти значения часто называют входными регистрами. Часто Вы будете встречать слова “при входе AX должен содержать . ”, описывающие спецификацию входных регистров. Аналогично, при возврате из прерывания некоторые регистры возвращают значения или информацию о состоянии процессора. Они называются выходными регистрами и мы описываем их словами “при выходе AX содержит . ”. Зачастую одно прерывание содержит много функций. В частности, операционная система включила практически все свои возможности в прерывание 21H. Поэтому при вызове прерывания необходимо указывать номер функции. Все прерывания (как BIOS так и DOS) передают номер функции в AH (иногда в AL содержится номер подфункции).

Ниже перечислены функции DOS, которые могут оказаться полезными для операций ввода — вывода. Код функции устанавливается в регистре AH и затем выдается команда INT 21H.

AH=01: Ввод с клавиатуры с эхоотображением. Данная функция возвращает значение ASCII-кода нажатой клавиши в регистре AL. Нулевое значение в регистре L свидетельствует о том, что на клавиатуре была нажата специальная функциональная клавиша, например, Home, F1 или PageUp.

AH=02: Вывод символа. Для вывода необходимо код символа поместить в регистр DL.

AH=07: Ввод с клавиатуры без эхоотображения. Данная функция аналогична функции 01, но введенный символ не отображается на экране.

AH=09: Вывод на экран строки символов. Адрес строки, заканчивающейся знаком $, должен быть в регистре DX.

AH=0A: Буферизированный ввод с клавиатуры строки символов. Адрес буфера должен быть в регистре DX. Первый байт буфера указывает рабочий размер буфера. Во втором байте буфера находится счетчик символов (фактическое число байтов, введенных с клавиатуры без учета кода Enter). Третий байт — начало входной строки, состоящей из символов ASCII. Конец входной строки — символ возврата каретки (Enter).

Иллюстрированный самоучитель по Assembler

Система прерываний

Самое начало оперативной памяти от адреса 0000h до 03FFh отводится под векторы прерываний – четырехбайтовые области, в которых хранятся адреса обработчиков прерываний (ОбрПр на рис. 1.12). В два старшие байта каждого вектора записывается сегментный адрес обработчика, в два младшие – смещение (относительный адрес) точки входа в обработчик. Векторы, как и соответствующие им прерывания, имеют номера, причем вектор с номером 0 располагается, начиная с адреса 0, вектор 1 – с адреса 4, вектор 2 – с адреса 8 и т.д. Вектор с номером п занимает, таким образом, байты памяти от n*4 до n*4+3. Всего в выделенной под векторы области памяти помещается 256 векторов.

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

Обработчик прерываний всегда заканчивается командой iret (interrupt return, возврат из прерывания), выполняющей обратные действия – извлечение из стека сохраненных там слов и помещение их назад в регистры IP и CS, а также в регистр флагов. Это приводит к возврату в основную программу в ту самую точку, где она была прервана.

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

Внутренние прерывания возбуждаются цепями самого процессора при возникновении одной из специально оговоренных ситуаций, например, при выполнении операции деления на ноль или при попытке выполнить несуществующую команду. За каждым из таких прерываний закреплен определенный вектор, номер которого известен процессору. Например, за делением на 0 закреплен вектор 0, а за неправильной командой – вектор 6. Если процессор сталкивается с одной из таких ситуаций, он выполняет описанную выше процедуру прерывания, используя закрепленный за этой ситуацией вектор прерывания.

Наконец, еще одним чрезвычайно важным типом прерываний являются программные прерывания. Они вызываются командой hit с числовым аргументом, который рассматривается процессором, как номер вектора прерывания. Если в программе встречается, например, команда: int 13h то процессор выполняет ту же процедуру прерывания, используя в качестве номера вектора операнд команды int. Программные прерывания применяются в первую очередь для вызова системных обслуживающих программ – функций DOS и BIOS. С командой int 2In вызова DOS мы уже сталкивались в Примере 1.1 и будем встречаться еще многократно. В дальнейшем будут также приведены примеры использования команды int для вызова прикладных обработчиков программных прерываний.

Читать еще:  Выполняется проверка безопасности как отключить

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

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

Как видно из таблицы, векторы прерываний можно условно разбить на следующие группы:

  • векторы внутренних прерываний процессора (0lh, 02h и др.);
  • векторы аппаратных прерываний (08h…0Fh и 70h…77h);
  • программы BIOS обслуживания аппаратуры компьютера (10h, 13h, 16h и др.);
  • программы DOS (21h, 22h, 23h и др.);
  • адреса системных таблиц BIOS (IDh, lEh и др.).

Системные программы, адреса которых хранятся в векторах прерываний, в большинстве своем являются всего лишь диспетчерами, открывающими доступ к большим группам программ, реализующих системные функции. Так, видеодрайвер BIOS (вектор 10h) включает программы смены видеорежима, управления курсором, задания цветовой палитры, загрузки шрифтов и многие другие. Особенно характерен в этом отношении вектор 21h, через который осуществляется вызов практически всех функций DOS: ввода с клавиатуры и вывода на экран, обслуживания файлов, каталогов и дисков, управления памятью и процессами, службы времени и т.д.

Для вызова требуемой функции надо не только выполнить команду int с соответствующим номером, но и указать системе в одном из регистров (для этой цели всегда используется регистр АН) номер вызываемой функции. Иногда для «многофункциональных» функций приходится указывать еще и номер подфункции (в регистре AL).

MS-DOS для программиста

5.3. Установка обработчиков прерываний

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

Перед тем как приступить к изменению векторов прерываний, функция tsrinit запрещает аппаратные прерывания, вызывая функцию _disable . После того как изменение векторов прерываний завершено, вызывается функция _enable , разрешающая обработку аппаратных прерываний:

Обработчики всех прерываний, за исключением прерывания INT 13h, составлены на языке С. Так как прерывание INT 13h возвращает результат выполнения операций в регистре флагов, соответствующий обработчик удобнее составить на языке ассемблера.

Расскажем подробно о том, какие вектора прерываний мы переопределяем и зачем.

Прерывание INT 1Ch

Прерывание INT 1Ch является программным и вызывается обработчиком аппаратного прерывания от таймера INT 08h приблизительно 18,2 раза в секунду.

Наша программа использует это прерывание, для того чтобы выводить в правом верхнем углу экрана мигающие символы «*» и «+». Такое мигание нужно только для индикации активности резидентной программы. Если индикация не требуется, вы можете не изменять соответствующий вектор прерывания и не предусматривать обработчик для этого прерывания.

Наш обработчик прерывания INT 1Ch называется new_int1c и имеет следующий вид:

Массив screen содержит дальние указатели на массив целых чисел, определенные следующим образом:

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

Для того чтобы символы не мигали слишком часто, обработчик прерывания INT 1Ch подсчитывает прерывания в статическом счетчике count. Если значение этого счетчика больше 2, выводится символ ‘*», если меньше — символ «+».

Перед тем как возвратить управление, функция new_int1c вызывает старый обработчик прерывания INT 1Ch , адрес которого хранится в переменной old_int1c. Для этого используется функция _chain_intr .

Прерывание INT 2Fh

Обработчик прерывания INT 2Fh , который встраивает наша программа, выполняет две функции.

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

Во-вторых, он нужен для выгрузки резидентной программы из памяти.

Исходный текст обработчика прерывания INT 2Fh представлен ниже:

Вызов прерывания INT 2Fh происходит при запуске нашей программы, а также и при запуске других резидентных программ. Регистр AH при этом должен содержать идентификатор резидентной программы. Для программы TSRDEMO мы выбрали идентификатор FFh, хотя никто не сможет гарантировать, что такой идентификатор уже не используется другой программой. Для надежности вы можете указать дополнительный идентификатор, например, в виде текстовой строки, адрес которой передается через другие регистры. Мы не стали этого делать для сокращения объема листинга программы.

Итак, если при вызове прерывания INT 2Fh регистр AH содержит значение FFh, наш обработчик прерывания считает, что вызов выполняет программа TSRDEMO.

В этом случае он дополнительно проверяет содержимое регистра AL, в котором находится код выполняемой функции.

Если этот код равен 0, прерывание INT 2Fh вызвано для проверки наличия программы TSRDEMO в памяти. В ответ обработчик возвращает в регистре AX значение 00FFh. Это и есть признак того, что программа TSRDEMO уже загружена в память и ее повторная загрузка невозможна.

Читать еще:  Изучение языка си с нуля

Если же код равен 1, программа TSRDEMO была запущена с параметром u для выгрузки своей копии из памяти.

В этом случае обработчик прерывания INT 2Fh сохраняет в глобальной переменной ExitAddress адрес завершения, переданный обработчику в регистрах BX:DX. Затем проверяется флаг tsr_already_active, который установлен, если резидентная программа активна и ее в данный момент нельзя выгружать из памяти.

Далее обработчик разрешает аппаратные прерывания, которые были запрещены перед вызовом прерывания INT 2Fh для выгрузки, и предпринимает попытку выгрузить резидентную программу, вызывая функцию tsr_exit.

Заметим, что после выгрузки резидентной программы функция tsr_exit передает управление MS-DOS, а не возвращает его обратно в программу.

Попытка выгрузки программы может окончиться неудачно, если пользователь загрузил после программы TSRDEMO другую резидентную программу, изменившую вектора прерываний, для которых программа TSRDEMO установила свои обработчики. В этом случае наша программа «не знает», как восстановить вектора прерываний и не выгружается из памяти. Тем не менее, она блокирует свою работу, записывая в переменную tsr_already_active значение -FFFFh.

Подробнее процесс выгрузки резидентной программы будет рассмотрен позже.

Заметим, что если содержимое регистра AX при вызове прерывания INT 2Fh не равно FF00h или FF01h, наш обработчик прерывания передает управление по цепочке, вызывая для этого функцию _chain_intr .

Прерывание INT 09h

Аппаратное прерывание от клавиатуры INT 09h обрабатывается для того чтобы обнаружить комбинацию клавиш, предназначенную для активизации резидентной программы:

Когда программа уже активна, установлен флаг tsr_already_active. В этом случае наш обработчик прерывания передает управление по цепочке, вызывая старый обработчик.

Если программа TSRDEMO не активна, наш обработчик прерывания вводит код нажатой клавиши из порта клавиатуры и проверяет, была ли нажата клавиша . Затем проверяется код нажатой клавиши. В том случае, если пользователь нажал комбинацию клавиш , нужно активизировать резидентную программу.

Однако активизация во время обработки аппаратного прерывания от клавиатуры — не самое лучшее решение. Поэтому наш обработчик просто устанавливает флаг popup_while_dos_busy, который служит запросом на активизацию.

Активизация резидентной программы будет выполнена позднее, при обработке аппаратного прерывания INT 08h или прерывания INT 28h .

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

Прерывание INT 08h

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

Наша программа использует несколько возможностей для своей активизации. В частности, обработчик аппаратного прерывания таймера INT 08h периодически проверяет возможность активизации:

Прежде всего, проверяется флаг tsr_already_active. Этот флаг устанавливается, когда резидентная программа уже активизирована. Проверка флага активизации позволяет избежать повторной активизации, которая может привести к катастрофе.

Активизация не выполняется также и в том случае, если установлен флаг InDos или unsafe_flag (последний устанавливается, если вызван обработчик прерывания INT 13h ).

Флаг popup_while_dos_busy установлен в том случае, когда был запрос на активизацию. Он устанавливается обработчиком аппаратного прерывания от клавиатуры INT 08h . Если запроса на активизацию нет, этот флаг не установлен и, следовательно, активизацию выполнять не нужно.

Если активизация возможна, сбрасываются флаги popup_while_dos_busy и устанавливается флаг tsr_already_active. Затем вызывается старый обработчик прерывания INT 08h и разрешаются прерывания.

Далее вызывается функция activate_tsr, которая выполняет все действия, необходимые для активизации. Она будет описана отдельно. После возвращения управления из этой функции флаг tsr_already_active сбрасывается.

В том случае, когда активизация резидентной программы невозможна, наш обработчик прерывания INT 08h вызывает старый обработчик и возвращает управление прерванной программе.

Прерывание INT 28h

Прерывание INT 28h вызывается MS-DOS, когда она ожидает ввод данных от клавиатуры или, иными словами, ничем особенным не занята. Поэтому обработчик прерывания INT 28h может активизировать резидентную программу, если на это есть запрос от пользователя.

Приведем исходный текст обработчика прерывания INT 28h :

Обработчик прерывания INT 28h содержит счетчик рекурсивных вызовов int_28_in_progress, который анализируется при активизации резидентной программы функцией activate_tsr.

Если есть запрос на активизацию, проверяются флаги tsr_already_active и unsafe_flag. Дополнительно проверяется, не выполняется ли попытка активизировать резидентную программу во время обработки прерывания MS-DOS, отличного от INT 28h . Для этого вызывается функция Int28DosBusy.

Обратите внимание на различие в способе проверки возможности активизации при обработке прерывания INT 08h и INT 28h .

В первом случае вызывается функция DosBusy:

Эта функция проверяет содержимое флагов InDos и флага обработки критической ошибки. Если MS-DOS не выполняет обработку критической ошибки и если прерываемая программа не вызывает функцию MS-DOS, можно выполнять активизацию. В этом случае функция DosBusy возвращает значение 0.

Однако при вызове прерывания INT 28h флаг InDos установлен всегда, так как указанное прерывание — это тоже прерывание MS-DOS. В данном случае для проверки возможности активизации используется другая функция, которая называется Int28DosBusy.

Читать еще:  Открыть файл предупреждение системы безопасности

Эта функция допускает однократный (не рекурсивный) вызов функции INT 28h , проверяя значение, которое записывается в байт памяти, отведенный для флага InDos:

При рекурсивных вызовах функций MS-DOS значение, хранящееся в этом байте, увеличивается на 1. Активизация резидентной программы допускается только в том случае, когда в этом байте находится значение 1, т. е. когда нет рекурсии.

Обработчик прерывания INT 28h активизирует резидентную программу точно таким же способом, что и обработчик прерывания INT 08h , а именно, вызывая специально предназначенную для активизации функцию activate_tsr, определенную в нашей программе.

Прерывание INT 13h

Обработчик прерывания INT 13h составлен на языке ассемблера. Его единственное назначение — увеличение значения флага unsafe_flag при каждом вызове прерывания INT 13h и уменьшение при возврате из этого прерывания. Когда программа TSRDEMO будет предпринимать попытку активизации во время обработки прерывания INT 13h, она проверит значение флага unsafe_flag. Если оно не будет равно 0, активизация невозможна, так как в данный момент времени выполняется обработка прерывания INT 13h.

Исходный текст обработчика прерывания INT 13h представлен ниже:

Для обеспечения возможности адресации глобальной переменной unsafe_flag регистр DS устанавливается на сегмент данных программы TSRDEMO.

Адрес старого обработчика прерывания INT 13h находится в переменной old_int13, куда он записывается функцией get_int_13. Эта функция вызывается из функции tsrinit. Ее исходный текст вы найдете в листинге 5.3 (см. ниже).

Ассемблер

Прерывание 21h: общие функции DOS

Все функции DOS вызываются с помощью прерывания 21h (в десятичной нотации 33). Первая версия DOS содержала 42 функции. Во второй к ним добавлено еще 33 функции, которые сохраняются во всех последующих версиях. Выбор конкретной функции осуществляется путем записи соответствующего номера в регистр AH.

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

Для вывода одного символа на экран ПК используется

функция 02 прерывания 21h:

Выводимый символ высвечивается в позиции курсора (что бы там ни было записано), после чего курсор сдвигается на одну позицию вправо. Если курсор находился в конце строки экрана, то он перемещается на начало следующей строки, а если курсор был в конце последней строки экрана, то содержимое экрана сдвигается на одну строку вверх, а внизу появляется пустая строка, в начало которой и устанавливается курсор.

Особым образом осуществляется вывод символов с кодами 7, 8, 9, 10 (0Ah) и 13 (0Dh). Символ с кодом 7 (bell, звонок) на экране не высвечивается (и курсор не сдвигается), а вызывает звуковой сигнал. Символ с кодом 8 (backspase, шаг назад) возвращает курсор на одну позицию влево, если только он не был в самой левой позиции строки. Символ с кодом 9 (tab, табуляция) смещает курсор вправо на ближайшую позицию, кратную 8. Символ с кодом 10 (line feed, перевод строки) перемещает курсор в следующую строку экрана, оставляя его в той же колонке. Символ с кодом 13 (carrige returne, возврат каретки) устанавливает курсор на начало текущей строки; вывод подряд символов с кодами 13 и 10 означает перевод курсора на начало следующей строки.

Функция 9: вывести строку на экран дисплея

Для вывода на экран строки (последовательности символов) можно, конечно, использовать функцию 02, однако сделать это можно и за один прием с помощью функции 09 прерывания 21h:

DS:DX := начальный адрес строки

Перед обращением к этой функции в регистр DS должен быть помещен номер того сегмента памяти, в котором находится выводимая строка, а в регистр DX — смещение строки внутри этого сегмента. При этом в конце строки должен находиться символ $ (код 24h), который служит признаком конца строки и сам не выводится.

Хотя эта функция может оказаться намного удобнее функций побайтового вывода на экран (функция 2 и 6), она имеет тот недостаток, что вполне обычный символ $ используется как ограничитель строки. Это еще один побочный продукт совместимости с CP/M.

Расширенные функции операционной системы DOS в качестве ограничителя строки используют CHR$(0). Это соответствует соглашениям, принятым в операционной системе UNIX и языке программирования Си.

Среди функций DOS нет такой, которая выводит числа. Такую операцию, если надо, приходится реализовывать на основе рассмотренных функций.

Функция 4Ch: завершение программы

Завершив все свои действия, программа обязана вернуть управление операционной системе, чтобы пользователь мог продолжить работу на ПК. Такой возврат реализуется функцией 4Ch прерывания 21h, которую помещают в конце программы:

Каждая программа, вообще говоря, обязана сообщить, успешно или нет она завершила свою работу. Дело в том, что любая программа вызывается из какой-то другой программы (например, из операционной системы), и иногда вызвавшей программе, чтобы правильно продолжить работу, надо знать, выполнила ли вызванная программа все, что надо, или она проработала с ошибкой. Такая информация передается в виде кода завершения программы (некоторого целого числа), который должен быть нулевым, если программа проработала правильно, и ненулевым (каким именно — оговаривается в каждом случае особо) в противном случае. (Узнать код завершения вызванной программы можно с помощью функции 4Dh прерывания 21h.) Потребуется этот код или нет, программа все равно должна выдать его.

Ссылка на основную публикацию
Adblock
detector