Изучение принципов работы с прерываниями в DOS, страница 2

Листинг 3. Текст программы PR_2.8 (окончание)

Выводы:

            Данная программа заменяет стандартный обработчик прерывания int 0. При ее запуске на экран выдается надпись “'Warning: деление на ноль”. Вектор успешно сохраняется, о чем свидетельствует успешный запуск первой программы (инициирование деления на ноль).

         При попадании в прерывание, в стек заносятся последовательно флаги, CS и IP. IP (instruction Pointer) указывает на месторасположение команды, вызвавшей прерывание. В нашем обработчике мы извлекаем это значение из стека и увеличиваем на 4. Затем снова заносим в стек и выходим из прерывания. Это сделано потому, что команда деления в данном случае занимает 4 байта, и если мы укажем значение меньше 4, то попадем в зону неопределенности для нас (в середину выполнения команды деления, например), но на вполне осознанную часть для процессора, который наверняка посчитает оставшиеся до 4 байты как коды команд и непременно их выполнит. По этой же причине опасно задавать значение, большее 4.

4.  Модификация программы

Задание:

Преобразуйте  вашу программу так, чтобы не применять функции DOS для получения и установки вектора прерываний int 0

print   macro

        push    ax, dx

        lea     dx, #1

        mov     ah, 9

        int     021

        pop     dx, ax

#em

        jmp     start

_error  db      'Warning: деление на ноль', 13, 10, '$'

n_vect  equ     0

old_v     dd      ?

start:

            lea ax, new                             ;установка нового вектора

            mov dx, cs                             ;сохранение старого

            mov es, 0

            es xchg w [n_vect*4], ax

            es xchg w [n_vect*4+2], dx

            mov     w old_v, ax

            mov     w old_v + 2, dx          

            mov al, 11

            mov bl, 0

            div bl

            mov ax, w old_v                                ;восстановление страрого вектора

            mov dx, w old_v+2

            es mov [n_vect*4], ax

            es mov [n_vect*4+2], dx

            int     020                                ;выход

new:   

            print     _error

            pop ax

            add ax, 2

            push ax

            iret

Листинг 4. Текст программы PR_3.8

Выводы:

Данная программа реализована без использования стандартных функций DOS для получения и установке вектора int 0. Как видно по обработчику прерывания, указатель смещается на 2 байта. И действительно, в этом случае команда деления занимает 2 байта.

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


5.  Передача управления обработчику BIOS

Задание:

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

print   macro

        push    ax, dx

        lea     dx, #1

        mov     ah, 9

        int     021

        pop     dx, ax

#em

        jmp     start

_error  db      'Warning: деление на ноль', 13, 10, '$'

_msg     db           'Все правильно))',13,10,'$'

n_vect  equ     0

old_v        dd         ?

start:

                mov        ax, 035 by n_vect               ;сохранение старого вектора

                int           021                                        ;es:bx

                mov        w old_v, bx

                mov        w old_v + 2, es   

                mov        ax, 025 by n_vect               ;установка нового вектора

                lea          dx, new                                 ;ds:dx

                int           021

                mov ax, 11

                mov bl, 0

                div bl

norm_exit:

                mov        ax, 025 by n_vect               ;восстановление вектора

                mov dx, w old_v                                 ;ds:dx

                mov ds, w old_v+2

                int 021

                mov ds, cs                                           ;восстановление ds

                print _msg

                int     020                                              ;выход

new:      

                print _error

                mov ax, 025 by n_vect

                mov dx,w old_v

                mov ds,w old_v+2

                int 021

                mov ds,cs

                jmp old_v