Goto... Search.. Hext Change.. Follou Previous 6 глава





Ъ.нанды и алгоритмы


III


 


Будем считать, что наш программный комплекс представляет собой программу типа.ЕХЕ и что обработчик прерываний входит в общий с основной программой программный сегмент. Для определенности будем использовать вектор 08U, хотя, разумеется, для любого другого аппарат­ного вектора структура программы останется той же. Поначалу приведем текст программы с некоторыми купюрами.

;Пример 3-3. Обработчик прерываний от таймера code segment

assume CS:code,DS:data

;Главная процедура main ртос

mov AX,data Инициализация сегментного

mov DS,AX;регистра DS

;Сохраним исходный вектор

mov AH,35h;Функция получения вектора

mov AL,08h;Номер вектора * -

int 21h

mov word ptr old_08,BX;Смещение исходного;обработчика

mov word ptr оШ_08-$-2,Е5;Сегмент исходного обработчика;Установим наш обработчик

mov AH,25h;Функция заполнения вектора ч

mov AL,08h;Номер вектора,.

mov DX,offset lгew_08;Cмeщeниe нашего;обработчика

push DS;Сохраним DS=data

push CS;Перешлем CS в DS

pop DS;через стек. DS:DX->new_08;,

int 21h v

pop DS;Восстановим DS=data:;..

;Продолжение основной программы :\.;Перед завершением профаммы восстановим исходный вектор

;3аполним DS:DX из old_09;Функция заполнения вектора;Номер вектора ;Функция завершения профаммы

Ids DX,oIdJ)8

mov AH,25h

mov AL,09h

int 21h

mov AX,4COOh

hit 21h

main endp K,-

;Процедура обработчика прерываний от таймера, .•

new_08 proc i ;.

;Действия, выполняемые 18 раз в секунду

mov AL,20h разблокировка прерываний L-

out 20h,AL;в контроллере прерываний и

iret;Возврат в прерванную программу &Ь

ne-wj)8 endp ^


code ends

data segment

old_08 dd 0;Ячейка для хранения исходного вектора

data ends

stk segment stack

db 256 dup (0)..

stk ends

end main

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

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

Хотя и чтение, и заполнение вектора прерываний можно выполнить с помощью простых команд mov, однако предпочтительнее использовать специально предусмотренные для этого функции DOS. Для чтения векто­ра используется функция с номером 35h. В регистр AL помешается номер вектора. Функция возвращает исходное содержимое вектора в парс регис­тров ES:BX (легко догадаться, что в ES сегментный адрес, а в ВХ смеще­ние). Для хранения исходного содержимого вектора в сегменте данных предусмотрена двухсловная ячейка old_08. В младшем слове этой ячейки (с фактическим адресом old_08) будет хранится смещение, в старшем (с фактическим адресом old_08+2) — сегментный адрес. Для того, чтобы обратиться к словам, составляющим эту ячейку, приходится использо­вать описатель word ptr, который как бы заставляет транслятор на время забыть о начальном объявлении ячейки и позволяет рассматривать ее, как два отдельных слова. Если бы мы отвели для исходного вектора две 16-битовые ячейки, например

old_08_offs dw 0;Для смещения old_08_seg dw 0;Для сегментного адреса

то к ним можно было бы обращаться без всяких описателей.

Сохранив исходный вектор, можно установить в нем адрес нашего обработчика. Для установки вектора в DOS предусмотрена функция 25h. Она требует указания номера устанавливаемого вектора в регистре AL, a



Глава 3


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



 


 


его полного адреса — в паре регистров DS:DX. Здесь нас подстерегает неприятность. Занести в регистр DX смещение нашего обработчика new_08 не составляет труда, это делается командой

mov DX,ofTset new_08;Смещение нашего обработчика

Однако регистр DS у нас занят — в нем хранится сегментный адрес сегмента данных. Придется на какое-то время сохранить этот адрес, для чего удобнее всего воспользоваться стеком. Откуда взять сегментный ад­рес обработчика' Между прочим, в языке ассемблера существует специ­альная конструкция, позволяющая определить сегментный адрес любого поля. В нашем случае она выглядела бы таким образом:

mov AX,seg new_08 mov DS.AX

; Получим сегмент с процедурой new_08;Псрешлем его в DS

