Форум программистов, компьютерный форум, киберфорум
Assembler: DOS/Real Mode/16-bits
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/29: Рейтинг темы: голосов - 29, средняя оценка - 4.69
1 / 1 / 0
Регистрация: 26.03.2017
Сообщений: 11
TASM

Перехват int 21h

11.12.2019, 19:18. Показов 5644. Ответов 19

Студворк — интернет-сервис помощи студентам
Добрый день. Заменяю обработчик 21-ого прерывания на свое, где я вызываю старый обработчик, однако... Мое "Hi!" он не выводит вообще. Программа виснет.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
.model small
.stack 100h
 
.data
    old21 dw 0,0
    str2 db 'H', 'i', '!', '$'
 
.code
 
New21 proc 
        pushf
        popf
        call word ptr cs:old21
        iret
New21 endp
 
main:  
       mov      ax,@data
       mov      ds,ax
       mov      es,ax
 
       ;save
       mov      ax,3521h
       int      21h
       mov      word ptr old21, bx
       mov      word ptr old21+2, es
       ;install
       mov      ax,2521h
       mov      dx,seg New21
       mov      ds, dx
       mov      dx,offset New21
       int      21h
       ;use
       mov      ah,09h
       lea      dx,str2
       int      21h
       ;restore
       mov      ax,2521h
       mov      dx,seg old21
       mov      ds, dx
       mov      dx,offset old21
       int      21h
       
       MOV      AH, 4Ch
       INT      21h
end main
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
11.12.2019, 19:18
Ответы с готовыми решениями:

Перехват int 21h
Подскажите пожалуйста. Как передать управление оригинальному обработчику 21h? CSEG Segment ASSUME CS:CSEG org 100h begin: ...

Перехват int 21h
com 16 bit .286 ASKII_code_key_check equ 'A' ASKII_code_key equ 'B' number_handler_int21_02h equ 02h ...

Перехват прерывания int 21h
Немного решил поэкспериментировать. Есть два случая для сравнения. Первый случай (работает): CSEG segment assume cs:CSEG,...

19
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406
12.12.2019, 16:01
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    .286
    .model small
    .code
    org 100h
main:   jmp beg
 
; переменные удобнее размещать в cseg, хотя код немного длиннее
; потому что не приходится загружать DS в подпрограмме прерывания
 
old21   label dword ; именно dword, а не word
old21ip dw 0
old21cs dw 0
str2 db "Hi$"
 
New21: 
        pushf      ; вызов old21, не надо делать popf
        call cs:old21
    pushf      ; сохраняем регистры
    push ds
    push es
    pusha
    call mysub ; выполняем свою подпрограмму
    popa       ; восстанавливаем регистры
    pop  es
    pop  ds
    popf
        retf 2     ; завершение retf 2, а не iret
                   ; т к int 21h возвращает Carry Flag
 
mysub: mov ax,0E07h ; bell - пискнуть динамиком
       int 10h
       ret
 
beg:   push cs
       pop  ds
 
       ;save
       mov      ax,3521h
       int      21h
       mov      word ptr old21ip, bx
       mov      word ptr old21cs, es
       ;install
       mov      ax,2521h
       mov      dx,offset New21
       int      21h
       ;use
       mov      ah,09h
       mov      dx,offset str2
       int      21h
       ;restore
       lds      dx,old21 ; спец короткая команда грузит ds и dx
       mov      ax,2521h
       int      21h
       MOV      ax, 4C00h ; программа возвращает код ошибки 0
       INT      21h
end main
2
1 / 1 / 0
Регистрация: 26.03.2017
Сообщений: 11
12.12.2019, 16:51  [ТС]
Работает, большое спасибо, плюс улетел.
0
Прощай, Мир!
 Аватар для proc3nt
1673 / 831 / 253
Регистрация: 26.05.2012
Сообщений: 3,056
12.12.2019, 18:59
qbfan, сегодня прогноз погоды передовал туман.. наверное, я под него попал и заблудился..
вобщем, решил переделать твой код, чтобы обязательно использовался сегмент данных.. ничего не выводит вообще, программа виснет.. пжл, покажи и выведи меня на правильный путь..
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.model small
 
.data
old21 label dword
old21_off dw 0
old21_seg dw 0
msg db "Hi!$"
 
.stack 100h
   
.code   
start:
mov ax,@data
mov ds,ax
 
push ds
 
mov ax,3521h
int 21h
mov old21_off,bx
mov old21_seg,es
 
mov ax,2521h
push cs
pop ds
mov dx,offset new21
int 21h
 
pop ds
 
mov ah,09h
mov dx,offset msg
int 21h
 
jmp $
 
;mov ax,2521h
;mov dx,old21_seg
;mov ds,dx
;mov dx,old21_off
;int 21h
 
;mov ax,4C00h
;int 21h
 
new21 proc
pushf
call ds:old21
        
retf 2
new21 endp
end start
1
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8657 / 4493 / 1669
Регистрация: 01.02.2015
Сообщений: 13,902
Записей в блоге: 12
12.12.2019, 19:19
Assembler
48
call dword ptr ds:old21
0
Прощай, Мир!
 Аватар для proc3nt
1673 / 831 / 253
Регистрация: 26.05.2012
Сообщений: 3,056
12.12.2019, 19:23
ФедосеевПавел, не помогло..
1
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8657 / 4493 / 1669
Регистрация: 01.02.2015
Сообщений: 13,902
Записей в блоге: 12
12.12.2019, 20:47
Как-то делал перехват int 1Ch из exe программы. Смысл тот же.
Сейчас попробую разобраться.

Добавлено через 1 час 22 минуты
proc3nt, у меня не получилось устанавливать новый вектор при помощи самого int 21h. А вот всё то же самое, но при прямой записи в память таблицы векторов - отлично работает.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
.model small
 
.stack 200h
 
.data
        CrLf            db      0Dh, 0Ah, '$'
        msgTest         db      'int 21h ah='
        msgFuncNo       db      '00h', 0Dh, 0Ah
        msgTestLen      equ     $-msgTest
        msgResult       db      'Test string', 0Dh, 0Ah, '$'
        msgPressAnyKey  db      0Dh, 0Ah, 'Press any key to exit...', '$'
.data?
        old_int21h      dd      ?
.code
 
int21h_handler  proc
        pushf
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    es
 
        cld
        push    ds
        pop     es
        lea     di,     [msgFuncNo]
        mov     al,     ah
        mov     cl,     8-4     ; 16-битный регистр, будем выводить по 4 бита (0..F)
        mov     dx,     ax      ; Сохраняем число в DX
@@Repeat:
        mov     ax,     dx      ; Восстанавливаем число в AX
        shr     ax,     cl      ; Сдвигаем на CL бит вправо
        and     al,     0Fh     ; Получаем в AL цифру 0..15
        add     al,     90h     ; special hex conversion sequence
        daa                     ; using ADDs and DAA's
        adc     al,     40h
        daa                     ; nibble now converted to ASCII
        stosb                   ; Выводим символ в AL на экран
        sub     cl,     4       ; Уменьшаем CL на 4 для следующей цифры
        jnc     @@Repeat        ; Если знаковый CL >= 0, то повторяем
        lea     si,     [msgTest]
        mov     cx,     msgTestLen
        @@for:
                lodsb
                int     29h
        loop    @@for
 
        pop     es
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        popf
 
        pushf
        call    dword ptr old_int21h
 
        retf    2
int21h_handler  endp
 
main    proc
        ;инициализация сегментного регистра ds адресом сегмента данных
        mov     ax,     @data
        mov     ds,     ax
 
        ;установка обработчика прерывания
        mov     ax,     3521h           ; AH = 35h, AL = номер прерывания
        int     21h                     ; получить адрес обработчика
        mov     word ptr old_int21h, bx ; и записать его в old_int21h
        mov     word ptr old_int21h+2, es
        push    ds
        ;mov     ax,     2521h           ; AH = 25h, AL = номер прерывания
        mov     dx, offset int21h_handler  ; DS:DX - адрес обработчика
        mov     bx, seg int21h_handler
        ;mov     ds,     bx
        ;int     21h                     ; установить обработчик
 
        mov     ax,     0
        mov     es,     ax
        cli
        mov     word ptr es:[21h*4],    offset int21h_handler
        mov     word ptr es:[21h*4+2],  seg int21h_handler
        sti
 
        pop     ds
 
        ;вывод тестовой строки
        mov     ah,     09h
        lea     dx,     [msgResult]
        int     21h
        ;вывод тестовой строки
        mov     ah,     09h
        lea     dx,     [msgResult]
        int     21h
 
 
        ;восстановление вектора прерывания
        push    ds
        mov     ax,     2521h           ; АН = 25h, AL = номер прерывания
        lds     dx,     dword ptr old_int21h   ; DS:DX = адрес обработчика
        ;int     21h                     ; восстановить старый обработчик
        mov     ax,     0
        mov     es,     ax
        cli
        mov     word ptr es:[21h*4],    dx
        mov     word ptr es:[21h*4+2],  ds
        sti
        pop     ds
 
 
        ;вывод результата
        mov     ah,     09h
        lea     dx,     [msgResult]
        int     21h
        ;ожидание нажатия любой клавиши
        mov     ah,     09h
        lea     dx,     [msgPressAnyKey]
        int     21h
 
        mov     ah,     00h
        int     16h
 
        ;завершение программы
        mov     ax,     4C00h
        int     21h
main    endp
 
end     main
1
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406
13.12.2019, 12:23
proc3nt Вы пишите

Assembler
1
2
    pushf
    call ds:old21
но сегмент DS соответствует программе, которую прервали,
а не нашей программе. поэтому данная идея не работает.
(Надо сохранять DS, устанавливать наш DS, в конце прерывания
восстанавливать исходный DS)

Есть другой простой способ вызывать старое прерывание:

Assembler
1
2
3
4
    pushf
    db 9Ah ; код call far...
old21ip  dw 0
old21cs dw 0
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8657 / 4493 / 1669
Регистрация: 01.02.2015
Сообщений: 13,902
Записей в блоге: 12
13.12.2019, 14:34
Думаю, что мы имеем дело с программным прерыванием и регистр ds никто не меняет - иначе бы не распечатывалась строка ds:dx при вызове функции ah=09h.

Мне не удавалось выполнить замену вектора int 21h средствами самого int 21h. Видимо, это связано как-то с внутренним устройством "родного" обработчика. Думаю, чтобы исключить такое влияние, корректнее напрямую заменять вектор.

Добавлено через 7 минут
Очень может быть, что "родной" обработчик int 21h в некоторых случаях рекурсивно обращается к int 21h уже после замены ds.
Поэтому адрес перехода лучше хранить в сегменте кода и выполнять косвенных переход по адресу в переменной из сегмента данных. А вот регистр ds перед переходом - не устанавливать на cs.

Поэтому примеры com программ выглядят проще, и не дают представления о происходящем - когда с виду корректная программа, зависает.

Добавлено через 38 минут
Т.е. так вижу:
- адрес оригинального обработчика хранится в сегменте кода
- в собственном обработчике перед передачей управления оригинальному обработчику сегмент данных не изменяется (поэтому адрес и храним сегменте кода).

Так работает.
А предыдущий код из сообщения #7, скорее всего некорректный
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
.model small
 
.stack 200h
 
.data
        CrLf            db      0Dh, 0Ah, '$'
        msgInt21hInfo   db      'int 21h ah='
        msgFuncNo       db      '00h', 0Dh, 0Ah
        Int21hInfoLen   equ     $-msgInt21hInfo
        msgTest         db      'Test string', 0Dh, 0Ah, '$'
        TestLen         equ     $-msgTest-1
        msgPressAnyKey  db      0Dh, 0Ah, 'Press any key to exit...', '$'
 
.code
        ;оригинальный вектор прерывания int 21h
        old_int21h      dd      ?
 
int21h_handler  proc
 
        pushf
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    ds
        push    es
 
        push    ax
        mov     ax,     @data
        mov     ds,     ax
        pop     ax
 
        call    my_addon_int21h
 
        pop     es
        pop     ds
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        popf
 
        pushf
        call    cs:[old_int21h]
 
        retf    2
 
int21h_handler  endp
 
my_addon_int21h proc
 
        cld
        push    ds
        pop     es
        lea     di,     [msgFuncNo]
        mov     al,     ah
        mov     cl,     8-4     ; 16-битный регистр, будем выводить по 4 бита (0..F)
        mov     dx,     ax      ; Сохраняем число в DX
@@Repeat:
        mov     ax,     dx      ; Восстанавливаем число в AX
        shr     ax,     cl      ; Сдвигаем на CL бит вправо
        and     al,     0Fh     ; Получаем в AL цифру 0..15
        add     al,     90h     ; special hex conversion sequence
        daa                     ; using ADDs and DAA's
        adc     al,     40h
        daa                     ; nibble now converted to ASCII
        stosb                   ; Выводим символ в AL на экран
        sub     cl,     4       ; Уменьшаем CL на 4 для следующей цифры
        jnc     @@Repeat        ; Если знаковый CL >= 0, то повторяем
        lea     si,     [msgInt21hInfo]
        mov     cx,     Int21hInfoLen
        @@for:
                lodsb
                int     29h
        loop    @@for
 
        ret
