Методическое руководство к курсовой работе по дисциплине Assembler ibm pc содержание
Вид материала | Руководство |
- Учебно-методическое пособие по выполнению курсовой работы по дисциплине «Комплексный, 276.48kb.
- Дейт К. Д27 Руководство по реляционной субд db2/ Пер с англ и предисл. М. Р. Когаловского, 4309.37kb.
- Методическое пособие по дисциплине «информатика» (2семестр), 838.3kb.
- Методическое пособие по курсовой работе Для студентов Современной Гуманитарной Академии, 63.65kb.
- Пособие предназначено для студентов, выполняющих курсовые работы по дисциплине «Направления, 589.33kb.
- Руководство к выполнению курсовой работы по дисциплине «Финансы предприятий», 244.13kb.
- Методические указания к курсовой работе по дисциплине «Материаловедение и ткм», 699.8kb.
- Пояснительная записка к курсовой работе на тему: «Активный полосовой фильтр» по дисциплине, 342.06kb.
- Всвязи с имеющими место случаями невыполнения требований задания к курсовой работе, 112.75kb.
- Курс. 01;Мпк. 01;3 методическое пособие по курсовой работе методика воспитательной, 230.31kb.
Endp init
;Поля данных в нерезидентной части программы
msg1 db 'Резидентный обработчик установлен$'
msg2 db 'Попытка вторичной установки. Установка отменена$'
msg3 db 'Программа выгружена из памяти$'
option db 'off'
^
END resident ;Конец программы/точка входа
Комментарий. Резидентная часть программы включает два обработчика. Аппаратный обработчик new_09h, выявляет нажатие клавиши “серый плюс” для активизации процедуры получения системного времени с помощью функции DOS 2Ch и осуществляет его вывод на экран с использованием средств BIOS. Инструментальный обработчик new_2Fh реализует рассмотренные выше функции по недопущению повторной загрузки программы в память и выполняет её выгрузку из памяти.
Рассмотрим подробно реализацию функции выгрузки программы из памяти. Если какая-либо программа запускается из командной строки с указанием помимо имени файла каких-либо параметров (ключей или опций), определяющих режим её работы, то DOS помещает все символы, введённые после имени программы (так называемый хвост команды) в префикс программного сегмента PSP, начиная с адреса 80h. При этом в байт по адресу 80h заносится число символов всего хвоста, включая пробелы между именем программы и последующими параметрами, а начиная с адреса 81h, следует запись всех символов хвоста, введённых с клавиатуры (последним будет код нажатия клавиши Enter). Таким образом, если программа с именем Prg6.com была запущена командой Prg6.com off, то в PSP, начиная с байта 80h, будет записано: 4, ‘ off’,13
Анализ структуры команды запуска производится в секции инициализации программы. Прежде всего, с помощью функции AX=0C800h прерывания 2Fh выполняется проверка на наличие в памяти первой копии программы. Если она не обнаружена, то независимо от типа запускающей команды (с опцией или нет) происходит переход на метку ОК и установка программы в памяти. В противном случае начинается анализ хвоста команды. Байт с длиной хвоста, находящийся по адресу ES:80h, помещается в регистр CL и сравнивается с нулём. Если в нём 0, команда была без хвоста. В этом случае выводится сообщение о невозможности вторичной установки, и инициализация завершается вызовом функции 4Ch (выход в DOS). Если хвост имеет ненулевую длину, то его длина фиксируется в регистре CX для последующей организации цикла. C помощью строковой команды scasb определяется адрес первого символа хвоста, отличного от нулевого. Далее командой сравнения строк cmpsb осуществляется сравнение трёх оставшихся символов хвоста с опцией ‘off”. Если результат сравнения оказался отрицательным, выполняется переход на завершение программы с предварительным выводом сообщения о невозможности повторной установки. Если введённая команда содержала опцию ‘off’, - в первую копию резидента посылается приказ на выгрузку: прерывание 2Fh с кодом AL=01h. По завершению выгрузки программы из памяти (команда iret процедуры new_2Fh), секция инициализации завершается выводом соответствующего сообщения последующим вызовом функции 4Ch.
Несколько слов о выгрузке программы из памяти, которой предшествует восстановление всех перехваченных резидентом векторов
Программа, загруженная в память, включает три компонента: окружение, префикс программы PSP и собственно саму программу, которая в случае файла .EXE может состоять из нескольких сегментов. Окружение представляет собой блок памяти, в которой в виде символьных строк записаны переменные окружения программы, и служит для передачи программе требуемых параметров с помощью системной команды SET. В конце блока окружения DOS помещает полный путь нахождения программы и её имя.4
Выгрузка всех компонентов программы осуществляется с помощью функции DOS 49h.
Int 21h,функция 49h. Освобождение блока памяти.
^ Освобождает блок памяти и передаёт его системе.
Вызов: AH=49h,
ES= сегментный адрес освобождаемого блока
На первом шаге осуществляется выгрузка окружения программы, сегментный адрес которого находится в PSP со смещением 2Ch относительно его начала, а затем уже и вся программа, включая и сам PSP (Сегментный адрес этого блока находится, естественно, в регистре CS).
Как уже отмечалось ранее, обработчик прерывания new_09h, использовал процедуру вывода на экран на основе функции BIOS 13h прерывания Int 10h (выделена в тексте программы символами ***). К этому вопросу мы ещё вернёмся в следующем параграфе.
11. Нереентерабельность MS-DOS и пути её преодоления в обработчиках
аппаратных прерываний
В предыдущей программе ^ Prg6 для вывода системного времени на экран использовалась функция BIOS 13h. Сделано это было сознательно, так как использовать в данном случае функции DOS для вывода было нельзя. Чтобы убедиться в этом, замените блок вывода в программе следующим фрагментом, предварительно сняв символ комментария в конце строки с инициализацией переменной time.
Mov ah,02h ;Функция BIOS установки позиции курсора
Mov bh,0 ;0- страница
Mov dh,10h ;Строка
Mov dl,25h ;Столбец
Int 10h
Push cs ;Адрес строки вывода в DS:DX
Pop ds
Mov ah,09h ;Функция вывода DOS 09h
Mov dx,offset string
Int 21h
Установите режим сеанса MS-DOS и активизируйте резидентную программу, нажав на клавишу «серый плюс». После выполнения резидентом операции по выводу времени на экран функцией DOS 09h, система неминуемо зависнет5. Почему так происходит? Дело в том, что в момент запуска резидентной программы, выполнялась программа командного процессора Command.com по вводу символов с клавиатуры в командную строку функцией DOS 0Ah, которая и прервалась обработчиком аппаратных прерываний new_09h, когда последний выявил нажатие клавиши «серый плюс». Само по себе прерывание функции DOS - нормальное явление, не приводящее к каким-либо последствиям, если после этого уже сам обработчик аппаратного прерывания не обратится к функциям ввода/вывода MS-DOS. Функция ввода/вывода выполнится правильно, но при возврате управления командой iret в прерванную обработчиком new_09h функцию DOS 0Ah, произойдёт разрушение системы.
Невозможность вызвать функцию DOS “изнутри” другой функции DOS данного типа носит название нереентерабельности DOS. Как уже упоминалось в § 8, DOS выполняет свои функции на собственных стеках (стек ввода/вывода, дисковый стек и вспомогательный стек для обработки ошибок). Перед началом выполнения функции диспетчер DOS заносит в указатель стека SP адрес дна соответствующего стека DOS, которым и пользуется при исполнении данной функции. Если же прервать этот процесс (что и делает асинхронное прерывание от клавиатуры) и активизировать какую-либо функцию DOS той же группы, то диспетчер DOS снова установит регистр SP на начало того же стека. При этом в процессе вторичного исполнения происходит затирание содержимого стека, оставшегося от первого исполнения функции этой группы. Разрушение не будет происходить, если аппаратный обработчик прервёт функцию одной группы, а вызовет функцию другой группы. В этом случае используются разные стеки, и система будет работать нормально.
Какие же пути существуют для преодоления данного недостатка, в контексте рассматриваемых вопросов? Укажем на некоторые из них.
1. Возвращаясь снова к предыдущей программе ^ Prg6, можно заметить, что мы могли бы для целей вывода информации на экран использовать функцию DOS 40h, которая принадлежит к так называемой дисковой группе. Однако, при использовании стандартного дескриптора экрана 01h, эта функция уподобляется функциям ввода/вывода первой группы и, в таком виде, её использовать нельзя. Использовать эту функцию можно, если открыть экран как файл, получив для него другой дескриптор. Это можно сделать с помощью функции DOS 3Dh, указав в качестве имени файла обозначение CON – консоль экрана.
^ Int 21h, функция 3Dh. Открытие файла.
Открывает файл с указанной спецификацией. Возвращает дескриптор для последующих операций над файлом. Устанавливает указатель на начало файла (байт 0).
Вызов: AH=3Dh,
AL=режим доступа: 0 – чтение, 1 – запись, 2 – запись и чтение. Если к режиму
добавлено 80h, дескриптор наследуется дочерним процессом.
DS:DX= адрес спецификации файла в виде строки ASCIIZ.
Возврат: AX= дескриптор.
Ниже приводится фрагмент вывод на экран функцией DOS 40h с использованием нестандартного дескриптора.
Mov ah,3Dh ;Открытие файла с доступом для записи
Mov al,1
Mov dx,offset consol ;Адрес имени файла
Int 21h
Mov bx,ax ;Перешлём дескриптор в BX
Mov ax,40h ;Файловая функция вывода информации
Mov cx,strlen
Mov dx,offset string
Int 21h
;Поля данных резидентной программы (надо добавить)
consol DB ‘CON’,0 ;Имя консоли в формате файловых функций
2. Достаточно радикальным средством преодоления нереентерабельности DOS применительно к рассматриваемой ситуации является всё-таки использование для вывода информации функций BIOS. Дело в том, что прерывания BIOS не используют системные стеки, а работают на стеке программы, вызвавшей это прерывание. Однако надо помнить, что прерывания BIOS нереентерабельны по отношению к самим себе – нельзя, прервав, допустим выполнение функции BIOS прерывания 13h (функции управления дисплеем), вызвать в обработчике то же прерывание Int 13h, или, прервав работу с экраном функцией 10h, вызвать в обработчике функцию того же прерывания Int 10h.
К сожалению BIOS не имеет системных флагов, которые фиксировали бы занятость BIOS при использовании её функций. Поэтому прикладные обработчики аппаратных прерываний, для корректной работы с функциями BIOS, должны вводить данные флаги самостоятельно.
3. Вывод информации на экран компьютера путём непосредственного программирования видеобуфера снимает все вопросы, однако этот способ нельзя рекомендовать при выводе большого объёма выводимой информации в виду отсутствия специальных средств форматирования (см. описание работы № 4).
4. Обработчик аппаратного прерывания перед вызовом какой-либо функции DOS должен анализировать состояния двух флагов занятости, а именно:
Флаг InDOS – устанавливается диспетчером DOS сразу же после анализа номера вызванной функции DOS. Значение InDOS=1 говорит о том, что выполняется какая-либо функция DOS. Флаг ErrorMode - устанавливается диспетчером DOS, если зафиксировано состояние критической ошибки при выполнении операций с дисками. Обнаружив такую ошибку, DOS устанавливает ErrorMode в “1” и выполняет прерывание Int 24h, которое выводит на экран аварийное сообщение.
Адреса указанных флагов можно получить с помощью функции DOS 34h.
^ Int 21h, функция 34h. Получение адресов флагов занятости DOS.
Возвращает адрес байта области текущих данных DOS (SDA), содержащего флаг занятости InDOS
Вызов: AH=34h.
Возврат: ES:BX = двухсловный адрес однобайтного флага InDOS,
ES:BX-1 = двухсловный адрес однобайтного флага ErrorMode.
Итак, если хотя бы один из флагов не равен нулю, вызывать DOS нельзя (дело в том, что при обнаружении критической ошибки DOS декрементирует флаг InDOS и инкрементирует флаг ErrorMode). Данные адреса необходимо получить и сохранить на этапе инициализации обработчика аппаратного прерывания, а в самом обработчике аппаратных прерываний, перед вызовом функции DOS, необходимо проверить значения этих флагов.
in_dos dd 0 ;Адрес ES:BX флага InDOS
crit_err dd 0 ;Адрес ES:BX-1 флага ErrorMode
task_request db 0 ;Флаг требования запуска задачи
…
les bx,[cs:in_dos] ;Загрузим адрес флага InDOS в регистры ES:BX
cmp [byte ES:BX],0 ;Флаг InDOS сброшен?
jne wait_dos ;Нет, придётся ждать
cmp [byte ES:BX-1],0 ; Флаг ErrorMode сброшен?
jne wait_dos ;Нет, придётся ждать
call task ;Да, оба флага сброшены и можно вызывать процедуру
jmp out_int ;с использованием функций DOS
wait_dos: inc [cs:task_request] ;Установим флаг требования запуска процедуры task
out_int: … ;Посылка в контроллер команды EOI и восстановление регистров
iret ; Завершим обработчик
В данном фрагменте предполагается, что процедура task как раз и составляет ту часть обработчика аппаратного прерывания, которая содержит обращение к функциям DOS. При этом, если хотя бы один из флагов занятости DOS установлен в 1, процедура task не выполняется, а устанавливается флаг требования на её обработку task_request с последующей передачей управления в прерванную задачу. Чтобы запустить в дальнейшем процедуру task, нужен дополнительный «активизатор» данного обработчика. В качестве такого «активизатора» обычно используется прикладной обработчик таймера, который 18,2 раз в секунду будет проверять состояние флагов требования на обработку task_request и флагов занятости DOS.
in_dos dd 0 ;Адрес ES:BX флага InDOS
task_request db 0 ;Флаг требования запуска задачи
old_08h dd 0
…
Proc new_08h
Pushf
Call [dword cs:old_08h] ;Перейдём в системный обработчик с возвратом
… ;Сохраним регистры
cmp [cs:task_request],1 ;Процедура task требует запуска
jne out_08h ;Нет, можно завершить обработку
les bx,[cs:in_dos] ;Загрузим адрес флага занятости InDOS
cmp [byte ES:BX],0 ;Флаг InDOS сброшен?
jne out_08h ;Нет, можно завершить обработку
cmp [byte ES:BX-1],0 ;Флаг ErrorMode сброшен?
jne out_08h ;Нет, можно завершить обработку
dec [es: task_request] ;Сбросим флаг требования
call task ;Да, оба флага сброшены и можно вызывать процедуру
;с использованием функций DOS
out_08h: … ;Восстановим используемые регистры
iret ;Завершим обработчик
Endp new_08h
Описанная методика не может считаться универсальной (впрочем, такой нет). Если текущая программа ждёт ввода с клавиатуры, она не выходит из соответствующей DOS и флаг занятости InDOS=1. То же получится, если в качестве текущей программы выступает командный процессор Command.com, ожидающий ввода с клавиатуры очередной команды (функция ввода DOS 0Ah). В этой ситуации обработчик прерывания никогда не сможет запустить процедуру task с требуемой функцией DOS. Для преодоления такой тупиковой ситуации можно использовать прерывание Int 28h, которое включено в каждую функцию DOS ввода с клавиатуры. Так, функцию ввода с клавиатуры DOS 01h в упрощенном виде можно представить схемой рис. 7. Системный обработчик Int 28h содержит единственную команду iret, поэтому вызов Int 28h при выполнении функции ввода/вывода никак не нарушает ход программы, но даёт возможность использовать свою процедуру обработки.
Надо только иметь ввиду, что поскольку данное прерывание возникает при выполнении функции DOS, работающих на стеке ввода/вывода, то в прикладном обработчике Int 28h допустим вызов любых функций из диапазона 0Dh…6Ch. Кроме того, недопустим вызов функций с указанием стандартных дескрипторов клавиатуры или дисплея (0…2).
Активизатор задачи task, замещающий системный вектор Int 28h, строится по несколько отличной схеме в сравнении с активизатором от таймера.
…
in_dos dd 0
task_request db 0
old_28h dd 0 ;Ячейка для хранения вектора 28h
…
Proc new_28h
… ;Сохраним используемые регистры
Cmp [cs: task_request],1 ;Процедура task требует запуска?
Jne out_28h ;Нет, завершим обработку
Les bx,[cs:in_dos] ;Загрузим адрес флага InDOS
Cmp [byte ES:BX-1],0 ;Флаг ErrorMode сброшен?
Jne out_28h ;Нет, придётся ждать
Cmp [byte ES:BX],1 ;Флаг InDOS не больше 1?
Ja out_28h ;Больше. Вложенный вызов – вызов DOS запрещён
Dec [cs: task_request] ;Сбросим флаг требования и
Call task ;вызовем task
… ;Восстановим регистры
out_28h: jmp [dword cs:old_28h] ;В системный обработчик без возврата
Endp new_28h
Из программного кода активизатора new_28h следует, что если флаг запроса на обработку task_request установлен, то сначала проверяется состояние флага ErrorMode и, если он сброшен, то и состояние флага InDOS. Дело в том, что этот флаг должен быть равен 1, т. к. выполняется функция ввода с клавиатуры. Если же InDOS>1, то это значит, что в системе уже воспользовались данным прерыванием и вызвали функцию DOS Int 21h. Вызывать функции DOS, увеличивая уровень вложенности, нельзя. В этом случае, очевидно, можно обратится к функциям BIOS.
Ниже приводится пример резидентной программы, активизирующейся командой с клавиатуры (комбинация клавиш ^ Alt-A). При этом прикладной обработчик 09h лишь устанавливает флаг требования обработки task_request процедуры вывода на экран task системного времени, непосредственными же активизаторами исполнения процедуры task являются (в зависимости от ситуации в системе в момент вызова резидента) обработчики new_08h и new_28h. В программе Prg7 полностью приведены лишь те модули, которые отличают её от предыдущей программы Prg6.
Программа^ Prg7 может быть активизирована горячей клавишей Alt-A как во время ожидания системой ввода символов в командную строку (обработчик new_28h), так и во- время исполнения какой-либо задачи, использующей функции вывода DOS (обработчик таймера new_08h). Для исследования последней функции приведена тестовая программа Prg8.
;Prg7. Резидентная программа, активизирующаяся нажатием клавиш Alt-A, выводит на экран
;системное время функцией DOS 40h с учётом анализа занятости DOS. Программа защищена от
;повторной установки и может быть выгружена командой с клавиатуры с опцией off.
IDEAL
MODEL tiny
P486N
CODESEG
org 100h