Методическое руководство к курсовой работе по дисциплине Assembler ibm pc содержание

Вид материалаРуководство

Содержание


Proc resident
Proc new_61h
Endp new_61h ;Процедура bin_decASCII для преобразования «Двоичный код -> десятичное ASCII-число» Proc bin_decASCII
Endp bin_decASCII Endp resident ;Секция инициализации резидента. Proc init
Endp init
Int 2Fh: мультиплексное прерывание.
C0h – FFh отводится для использования в прикладных программах
Подобный материал:
1   2   3   4   5   6   7   8   9
^

Proc resident


jmp init

;Поле данных резидентной части

old_61h dd 0 ;Двухсловная ячейка для хранения адреса старого вектора.

;Для данного вектора это скорее дань принятой форме построения программы, так как данный адрес

;вектора является свободным
^

Proc new_61h


pusha ;Сохраним общие регистры и сегментный регистр DS

push ds ;в том числе

mov ds,ax ;Восстановим значения DS из тестовой программы

mov ax,bp ;Двоичный код для преобразования поместим в AX

Call bin_decASCII ;Процедура преобразования двоичного кода из регистра AX в

;десятичный ASCII- формат с записью в буфер по адресу DS:BX

pop ds ;Восстановим регистры

popa

iret
^

Endp new_61h


;Процедура bin_decASCII для преобразования «Двоичный код -> десятичное ASCII-число»

Proc bin_decASCII


push ax ;Сохраним знак преобразуемого числа

mov cx,6 ;Число байт буфера

L1: mov [byte bx],' ' ;Заполним буфер пробелами

inc bx

loop L1

dec bx ;Установим адрес последнего элемента буфера

mov si,10 ;Основание системы счисления

or ax,ax ;Определим знак числа

jns convert ;Перейдём к преобразованию, если SF=0

neg ax ;Иначе изменим знак числа

convert: xor dx,dx

div si ;ax=quot(dx:ax/10), dx=rem(dx:ax/10)

add dl,'0' ;Сформируем ASCII-цифру

mov [byte bx],dl ;Занесём в буфер

dec bx ;Движение назад

or ax,ax ;Преобразование закончено

jnz convert ;Нет, так как АХ≠0

pop ax ;Да

or ax,ax ;Проверим знак числа

jns end_convert ;Конец преобразованию, если число положительное

dec bx

mov [byte bx],'-' ;Запись знака

end_convert: ret
^

Endp bin_decASCII

Endp resident


;Секция инициализации резидента.

Proc init


mov ax,3561h ;Чтение и сохранение вектора 61h. AL=номер вектора

int 21h

mov [word cs:old_61h],bx ;bx=offset вектора 61h

mov [word cs:old_61h+2],es ;es=segment вектора 61h

;Установка обработчика 61h функцией DOS 25h. Адрес обработчика должен быть в DS:DX.

;Изначально в COM-программах выполняется CS=DS

mov ax,2561h ;Al=номер вектора

mov dx,offset new_61h

int 21h

mov ah,09h

mov dx,offset msg

int 21h

;Завершим программу, оставив её резидентной в памяти прерыванием Int 27h.

mov ah,27h

mov dx,[cs:init] ;DX - адрес первого байта за резидентной частью программы,

;включая PSP, в параграфах

int 21h ;Оставить резидентной
^

Endp init


;Поле данных нерезидентной части

msg DB 'Резидент загружен',13,10,'$'

End resident ;Конец программы/точка входа


Prg5_test. Тестовая задача для проверки работоспособности резидентной программы Prg5_res

;Тестовая программа передаёт управление резиденту командой int 61h, предварительно загрузив в

;регистр BP 16-разр. двоичное число для преобразования его в десятичное, а в регистры AX:BX-

;полный адрес (seg:offset) буфера результата преобразования. Вывод на экран строки string с

;десятичным числом, находящимся в буфере buff, осуществляется функцией DOS 09h. В строку

;вывода string для большей наглядности введены управляющие коды ANSI- драйвера для управления

;курсором и цветом символов

Ideal

Model small

stack 256

Dataseg

;Поле данных программы с применением EXC- последовательности

string DB 27,'[2J',27,'[31;47m' ;Очистка экрана и задание цвета (красные

;символы на белом фоне)

DB 27,'[12;30H',201,8 DUP(205),187 ;Позиционирование (12 -я строка,

;30-й столбец) и символы

DB 27,'[13;30H',186,32 ;Позиционирование и символы

buff DB 6 DUP(' '),32,186 ;Буфер, заполненный пробелами и символы

DB 27,'[14;30H',200,8 DUP(205),188 ;Позиционирование и символы

DB 27,'[0m',27,'[15;30H','$' ;Отмена цвета и позиционирование

Codeseg

start: mov ax,@data

mov ds,ax

mov bx,offset buff ;Смещение буфера результата