В примере 3-3 использован другой прием — содержимое CS отправля­ется в стек и тут же извлекается оттуда в регистр DS:

push CS pop DS

После возврата из DOS надо не забыть восстановить исходное содер­жимое DS, сохраненное в стеке. Инициализация обработчика прерыва­ний закончена. Начиная с этого момента, каждый сигнал таймера будет приводить к прерыванию продолжающейся основной программы и пере­даче управления на процедуру new_08.

Перед завершением программы необходимо поместить в вектор 8 адрес исходного, системного обработчика, который был сохранен в двухсловном поле old_08. Перед вызовом функции 25U установки вектора в регистры DS:DX надо занести содержимое этого двухсловного поля. Эту операцию можно выполнить одной командой Ids, если указать в качестве ее первого операнда регистр DX, а в качестве второго — адрес двухсловной ячейки, в нашем случае old_08. Именно имея в виду использование этой команды, мы и объявили поле для хранения вектора двухсловным, отчего возникли некоторые трудности при его заполнении командами mov. Если бы мы ис­пользовали второй предложенный выше вариант и отвели для хранения вектора две однословные ячейки (old_08_pfls и old_08_scg), то команду Ids пришлось бы снабдить описателем изменения размера ячейки:

Ids DX.dword ptr old_08_offs

Между прочим, здесь так же разрушается содержимое DS, но поскольку сразу же вслед за функцией 25h вызывается функция 4Ch завершения программы, это не имеет значения.

Последнее, что нам осталось рассмотреть — это стандартные действия по завершению самого обработчика прерываний. Выше уже говорилось, что последней командой обработчика должна быть команда irct, возвра­щающая управление в прерванную программу. Однако перед ней необхо­димо выполнить еще одно обязательное действие — послать в контроллер


прерываний команду конца прерываний. Дело в том, что контроллер пре­рываний, передав в процессор сигнал прерывания INT, блокирует внут­ри себя линии прерываний, начиная с той, которая вызвала данное пре­рывание, и до последней в порядке возрастания номеров IRQ. Таким об­разом, прерывание, пришедшее, например, по линии IRQ 6 (гибкий диск) заблокирует дальнейшую обработку прерываний по линиям 6 и 7, а пре­рывание от таймера (IRQO) блокирует вообще все прерывания (IRQO...IRQ7, а также и IRQ8...IRQ15, поскольку все они являются раз­ветвлением уровня IRQ2, см. гл. 1, рис. 1.11). Любой обработчик аппарат­ного прерывания обязан перед своим завершением снять блокировку в контроллере прерываний, иначе вся система прерываний выйдет из строя. Снятие блокировки осуществляется посылкой команды с кодом 20h в один из двух портов, закрепленных за контроллером прерываний., Для ве­дущего контроллера эта команда посылается в порт 20h, для ведомого — в порт AOh. Таким образом, если бы мы обрабатывали прерывания от часов реального времени (линия прерываний IRQ8, вектор 70h, ведомый контроллер), то команда конца прерывания выглядела бы так:

mov AL,20h;Команда конца прерывания

out AOh,AL;Пошлем ее в порт ведомого;контроллера

Указанную последовательность команд иногда называют приказом, или командой EOI (от end of interrupt, конец прерывания).

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

Пусть наш обработчик в ответ на каждое прерывание от таймера вы­водит на экран какой-нибудь символ. Для этого можно воспользоваться функцией OEU прерывания BIOS 10h. Это прерывание обслуживает боль­шое количество различных функций, обеспечивающих управление экра­ном. Сюда входят функции вывода символов и строк, настройки режимов видеосистемы, загрузки нестандартных таблиц символов и многие другие. Функция OEh предназначена для вывода на экран отдельных символов. Она требует указания в регистре AL кода выводимого символа. Процедура new_08 будет выглядеть в этом случае следующим образом:

;Обработчик прерываний для примера 3-3

new_08 proc
push AX
mov AH.OEh
mov AL,'@'
hit lOh
mov AL,20h
out 20h,AL

;Сохраним исходное значение АХ;Функция вывода символа;Выводимый символ;Переход в BIOS разблокировка прерываний;в контроллере прерываний



Глава 3


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



 


 


pop AX iret. new_08 eudp

восстановим АХ

;Возврат в прерванную программу

Что же касается основной программы, то самое простое включить в нее (после завершения действий по инициализации обработчика преры­ваний) функцию DOS Olh ожидания ввода с клавиатуры:

