Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm для Windows/Dos > Перехват 16 прерывания


Автор: MarkedOne 13.6.2008, 17:37
Написал программу, котороя перехватывает 16 прерывание, если вызвана функция 10h(ожидание нажатия на любую клавишу), то выводится сообщение и управление передается оригинальному обработчику.
Запустил её, потом нажимаю на любую клавишу и выскакивает ошибка:
Цитата(16-разрядная подсистема MS-DOS)

PROG04.com
Процессор NTVDM обнаружил недопустимую инструкцию.
CS:00a7 IP:0094 OP:2e fe d7 28 2e Дла завершения работы приложения нажмите кнопку "Закрыть".


Вот код:
Код

CSEG segment
org 100h

Start:
    jmp Init

    ;обработчик 16 прерывания
    int_16h proc                  
      ;если 10h функция(ожидание нажатия на любую клавишу), то на метку Ok_10h    
      cmp ah, 10h 
      je Ok_10
      ;Иначе вызываем оригинальный обработчик 
      jmp dword ptr cs:[Old_16h] 
    ok_10:
      ;сохраняем используемые регистры
      push ax 
      push dx
      ;В ds - текущий сегмент
      push cs 
      pop ds
      ;Выводим строку на экран
      mov ah, 9 
      mov dx, offset Wait_Mes
      int 21h
      ;Сохраняем флаги  
      pushf 
      ;Вызываем оригинальный обработчик
      call dword ptr cs:[Old_16h] 
      ;Восстанавливаем регистры  
      pop dx 
      pop ax
      ;Выходим из прерывания
      iret      

     ;адрес оригинального прерывания 
      Old_16h dd ?    
      Wait_Mes db 13, 10, 'Нажмите любую клавишу...$' 

    int_16h endp

Init:
    mov ax, 3516h     
    int 21h
    mov word ptr Old_16h, bx
    mov word ptr Old_16h+2, es

    mov ax, 2516h
    mov dx, offset int_16h
    int 21h

    mov dx, offset init
    int 27h

CSEG ends
end Start



Автор: Akina 13.6.2008, 21:04
Из обработчика 16 прерывания нельзя вызывать прерывания ДОС (за редким исключением, причем функция 9 прерывания 21 в этот список не входит).
Используйте для вывода на экран прерывания БИОС.

Автор: MarkedOne 14.6.2008, 13:00
Цитата(Akina @  13.6.2008,  21:04 Найти цитируемый пост)
 прерывания БИОС

А какое именно?

Автор: MarkedOne 14.6.2008, 14:11
Я немного переделал программу, и теперь 21h прерывание вызывается подругому:
Код

...
      push dx
      push cs
      pop ds
      mov ah, 9
      mov dx, offset Wait_Mes
      pushf
      call dword ptr cs:[int_21h]  ;Вызываем 21h преывание как процедуру
...
      int_21h dd ? 
...
      Wait_Mes db 13, 10, 'Нажмите любую клавишу...$'
...
    mov ax, 3521h  ;Получаем адрес 21h прерывания
    int 21h
    mov word ptr int_21h, bx
    mov word ptr int_21h+2, es
...


Но ошибка всё равно вылетает. И еще, я заметил что если убрать строки:
Код

 push cs
 pop ds

то ошибки нет, но при вызове 10h функции 16h прерывания ничего не выводится. С помощью этих команд я загружаю в cs текущий сегмент, ведь строка находится в том же сегменте что и прерывание!

Автор: Akina 14.6.2008, 20:36
Цитата(MarkedOne @  14.6.2008,  14:00 Найти цитируемый пост)
А какое именно?

Видео, вывод в режиме TTY

Цитата(MarkedOne @  14.6.2008,  15:11 Найти цитируемый пост)
ошибка всё равно вылетает.

т.е. программеры в МС таки не идиоты...

Цитата(MarkedOne @  14.6.2008,  15:11 Найти цитируемый пост)
я заметил что если убрать строки:

А я вообще не понимаю, почему вы присваиваете себе право менять содержимое регистров? После окончания работы обработчика ВСЕ регистры (кроме IP) должны содержать то же, что и до вызова... меняете AX, DX, DS? озаботьтесь восстановить перед выходом.

Автор: MarkedOne 14.6.2008, 21:18
Точно! Я забыл сохранить регистр DS, а остальные сохранил

Добавлено @ 21:26
Теперь всё нормально запускается. Но строка не выводится.
Цитата(Akina @  14.6.2008,  20:36 Найти цитируемый пост)
Видео, вывод в режиме TTY

Вы про функцию 13h 10h-ого прерывания?
Или про прямой вывод, через видеопамять?

Автор: Akina 15.6.2008, 22:32
Цитата(MarkedOne @  14.6.2008,  22:18 Найти цитируемый пост)
Вы про функцию 13h 10h-ого прерывания?

да

Автор: MarkedOne 16.6.2008, 14:48
Спасибо за помощь

Автор: mb78 11.7.2008, 22:48
Вы перепутали! Функция 10h(для DOS) -это видео Bios. А  клавиатура- 16h(32 в 10-тичной системе).
Выясните лучше , 16 или 16h вы хотите перехватить.
Например если 16h-то:
mov AX,16h   если 10h(16)то - mov AX,10h
mov BL,4
mul BL
mov CX,0
mov ES,CX
mov DI,AX
MOV AX,сюда введите строку ,куда перейти, если будет int 16
CLD
STOSW
MOV AX, СЮДА ВВЕДИТЕ СЕГМЕНТ,НА КОТОРЫЙ НУЖНО ПЕРЕЙТИ ,ЕСЛИ ТОТ ЖЕ,ГДЕ САМА ПРОГРАММА,ТО ВВЕДИТЕ CS
STOSW

Все теперь прерывание будет переходить по этому адресу.Можно конечно воспользоваться прерыванием int 21 при ah=25h
для изменения прерывания ,но я это пробовал ,у меня из Windows это не получилось,а когда сделал вручную,то вышло.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)