mov bp,8000h ;Исходное число (максимальное отрицательное) для

;преобразования резидентом

int 61h ;Вызов резидента, с параметрами в регистрах ax=ds,

;bx=смещение буфера, bp=число для преобразования.

;Вывод на экран результата преобразования, сформированного резидентом

mov ah,09h

mov dx,offset string

int 21h

mov ax,4C00h ;Завершим тестовую программу

int 21h

End start ;Конец программы/точка входа

10. Недостатки рассмотренного подхода построения резидентных программ и возможные пути их преодоления.

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

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

Наиболее распространённым способом защиты резидентной программы от повторной установки, является использование специально введённое мультиплексное прерывание 2Fh (в данной работе рассматривается способ, который пропагандируется в последних своих работах профессором Финогеновым К. Г. [1, 3, 8]).

^ I
nt 2Fh: мультиплексное прерывание.


Ввод: AH = функция прерывания или идентификатор программы (от 00h доFFh),

00h – 7Fh зарезервировано для DOS/Windows

B8h – BFh зарезервировано для сетевых функций,

^ C0h – FFh отводится для использования в прикладных программах,

AL = подфункция с кодом 00h – проверка наличия программы в памяти,

остальные коды – свои для каждой функции,

BX, CX ,DX=00h (если через эти регистры происходит возврат заранее

обусловленных кодов)

Возврат: если при вызове прерывания Int 2Fh из инициализационной части резидентной программы (AH –принятый идентификатор программы, а AL=00h), происходит возврат в регистре AL значения FFh, то обработчиком обнаружено в памяти установленная ранее копия программы с “нашим” идентификатором. Возврат же с AL=00h – её отсутствие (см. рис. 6). В системе может быть установлено несколько программ, использующих мультиплексное прерывание 2Fh, поэтому, если обработчик обнаружил в регистре AH “чужую” функцию, то он должен командой

Jmp [dword cs:old_2Fh]

передать управление по цепочке тому обработчику, адрес которого был ранее в векторе 2Fh. В результате вызов int 2Fh из любой программы будет проходить по цепочке через все загруженные резидентные программы, пока не достигнет “своей” (AL=FFh), или при её отсутствии, вернёт управление в вызвавшую программу (инициализационную часть) c AL=00h. Дальнейшие действия на этапе инициализации резидентной программы вполне определены. Если обработчик 2Fh вернул в регистре AL значение FFh, то программа должна вывести предупреждающее значение типа “Попытка вторичной установки. Установка отменена” и перейти на завершения программы функцией 4Ch без выполнения процедуры по установке программы в качестве резидентной. Возврат же AL=00h даёт разрешение на установку программы в памяти.

В DOS отсутствуют средства выгрузки резидентных программ. Единственный способ – перезагрузка компьютера.. Выгрузку резидентной программы из памяти можно осуществить разными способами и сводятся в любом случае к освобождению блоков памяти, занимаемых программой (например, с помощью функции DOS 49h). Однако перед освобождением памяти необходимо восстановить векторы прерываний, перехваченные программой. Это очень сложная задача, если действовать с помощью некоторой внешней программы (по отношению к резидентной), т. к. неизвестны адреса ячеек памяти, куда спрятала их резидентная программа в процессе её инициализации. Поэтому возможность выгрузки резидентной программы обычно предусматривается из неё самой на этапе её разработки. С другой стороны, если выгрузка резидентной программы осуществляется из неё самой, то восстановление старых векторов возможно лишь в том случае, когда не произошло вторичного перехвата векторов другой резидентной программой. В силу этого, надёжно можно выгрузить лишь последнюю из загруженных резидентных программ.

Будем использовать в качестве выгружающей программы её вторую копию, которая будет запускаться командой с клавиатуры, содержащей дополнительную опцию, означающей приказ о выгрузке из памяти первой копии. Однако для этого необходимо изменить инсталляционную часть программы. Эта часть программы должна будет анализировать наличие введённой опции и при её обнаружении через посредство мультиплексного прерывания 2Fh передать в резидентную программу признак о выгрузке. Обычно это осуществляется путём занесения в регистр AL значения 01h. Итак, примем в дальнейшем, что подфункция AL=00h прерывания 2Fh служит для проверки на повторную установку, а подфункция AL=01h – для выгрузки. Выгрузку резидентной программы из памяти будем осуществлять путём освобождения блоков памяти, занимаемых программой, с помощью функции DOS 49h. Изложенные выше способ защиты программы от повторной установки и возможностью её выгрузки из памяти, рассмотрим на примере программы Prg63.

Prg6. Резидентная программа типа .COM, активизирующаяся нажатием клавиши "серый плюс", выводит на экран время системного таймера (функция DOS 2Ch). Программа защищена от повторной установки и может быть выгружена командой с клавиатуры (опция выгрузки off)

IDEAL

MODEL tiny

p486n

CODESEG

org 100h