my_addon_int21h endp
 
main    proc
        ;инициализация сегментного регистра ds адресом сегмента данных
        mov     ax,     @data
        mov     ds,     ax
 
        ;установка обработчика прерывания
        ; - получить адрес оригинального обработчика
        mov     ax,     3521h           ; AH = 35h, AL = номер прерывания
        int     21h                     ; результат в es:bx
        ; - и записать его в переменную old_int21h
        mov     word ptr cs:[old_int21h],       bx
        mov     word ptr cs:[old_int21h+2],     es
        ; - установить собственный обработчик
        push    ds
        mov     ax,     2521h           ; AH = 25h, AL = номер прерывания
        mov     dx,     offset int21h_handler   ; DS:DX - адрес обработчика
        mov     bx,     seg int21h_handler
        mov     ds,     bx
        int     21h
        pop     ds
 
        ;вывод тестовой строки
        mov     ah,     09h
        lea     dx,     [msgTest]
        int     21h
        ;вывод тестовой строки
        mov     ah,     40h
        mov     bx,     1
        mov     cx,     TestLen
        lea     dx,     [msgTest]
        int     21h
 
        ;восстановление вектора прерывания
        push    ds
        mov     ax,     2521h           ; АН = 25h, AL = номер прерывания
        lds     dx,     dword ptr cs:[old_int21h]   ; DS:DX = адрес обработчика
        int     21h
        pop     ds
 
        ;вывод тестовой строки
        mov     ah,     09h
        lea     dx,     [msgTest]
        int     21h
        ;ожидание нажатия любой клавиши
        mov     ah,     09h
        lea     dx,     [msgPressAnyKey]
        int     21h
        mov     ah,     00h
        int     16h
 
        ;завершение программы
        mov     ax,     4C00h
        int     21h
main    endp
 
end     main
1
Прощай, Мир!
 Аватар для proc3nt
1673 / 831 / 253
Регистрация: 26.05.2012
Сообщений: 3,056
13.12.2019, 15:32
Цитата Сообщение от qbfan Посмотреть сообщение
Есть другой простой способ вызывать старое прерывание
Цитата Сообщение от qbfan Посмотреть сообщение
pushf
    db 9Ah ;код call far...
old21ip  dw 0
old21cs dw 0
qbfan, что-то не совсем понял в какое место ты хочешь вставить данные строки.. если внутри нового обработчика прерывания, то зачем тогда объявлять и обнулять данные переменные, которые к этому моменту уже должны быть заполнены в коде инициализации..

Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Мне не удавалось выполнить замену вектора int 21h средствами самого int 21h
ФедосеевПавел, но ведь qbfan сделал так в посте #2 и правильно работало.. единственное, что там данные находились в сегменте кода, а здесь данные только предполагается, что будут находится в своем собственном сегменте.. думаю, все-таки какой-то нюансик есть и он нами почему-то опускается..
1
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8657 / 4493 / 1669
Регистрация: 01.02.2015
Сообщений: 13,902
Записей в блоге: 12
13.12.2019, 16:05
Позже я пояснил, что
Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Т.е. так вижу:
- адрес оригинального обработчика хранится в сегменте кода
- в собственном обработчике перед передачей управления оригинальному обработчику сегмент данных не изменяется (поэтому адрес и храним сегменте кода).
И показал примером, когда все данные определены в сегменте данных за исключением адреса оригинального обработчика.

Иногда переменную объявляют в коде не просто, как переменную, а как часть инструкции перехода. Т.е. вместо call far Addres пишут инструкцию из отдельных кодов
Assembler
1
2
3
    db 9Ah ; код call far...
old21ip  dw 0
old21cs dw 0
Только для "видимости" переменных добавляют
Assembler
1
2
public old21ip
public old21cs
1
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406
13.12.2019, 19:54
ФедосеевПавел
и регистр ds никто не меняет
То есть как раз DS и меняется, когда мы в конце программы восстанавливаем старое прерывание Int 21h