mov int

AH,01h 2 Hi

В результате программа, дойдя до этих строк, остановится (фактически будет выполняться цикл опроса клавиатуры в ожидании нажатия клави­ши, включенный в состав программы реализации функции Olh DOS), а на экран непрерывной чередой будут выводиться символы коммерческого at (рис. 3.5). После нажатия на любую клавишу программа завершится.

FACUBRENT>p

Рис. 3.5. Вывод программы 3-3., ч;

Приведенный пример позволяет обсудить чрезвычайно важный вопрос о взаимодействии обработчиков аппаратных прерываний с прерываемой программой и операционной системой. Особенностью аппаратных преры­ваний является то, что они могут возникнуть в любой момент времени и, соответственно, прервать выполняемую программу в любой точке. Текущая программа, разумеется, использует регистры, как общего назначения, так и сегментные. Если в обработчике прерывания мы разрушим содержимое хотя бы одного из регистров процессора, прерванная программа по мень­шей мере продолжит свое выполнение неправильным образом, а скорее всего произойдет зависание системы. Поэтому в любом обработчике аппа­ратных прерываний необходимо в самом его начале сохранить все регист­ры, которые будут использоваться в программе обработчика, а перед за­вершением обработчика (перед командой iret) восстановить их. Регистры, которые обработчиком не используются, сохранять не обязательно.

В нашем простом обработчике используется толь'ко один регистр АХ. Его мы и сохраняем в стеке первой же командой push AX, восстанавли­вая в самом конце обработчика командой pop AX.

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


:рвем выполнение системной функции на полпути, и начнем выпол-|нять ту же самую или даже другую функцию с начала, произойдет разру-хение системы, которая не предусматривает такое «вложенное» выпол-|нение своих программ. В настоящее время разработаны программные при-|емы, позволяющие эффективно обойти указанный запрет, однако ^использование их в программе драматически увеличивает ее сложность и |объем, и рассматривать эти приемы мы здесь не будем.

В нашем случае дело усугубляется тем, что прерывания от таймера не |только могут придти в тот момент, когда выполняется функция DOS, но f и неминуемо приходят только в такие моменты, так как мы остановили ^•программу с помощью вызова функции Olh прерывания 21U и, следова-|тельно, все время, пока наша программа ждет нажатия клавиши, в дей-|ствительности выполняются внутренние программы DOS. Именно поэто-мы отказались от использования в обработчике прерывания функции и выводим на экран символы с помощью прерывания BIOS. Выпол­нение функции BIOS «на фоне» DOS не так опасно. Надо только следить тем, чтобы наше прерывание BIOS в обработчике не оказалось вложен­ным в такое же прерывание BIOS в прерываемой программе.

Рассмотренный пример имеет существенный недостаток. Записав в век­тор прерываний 8 адрес нашего обработчика, мы затерли исходное содер­жимое вектора и тем самым ликвидировали (в логическом плане) исход­ный, системный обработчик. Практически это приведет к тому, что на вре­мя работы нашей программы остановятся системные часы, и если в системе есть какие-то другие программы, использующие прерывания от таймера, они перестанут работать должным образом. Ликвидировать указанный не­достаток очень просто: надо «сцепить» наш обработчик с системным так, чтобы в ответ на каждый сигнат прерывания активизировались последова­тельно оба обработчика. Рассмотрим методику сцепления обработчиков.

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

;Сцспление прикладного обработчика с системным

;для программы 3-3 new_08 proc pushf call CS:old 08

;Отправляем в стек слово флагов

;В системный обработчик

;Продолжение программы обработчика

cndp

iret new 08

Как будет работать такая программа' После того, как процессор вы-юлнит процедуру прерывания, в стеке прерванного процесса оказывают-три слова: слово флагов, а также двухсловный адрес возврата в пре­рванную программу (рис.3.6, нижние три слова стека).


 

Глава 3

       
  IP2   >От команды
  CS2   call CS:old OS
  Флаги < — От команды pushf
  IP1    
  CS1   Заполнено процессором > при выполнении процедуры
  Флаги    

Рис. 3.6. Стек прерванной программы в процессе выполнения прикладного обработчика прерываний.

CS1 — сегментный адрес прерванного процесса;

fP! — смещение точки возврата в прерванную программу;

