Листинг 3-13. REMOVE - удаление резидентной подпрограммы,
вставленной в качестве "заплаты" в вектор
прерывания
----------------------------------------------------------------
PAGE 60,132
;===== REMOVE - Этот файл генерирует программу типа .COM =======
;===== Удаление резидентной подпрограммы, вставленной в ка- ====
;============ честве "заплаты" в вектор прерывания =============
;(Interrupt Service Routine (ISR) - это подпрограмма обслужива-
; ния прерывания))
OLD_IP EQU -4 ; Возможное положение IP в ISR
OLD_CS EQU -2 ; Возможное положение CS в ISR
ID EQU 0 ; Положение 1-го байта в ISR
IRETOP EQU 0CFh ; Код операции IRET
;
;===== МАКРООПРЕДЕЛЕНИЯ ДЛЯ УТИЛИТ =============================
;
INCLUDE STDMAC.INC ; Включение макроопределений
;
remove SEGMENT
ASSUME cs:remove
ASSUME ds:remove
; Определение необходимых адресов внутри сегмента программого
; префикса (PSP)
ORG 2Ch
env_adr LABEL WORD ; Адрес указателя среды
ORG 80h
cmd_len db ? ; Длина командной строки
new_len db ? ; Длина строки буферизованного чтения
cmd_buf db ? ; Строка командной строки
;===== НАЧАЛО ПРОГРАММНОГО КОДА ================================
ORG 0100h
main PROC FAR
start:
mov ch,byte ptr [cmd_len]
cmp ch,0 ; аргумент обеспечен ?
jnz have_cmd
; Аргумент не обеспечен - приглашение пользователя для указания
get_cmd:
@DisStr request ; приглашение для номера вектора
mov byte ptr [cmd_len],80
mov dx,offset cmd_len
mov ah,0Ah ; выполнение буферизованного чтения в
@DosCall ; буфер командной строки
@DisChr LF ; новая строка
mov ch,new_len ; получение размера введенного текста
cmp ch,0 ; просмотр, ответил ли пользователь?
jz abort ; если нет, то предполагается выход
inc ch ; установка ответа для приведения в
; соответствие
have_cmd:
cmp ch,3 ; проверка для правильного # символов
je ok_cmd
@DisStr bad_cmd ; если ошибка, то некорректный флажок
abort: jmp finis
ok_cmd: mov bx,offset cmd_buf
mov ch,2 ; грамматический разбор 2 символов
call get_hex ; преобразование # в буфер в двоичн.
jc abort ; выход, если ошибка преобразования
mov vec_num,al ; сохранение адреса вектора
mov ah,35h ; получение указателя вектора из MS-DOS
@DosCall
mov vec_ip,bx ; сохранение IP вектора
mov al,vec_num ; восстановление номера вектора
call show_vector ; отображение содержимого вектора
@DisStr askresv
call yesno
jc no_restore ; нельзя желать восстановить вектор
;
; ВОССТАНОВЛЕНИЕ ВЕКТОРА ПО АДРЕСУ В ПОДПРОГРАММЕ
mov bx,vec_ip ; получение адреса подпрограммы
mov dx,es:OLD_IP[bx] ; получение IP старого вектора
mov cx,es:OLD_CS[bx] ; получение CS старого вектора
mov al,vec_num ; получение номера вектора
push ds ; сохранение текущего DS
mov ds,cx ; установка назначения вектора
mov ah,25h ; установка адреса вектора
@DosCall
pop ds ; восстановление сегмента данных
;
; Отображение адреса среды и выдача приглашения для удаления.
; Адрес среды будет действительным, если это программа типа .COM
no_restore:
@DisStr askremb ; отображение адреса среды
mov ax,es:env_adr ; получение адреса среды
mov ch,4
call bin2hex ; отображение возможного сегмента среды
@DisStr ip0
call yesno
jc no_env ; обход удаления среды
;
; УДАЛЕНИЕ БЛОКА СРЕДЫ
push es ; сохранение сегмента главной подпрограммы
mov cx,es:env_adr ; получение адреса среды
mov es,cx ; и подготовка к удалению
call rem_mem ; попытка удалить блок
pop es ; восстановление адреса главной подпрограммы
;
; Отображение адреса сегмента главной подпрограммы и выдача
; приглашения для его удаления
no_env:
@DisStr askremm ; отображение адреса главного блока
mov ax,es ; адрес главного блока
mov ch,4
call bin2hex
@DisStr ip0
call yesno
jc finis ; нельзя желать удаления главного блока
;
; УДАЛЕНИЕ ГЛАВНОГО БЛОКА ПАМЯТИ РЕЗИДЕНТНОЙ ПОДПРОГРАММЫ
call rem_mem ; попытка удаления блока
;
finis: mov ax,4C00h ; завершение программы
@DosCall
;
vec_num db ? ; память для запоминания номера вектора
vec_ip dw ? ; память для запоминания IP вектора
; Номер удаляемого вектора
request db 'Vector number to remove: $'
; Аварийное завершение из-за ошибки в командной строке
bad_cmd db 'Command Line format error - aborting',CR,LF,'$'
; Восстановить вектор из старого ?
askresv db 'Restore Vector from Old? $'
; Удаление блока среды
askremb db 'Remove Environment Block: $'
; Удаление блока главной программы
askremm db 'Remove Main Program Block: $'
ip0 db ':0000 $'
;
main ENDP
;
; == REM_MEM использует функцию 49 (шестн.) MS-DOS для попытки =
; ======= перераспределения блока памяти, адресуемого ES =======
;
rem_mem PROC NEAR
push ax ; сохранение регистров
push cx ; используемых
push dx ; @DisStr и @Dischr
mov ah,49h ; освобождение распределенной памяти
@DosCall
jnc free_ok ; нет ошибок - выдача сообщения об успехе
push ax ; сохранение кода ошибки
@DisStr fail ; информирование о сбое
pop ax ; и выдача кода ошибки
mov ch,4 ; (все 4 цифры)
call bin2hex
@DisChr CR
@DisChr LF
jmp rem_exit
free_ok:
@DisStr pass
rem_exit:
pop dx ; восстановление регистров
pop cx
pop ax
ret
; Успешное освобождение распределенной памяти
pass db 'Successful Free Allocated Memory',CR,LF,'$'
; Сбой при освобождении распределенной памяти - код ошибки
fail db 'Failed to Free Allocated Memory - Error Code: $'
rem_mem ENDP
;
; ===== YESNO приглашает пользователя ответить либо Y, либо N. =
; ===== Если введено Y (да), то YESNO возвращает без переноса ==
; ===== (NC). Если введено N (нет) или , то YESNO возвра- =
; ===== щает с переносом (CY). =================================
yesno PROC NEAR
push ax
push dx
@DisStr prompt ; приглашение пользователя для ввода
retry: mov ah,08h ; получение ответа (no echo - нет эха)
@DosCall
@Case al,<'y','Y','n','N',CR>,
@DisChr 07h ; неправильный ответ - гудок
jmp retry ; и ожидание нового ответа
no: @DisStr 'N'
stc
jmp yn_exit
yes: @DisChr 'Y'
clc ; очистка переноса
yn_exit:
@DisChr CR
@DisChr LF
pop dx
pop ax
ret
prompt db ' (Y/N): $',
yesno ENDP
;
; ===== SHOW_VECTOR отображает содержимое отмеченных ячеек =====
; ===== в ES:BX в шестнадцатиричном формате и в формате ASCII. =
; ===== Так как это используется внутри отображения вектора, ===
; ===== то она также показывает AL в шестнадцатиричном формате =
; ===== как номер вектора, и информирует пользователя, если ===
; ===== в инструкции IRET отмечен первый байт. =================
; ===== SHOW_VECTOR также отображает два слова, размещенные ====
; ===== перед адресом вектора как CS:IP, в случае если =========
; ===== пользователь запомнил там адрес старого вектора при ====
; ===== установке. =============================================
;
show_vector PROC NEAR
push cx ; сохранение регистров,
push dx ; используемых
push ax ; @DisChr и @DisStr
@DisStr vmsg1 ; начало отображения сообщений
pop ax ; восстановление значения AL
push ax
mov ah,al
mov ch,2 ; отображение двух шестнадц. цифр
call bin2hex
@DisStr vmsg2 ; показ потенциального адреса воосст-я
mov ax,es:OLD_CS[bx] ; получение возможн. значения CS
mov ch,4
call bin2hex ; отображение возможного старого CS
@DisChr ':'
mov ax,es:OLD_IP[bx] ; получение возможн. значения CS
call bin2hex ; отображение возможного старого CS
cmp byte ptr es:ID[bx],IRETOP
jne noiret ; это инструкция IRET?
@DisStr vmsg3
noiret: @DisChr CR
@DisChr LF
mov cl,16 ; дамп 16 байтов
call dump ; показ шестнадц. и ASCII значений
pop ax
pop dx
pop cx
ret
vmsg1 db 'Vector # $'
vmsg2 db ' Old Vector: $'
vmsg3 db 'IRET$'
show_vector ENDP
;
; ===== DUMP отображает содержимое ячеек, отмеченных с помощью =
; ===== ES:BX, в шестнадцатиричном формате и в формате ASCII. ==
; ===== Содержимое CL # отображаемых байтов. ===================
dump PROC NEAR
push ax ; сохранение регистров,
push dx ; используемых
push bx ; @DisChr и @DisStr
push cx
@DisStr dmsg1 ; начало отображения сообщений
mov ch,2 ; 2 шестнадцатиричные цифры на байт
h_dump: mov ah,es:[bx] ; получение байта
jnc bx ; следующий байт
call bin2hex
@DisChr ' '
dec cl ; счетчик цикла - 1
jnz h_dump ; повторение, пока счетчик не станет 0
@DisStr dmsg2 ; следующий раздел
pop cx ; восстановление значений
pop bx ; BX (индекс)
push bx ; и
push cx ; CX (счетчик)
t_dump: mov al,es:[bx] ; получение байта
jnc bx ; следующий байт
cmp al,' ' ; проверка возможного диапазона печати
jb no_prnt ; ? < памяти
cmp al,7Eh ; DEL невозможно напечатать, либо
ja no_print
@DisChr al ; возможно - выполнить так ...
jmp nxt_txt
no_prnt:
@DisChr '.' ; используйте "." для невозможн.печати
nxt_txt:
dec cl ; счетчик цикла - 1
jnz t_dump ; повторение, пока счетчик не станет 0
; Выполнение всех восстановлений и выход
@DisChr CR
@DisChr LF
pop cx ; восстановление регистров
pop bx
pop dx
pop ax
ret
dmsg1 db 'HEX: $'
dmsg2 db ' ASCII: $'
dump ENDP
;
; ===== GET_HEX осуществляет грамматический разбор буфера, =====
; ===== указанного в BX, возвращаемое количество в AX. =========
; ===== # цифр для грамматического разбора содержится в CH, ====
; ===== и BX увеличивается на # обработанных цифр. =============
;
get_hex PROC NEAR
push dx ; сохранение регистра DX
push cx ; сохранение регистра CX
mov ax,0 ; очистка аккумулируемого #
mov dh,0 ; очистка верхней рабочей памяти
mov cl,4 ; установка сдвига счетчика
nxt_digit:
mov dl,[bx] ; получение символа
sub dl,'0'
jb bad_digit ; ? < '0' - неправильно
cmp dl,0Ah
jb ok_digit ; от '0' до '9' - хорошо
sub dl,'A'-'0'
jb bad_digit ; '9' < ? < 'A' - неправильно
add dl,0Ah
cmp dl,10h
jb ok_digit ; от 'A' до 'F' - хорошо
sub dl,'a'-'A'-0Ah
jb bad_digit ; 'F' < ? < 'a' - неправильно
add dl,0Ah
cmp al,10h
jae bad_digit ; 'f' < ? - неправильно
ok_digit:
add ax,dx ; аккумулирование цифр в AX
inc bx ; следующая цифра
dec ch
jnz more_digit ; еще цифры для аккумулирования?
clc ; ошибки нет - очистка CY
pop cx
pop dx
ret
more_digit:
shl ax,cl ; открытие места для следующей цифры
jmp nxt_digit ; цикл для следующей цифры
bad_digit:
@DisStr digit_error ; информирование об ошибке элемента
stc ; ошибка - установка переноса
pop cx
pop dx
ret
; ожидался двухцифровой шестнадцатиричный номер
digit_error db 'A two-digit hex number was expected',CR,LF,'$'
get_hex ENDP
;
; ===== BIN2HEX отображает значение, содержащееся в AX как =====
; ===== шестнадцатиричный #. Регистры не портятся. CH содержит =
; ===== # цифры для отображения, выбираемой слева направо в AX.=
; ===== (AH отображается, если CH равен 2). ====================
;
bin2hex PROC NEAR
push ax ; сохранение всех регистров
push bx
push cx
push dx
mov cl,4 ; установка счетчика чередования
mov bx,ax ; копирование AX для работы
; Начало цикла DIGIT (цифра) для обработки цифр
moredig:
rol bx,cl ; преобразование двоичн.-шестнадцат.
mov al,bl
and al,0Fh
add al,90h
daa
adc al,40h
daa
; Отображение цифры и проверка на последующие цифры - восста-
; новление, если нет
@DisChr al
dec ch
jnz moredig
pop dx
pop cx
pop bx
pop ax
ret
bin2hex ENDP
;
remove ENDS
END start
----------------------------------------------------------------
|