Добавлено через 20 минут
Извините - запутался.
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
13.12.2019, 20:33
Цитата Сообщение от qbfan Посмотреть сообщение
Извините - запутался
qbfan,
Попробуй прочитать FAQ для раздела Assembler, MASM, TASM https://www.cyberforum.ru/cgi-bin/latex.cgi?\to Всё о резидентах
1
Прощай, Мир!
 Аватар для proc3nt
1673 / 831 / 253
Регистрация: 26.05.2012
Сообщений: 3,056
13.12.2019, 21:09
Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
Иногда переменную объявляют в коде не просто, как переменную, а как часть инструкции перехода
ФедосеевПавел, если не трудно, то сбросьте весь код в таком виде.. думаю, многим будет интересно..
1
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8657 / 4493 / 1669
Регистрация: 01.02.2015
Сообщений: 13,902
Записей в блоге: 12
13.12.2019, 22:17
Пример - обработчик прерывания 1Ch в теме
Вызов звука по нажатию клавиш Control+C (создание собственного прерывания)
В строке 16 переменная с адресом старого вектора объявляется public - для доступа за пределами блока proc, т.е. из основной программы.
В строках 55-56 записана инструкция jmp far на старый обработчик. И т.к. возврата в новый обработчик уже не будет (переход к "старому" при помощи jmp, а не call), то никаких ret и iret далее не следует.

В данной теме обсуждается переход call far. У этой инструкции другой код, но адрес перехода находится очно в таком же месте.
Цитата Сообщение от qbfan Посмотреть сообщение
Есть другой простой способ вызывать старое прерывание:
Assembler
1
2
3
4
    pushf
    db 9Ah ; код call far...
old21ip  dw 0
old21cs dw 0
1
Модератор
1245 / 676 / 292
Регистрация: 10.11.2019
Сообщений: 1,406
14.12.2019, 12:59
Нет, через DS вызывать старое прерывание DOS нельзя, потому что большое число
функций DOS используют DS:DX в качестве аргумента, в том числе файловые функции и вывод на консоль
(как например AH=40h) Так что система неизбежно виснет. Вот моя слегка изменённая программа, в виде
COM файла длиной 76 байт. В ней нет префиксов CS:

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    .286
    .model small
    .code
    assume ds:_text
    org 100h
main:   jmp beg
 
; переменные удобнее размещать в cseg, хотя код немного длиннее
; потому что не приходится загружать DS в подпрограмме прерывания
 
str2 db "Hi$"
 
New21: 
        pushf      ; вызов old21, не надо делать popf
        db 9Ah     ; call far...
old21   label dword ; именно dword, а не word
old21ip dw 0
old21cs dw 0
    pushf      ; сохраняем регистры
    push ds
    push es
    pusha
    call mysub ; выполняем свою подпрограмму
    popa       ; восстанавливаем регистры
    pop  es
    pop  ds
    popf
        retf 2     ; завершение retf 2, а не iret
                   ; т к int 21h возвращает Carry Flag
 
mysub: mov ax,0E07h ; bell - пискнуть динамиком
       int 10h
       ret
 
beg:   push cs
       pop  ds
 
       ;save
       mov      ax,3521h
       int      21h
       mov      old21ip, bx
       mov      old21cs, es
       ;install
       mov      ax,2521h
       mov      dx,offset New21
       int      21h
       ;use
       mov      ah,09h
       mov      dx,offset str2
       int      21h
       ;restore
       lds      dx,old21 ; спец короткая команда грузит ds и dx
       mov      ax,2521h
       int      21h
       MOV      ax, 4C00h
       INT      21h
end main
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
14.12.2019, 22:33
Цитата Сообщение от qbfan Посмотреть сообщение
Assembler
16
17
pushf      ; вызов old21, не надо делать popf
call cs:old21
А теперь вопрос: поскольку при вызове прерывания флаги IF и TF очищаются, то что мы получим после вызова такого int 21h при IF=1, TF=1? Правильно, IF=0, TF=0. Но это при условии, что старый обработчик int 21h всё правильно делает. Собственно, MS-DOS, FreeDOS и DOSBox всё делают правильно (Turbo Debugger тоже перехватывает int 21h и делает неправильно, тупо выполняя sti), а посему поставив после int 21h инструкцию hlt мы получим зависание.

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

Если передать управление прерыванию можно в конце, лучше сделать так:
Assembler
1
2
3
4
Int21Handler:
  pushf
  popf
  jmp dword ptr cs:[OldInt21Handler]