CS2 — сегментный адрес прикладного обработчика;

IP2 — смещение точки возврата в прикладной обработчик.

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

Первая команда нашего обработчика pushf засылает в стек еще раз слово флагов, а команда дальнего вызова процедуры call cs:old_08 (где ячейка old_08 объявлена с помощью оператора dd двойным словом) в процессе передачи управления системному обработчику помещает в стек двухсловный адрес возврата на следующую команду прикладного обра­ботчика. В результате в стеке формируется трехсловная структура, которая нужна команде iret.

Системный обработчик, закончив обработку данного прерывания, завершается командой iret. Эта команда забирает из стека три верхние слова и осуществляет переход по адресу CS2:IP2, т.е. на продолжение при­кладного обработчика.

Завершающая команда нашего обработчика iret снимает со стека три верхних слова и передает управление по адресу CS1:IP1.

Описанная методика сцепления прикладного обработчика с систем­ным используется чрезвычайно широко и носит специальное название перехвата прерывания.

Обработчики программных прерываний

Программные прерывания вызываются командой int, операндом ко­торой служит номер вектора с адресом обработчика данного прерывания. Команда inl используется прежде всего, как стандартный механизм вызо­ва системных средств. Так, команда int 21h позволяет обратиться к много­численным функциям DOS, а команды int LOh, int 13h или hit 16h — к


 

 

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

группам функций BIOS, отвечающим за управление теми или иными ап­паратными средствами компьютера. В этих случаях обработчики прерыва­ний представляют собой готовые системные программы, и в задачу про­граммиста входит только вызов требуемого программного средства' с по­мощью команды int с подходящим номером.

В некоторых специальных случаях, однако, программисту приходится писать собственный обработчик прерывания, которое уже обслуживается системой. Таким образом, например, осуществляется управление рези­дентными программами, которые для связи с внешним миром обычно используют прерывание 2FU. В каждой резидентной программе имеется собственный обработчик этого прерывания, который, выполнив свою долю действий, передает управление «предыдущему», адрес которого находил­ся ранее в векторе 2FU, и был сохранен обработчиком в своих полях дан­ных. Другой пример — перехват прерываний BIOS в обработчиках аппа­ратных прерываний с целью обнаружения моментов времени, когда ни одна из наличных программ не использует данное прерывание и, следова­тельно, сам обработчик может им воспользоваться.

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

|"торый, таким образом, становится резидентной программой общего

^пользования.

Резидентные программы

Большой класс программ, обеспечивающих функционирование вычис­лительной системы (драйверы устройств, оболочки DOS, русификаторы, интерактивные справочники и др.), должны постоянно находиться в памя­ти и мгновенно реагировать на запросы пользователя, или на какие-то со­бытия, происходящие в вычислительной системе. Такие программы носят названия программ, резидентных в памяти (Terminate and Stay Resident, TSR), или просто резидентных программ. Сделать резидентной можно как программу типа.СОМ, так и программу типа.ЕХЕ, однако поскольку ре­зидентная программа должна быть максимально компактной, чаще всего в качестве резидентных используют программы типа.СОМ.

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

При первом вызове программа загружается в память целиком и управ­ление передается секции инициализации, которая заполняет или моди­фицирует векторы прерываний, настраивает программу на конкретные условия работы (возможно, исходя из параметров, переданных програм­ме при се вызове) и с помощью прерывания DOS Int 211i с функцией 31h завершает программу, оставляя в памяти ее резидентную часть. Размер резидентной части программы (в параграфах) передается DOS в регистре DX. Указывать при этом сегментный адрес программы нет необходимое-



Глава 3


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



 


;Функция «завершить и;оставить в памяти»
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). Для программ типа.СОМ эта точка входа должна соот­ветствовать самой первой строке программы, идущей вслед за префиксом программы. Поскольку при загрузке программы должна выполниться ее


 
 

Глава 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 не сохраняется. Это, разумеется, очень плохо, так как лишает нас возможности этот вектор восстановить. С дру­гой стороны, восстанавливать перехваченные векторы надлежит при за­вершении программы, а применительно к резидентной программе — при се выгрузке из памяти. Однако в нашей простой программе не предусмот­рено средств выгрузки (процедура выгрузки довольно сложна), и про­грамме придется находиться в памяти до перезагрузки машины.



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: