Всё таки хотел бы разобраться с этим вопросом
При создании своих обработчиков, нужно придерживаться основного правила - всегда возвращать управление оригин.обработчику. При работе с таймером это особо критично, т.к. его может использовать не только сама ОС, но и чипсет мат.платы (учитывая, что это прерывание биос, а не дос). Работу с таблицой векторов прерываний IVT (Interrupt Vector Table) лучше доверить спец.функциям сервиса MS-DOS: AH=35h
читает оригин.вектор из IVT в регистры ES:BX
, а AH=25h
записывает в IVT адрес нового обработчика из пары DS:DX
.
Непосредственно свой обработчик можно оформить двумя способами:
- Дать отработать оригин.обработчику, после чего принять от него управление. Это наиболее правильный способ перехвата прерываний.
- Перехватить управление первым, после чего обязательно возвратить бразды оригин.обработчику.
В случае перехвата системного таймера, длительность работы нашего обработчика не должна превышать одного тика, т.е. 18/60=0,3 сек
. Иначе вся система начнёт тормозить, и может даже зависнуть. Вектор(08h) таймера который вы перехватываете в своём примере, по цепочке возвращает управление в int-1Ch
. Поэтому когда программам требуется таймер, то в доках по MS-DOS советуют перехватывать именно вектор(1Ch), не трогая при этом int-08h
.
В примере ниже именно такой алгоритм. Здесь, приняв управление, наш обработчик сразу возвращает его по оригин.вектору. Когда системный отработает, то своей инструкцией IRET
сам возвратит нам руль (не тестировалось, могут быть ошибки):
;// fasm-code
;//--------------
org 100h
jmp Initialize
oldHandler dw 0,0 ;// под оригин.вектор
Initialize:
push es ;// AH=35h портит регистр ES
mov ax,351Ch ;// AH = функция, AL = вектор
int 21h ;// копируем оригин.вектор из IVT.
mov [oldHandler],bx ;// BX = смещение
mov [oldHandler+2],es ;// ES = сегмент оригин.обработчика
pop es
mov ax,251Ch ;// AH=25h записывает новый вектор в IVT
mov dx,newHandler ;// DS:DX = указатель на наш обработчик
int 21h
align 16 ;// выравнить наш обработчик на границу параграфа памяти
newHandler:
pushf ;// имитация инструкции INT
call dword[oldHandler] ;// сразу возвращаем управление оригин.обработчику!
call @f ;// после IRET оригин.обработчика попадаем сюда..
db 'Hello World!$' ;// строка для вывода
@@:
pop dx ;// DX = адрес строки
mov ah,9 ;// AH = печать
int 21h
mov ah,0Bh ;// проверить буфер клавиатуры
int 21h ;//
or al,al ;// если была нажата любая клавиша,
jnz @exit ;// то на выход!
iret ;// иначе, конец обработчика.
@exit:
mov ax,251Ch ;// восстановить оригин.вектор в IVT
mov dx,[oldHandler] ;// DS:DX = сохранённый вектор
mov bx,[oldHandler+2]
mov ds,bx
int 21h
int 20h
Почитать по теме: Зубков - "Ассемблер для Windows, DOS, Linux" (глава 5.8.1)
https://lshoshia.science.tsu.ge/assembler.pdf