А если его обязательно нужно вызвать где-то в середине, то:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
Int21Handler:
  . . .
  pop cs:[CallerIP]  ; сохраняем IP кода, вызвавшего прерывание
  pop cs:[CallerCS]  ; сохраняем CS кода, вызвавшего прерывание, в стеке остались его флаги
  call dword ptr cs:[OldInt21Handler]
  pushf
  . . .
  popf
  jmp dword ptr cs:[CallerAddr]  ; возвращаем управление программе
 
CallerAddr:
CallerIP dw ?
CallerCS dw ?
Или так:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
Int21Handler:
  pushf  ; сюда мы будем писать флаги (что мы пушим, не имеет значения, можно написать 'push ax')
  push bp
  mov bp,sp
  push [bp+8]  ; сохраняем старые флаги
  pop [bp+2]  ; куда надо
  pop bp  ; в стеке остались флаги
  call dword ptr cs:[OldInt21Handler]
  pushf
  . . .
  popf
  retf 2
(второй код короче на 5 байт... или на 1 байт, если удастся поместить CallerIP и CallerCS в такую область, которая не увеличит объём кода)

Цитата Сообщение от proc3nt Посмотреть сообщение
Assembler
48
call ds:old21
Не надо так делать, даже с учётом исправлений Павла (хотя это исправление ни на что не повлияет, ибо old21 и так имеет размер dword, поэтому call ds:old21 как call dword ptr ds:old21). У меня лично этот код работает под DOSBox'ом.
Но! Мы не можем гарантировать, что кто-либо другой не использует int 21h (например, в таймере или даже сам int 21h может вызывать себя рекурсивно), при этом DS может быть изменён.
2
3410 / 1829 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
14.12.2019, 22:38
Можно и DS передать в обработчик.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
model   small
.data
; . . . . 
; . . . .
.stack  100h
.code
begin:  mov ax,@data
    mov ds,ax
    jmp next
new21:  call    @@02
@@02:   pop bx
    mov SI,- на @data
    mov ax,cs:[bx+si]
; . . .
    iret
next:
1
Asm/C++/Delphi/Py/PHP/VBA
 Аватар для Jin X
6812 / 2052 / 238
Регистрация: 14.12.2014
Сообщений: 4,305
Записей в блоге: 12
14.12.2019, 22:44
Цитата Сообщение от Jin X Посмотреть сообщение
А если его обязательно нужно вызвать где-то в середине, то:
Кстати, эти 2 pop'а можно заменить на один pop dword ptr cs:[CallerAddr] (386+), это сэкономит 4 байта.

Цитата Сообщение от Jin X Посмотреть сообщение
Или так
А вот это можно вообще сократить до:
Assembler
1
2
3
4
5
6
  push word ptr [esp+4]  ; пересохраняем флаги в стеке
  call dword ptr cs:[OldInt21Handler]
  pushf
  . . .
  popf
  retf 2
Но это, опять же, 386+ и тут нужно быть уверенным, что старшая половина ESP = 0, что по идее должно быть всегда, но не гарантированно.
1
3410 / 1829 / 489
Регистрация: 28.02.2015
Сообщений: 3,696
14.12.2019, 22:49
это так идея - сильно не пинайте, со стека же как-то извлекаются и аргументы и локальные переменные.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
14.12.2019, 22:49
Помогаю со студенческими работами здесь

Резидентный обработчик функции ah=09h int 21h - вывод строки "My String"
Помогите пожалуйста Надо написать резидентную программу, которая будет активироватьcя при попытки программ вывести строку на экран...

Резидентная программа - перехват прерывания int 21h ah=09h
Задание: перекрыть 9 функцию 21 прерывания в assembler. Помогите, плиз, разобраться как правильно ставить перекрывание. Решил с самого...

Перехват прерывания int 21h ah=0Ah: во вводимой строке продублировать все гласные буквы
Привет всем, задали тут задачку: -Переопределить десятую функцию прерывания 21h таким образом, чтобы в вводимой строке были...

Поиск файлов (int 21h ah=4Eh)
Здравствуйте!!!! Всем доброго времени суток. Столкнулся с проблемой пойска файлов функцией DOS AH=4Eh. У меня win7 32x использую DOSBox....

Перемещение файла int 21h func 56
Нужно получить аргументами командной строки путь к файлу и его новый путь, то есть либо просто переместить, либо переместить с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru