中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 关于汇编改写中断入口地址 的问题。
作者:
标题: 关于汇编改写中断入口地址 的问题。 上一主题 | 下一主题
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『楼 主』:  关于汇编改写中断入口地址 的问题。 [已使用 LLM 解释]

在程序运行期间 修改了int9的入口地址 程序结束 恢复int9的入口地址
程序的执行从结果上看是正常的 结束后,键盘就锁住了。
以下是代码。

assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
db 128 dup(0)
stacksg ends
datasg segment
int9ip dw 0
int9cs dw 0

datasg ends
codesg segment
start:

mov ax,datasg
mov ds,ax
mov ax,0
mov es,ax
mov si,0
mov dx,es:[9*4]
mov word ptr int9ip,dx
mov dx,es:[9*4+2]
mov word ptr int9cs,dx ;保存当前的int 9的中断向量
;
mov word ptr es:[9*4],offset int99
mov word ptr es:[9*4+2],cs ;设置int 9中断向量

mov ax,0b800h
mov es,ax
mov di,160*12+2*40 ;第13行中间开始
mov cx,10
;
mov al,'a'
mov ah,7ch ;颜色
mov es:[di+1],ah
;
s:
mov es:[di],al
call time
inc al
loop s ;循环显示

mov dx,int9ip
mov word ptr es:[9*4],dx
mov dx,int9cs
mov word ptr es:[9*4+2],dx ;恢复int 9中断向量

mov ax,4c00h
int 21h


;----------------------------------
int99: ;到这里 CS IP 标志寄存器 已经由硬件完成入栈
mov ah,0fch
mov byte ptr es:[di+1],ah ;恢复向量表
iret
;----------------------------------

;用于延时
time proc
push ax
push bx
mov bx,1000h
mov ax,0
s1:
sub ax,1
sbb bx,0
cmp ax,0
jne s1
cmp bx,0
jne s1
pop bx
pop ax
ret
time endp
codesg ends
end start

继续研究。。。
LLM 解释

问题分析:键盘锁住的根本原因

您的程序在修改 int 9 中断向量后未能正确处理键盘硬件响应,导致键盘控制器始终处于等待状态,表现为"键盘锁住"。具体问题如下:

  1. 中断处理程序不完整:自定义的 int99 仅修改了显示颜色,未执行键盘中断必须的硬件操作
  2. 缺少EOI信号:未向8259A PIC发送中断结束命令,导致后续中断被屏蔽
  3. 未读取键盘扫描码:未从端口60h读取扫描码,键盘控制器无法接收新按键

正确解决方案

1. 完整的中断处理程序实现

assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
  db 128 dup(0)
stacksg ends
datasg segment
  int9ip dw 0        ;保存原中断向量IP
  int9cs dw 0        ;保存原中断向量CS
datasg ends
codesg  segment
start:
    mov ax,datasg
    mov ds,ax
    mov ax,stacksg
    mov ss,ax
    mov sp,128       ;初始化栈段,确保中断处理时堆栈可用

    ;保存原int9中断向量
    cli              ;关中断,避免保存向量过程被中断打断
    mov ax,0
    mov es,ax
    mov dx,es:[9*4]
    mov int9ip,dx
    mov dx,es:[9*4+2]
    mov int9cs,dx
    ;设置新int9中断向量
    mov word ptr es:[9*4],offset int99
    mov word ptr es:[9*4+2],cs
    sti              ;恢复中断

    ;显示字符部分
    mov ax,0b800h
    mov es,ax
    mov di,160*12+2*40  ;第13行中间位置
    mov cx,10
    mov al,'a'
    mov ah,7ch          ;初始颜色
    mov es:[di+1],ah    ;设置颜色属性
    
s:  mov es:[di],al      ;显示字符
    call time           ;延时
    inc al
    loop s

    ;恢复原中断向量
    cli                 ;关中断,确保恢复向量过程安全
    mov dx,int9ip
    mov es:[9*4],dx
    mov dx,int9cs
    mov es:[9*4+2],dx
    sti                 ;恢复中断

    mov ax,4c00h
    int 21h

;----------------------------------
;自定义int9中断处理程序
int99:
    push ax             ;保护寄存器
    push bx
    push es
    
    ;读取键盘扫描码
    in al,60h           ;从8042端口读取扫描码
    
    ;调用原int9中断处理程序
    pushf               ;将标志寄存器入栈,模拟中断调用环境
    call dword ptr ds:[int9ip]  ;调用原中断处理(CS:IP)
    
    ;自定义处理 - 修改显示颜色
    mov ax,0b800h
    mov es,ax
    mov byte ptr es:[di+1],0fch  ;修改颜色属性
    
    pop es              ;恢复寄存器
    pop bx
    pop ax
    iret                ;中断返回
;----------------------------------

;延时子程序
time proc
    push ax
    push bx
    mov bx,1000h
    mov ax,0
s1: sub ax,1
    sbb bx,0
    cmp ax,0
    jne s1
    cmp bx,0
    jne s1
    pop bx
    pop ax
    ret
time endp
codesg  ends
end start

2. 关键修复点说明

  • 堆栈初始化:增加了栈段初始化,确保中断处理时堆栈操作安全
  • 中断开关控制:在修改中断向量时使用 cli/sti 保护,避免竞态条件
  • 完整中断处理流程
    1. 读取键盘扫描码 (in al,60h)
    2. 调用原中断处理程序 (call dword ptr ds:[int9ip])
    3. 添加自定义功能
  • 寄存器保护:使用 push/pop 保护所有修改过的寄存器

3. 中断处理的技术细节

DOS环境下修改硬件中断(int 08h-0fh)需特别注意:

  1. 硬件中断响应流程

    • CPU收到中断请求→自动关中断→压入FLAGS、CS、IP
    • 执行中断处理程序→需手动发送EOI信号(8259A控制器)
  2. 原中断调用方法

    pushf            ;模拟中断过程,使TF、IF标志正确传递
    call dword ptr cs:old_int9  ;调用原中断处理程序
    

    而非直接 jmp,因为原中断可能依赖标志寄存器状态

  3. 兼容性考虑

    • 对于AT以上机型,需处理8042键盘控制器的A20地址线问题
    • 某些DOS系统可能使用共享中断处理,直接替换可能导致冲突

4. 调试建议

若仍有问题,可采用以下调试方法:

  1. 在中断处理程序中添加端口调试输出:

    mov al,20h       ;发送EOI命令到主8259A
    out 20h,al
    
  2. 使用DEBUG工具单步跟踪中断向量修改过程:

    -g=start        ;运行到start标签
    -d 0:36 39      ;查看int9中断向量(0:36-0:39)
    
  3. 验证堆栈使用:在中断处理前后检查SP值是否一致

通过以上修改,程序将正确处理键盘中断,结束后也不会导致键盘锁住。



2008-12-3 18:26
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 2 楼』:   [已使用 LLM 解释]

你的问题出在这段程序上,你的ES被替换后未做现场保护,只要在前面加PUSH ES,在后面加POP ES就可以了。我在编VtMagiC.com时也有过如此疏漏导致的调试多次失败。汇编就是这样的!所以人家要用VB、VC啦!

mov ax,0b800h
mov es,ax
mov di,160*12+2*40 ;第13行中间开始
mov cx,10
;
mov al,'a'
mov ah,7ch ;颜色
mov es:[di+1],ah
;
s:
mov es:[di],al
call time
inc al
loop s ;循环显示
LLM 解释

汇编中断入口地址改写中的现场保护问题分析

问题定位

您指出的ES寄存器未保护的问题确实是汇编程序设计中的常见错误。在这段显存操作代码中,ES被修改为0B800h(文本模式显存段地址),但未考虑对原有ES值的保存与恢复。若此代码运行在中断服务程序(ISR)或多任务环境中,会导致后续依赖ES的操作使用错误的段地址,引发内存访问异常或数据损坏。

正确的现场保护实现

push    es              ; 保存原ES寄存器值
push    ax              ; 保护AX(可选,取决于上下文)

mov     ax, 0b800h      ; 设置显存段地址
mov     es, ax
mov     di, 160*12 + 2*40  ; 计算显存偏移量(第13行第40列)
mov     cx, 10          ; 设置循环次数

mov     al, 'a'         ; 初始字符
mov     ah, 7ch         ; 属性字节(高4位背景:7=灰, 低4位前景:c=亮红)
mov     es:[di+1], ah   ; 写入属性(仅首次?循环中未更新)

s:
mov     es:[di], al     ; 写入字符
call    time            ; 延时/等待(需确保此调用不破坏寄存器)
inc     al              ; 下一个字符
add     di, 2           ; 移动到下一个字符位置(每个字符占2字节)
loop    s               ; 循环10次

pop     ax              ; 恢复AX(若之前保存)
pop     es              ; 恢复原ES寄存器值

关键改进点说明

  1. 寄存器保护:使用PUSH/POPES进行完整保护,符合中断服务程序设计规范
  2. 显存地址计算
    • 文本模式显存按行×160 + 列×2计算偏移量
    • 每行80字符×2字节=160字节,12行偏移为160×12
    • 40列偏移为2×40,总计160×12+2×40=1920+80=2000(07D0h)
  3. 循环逻辑修正:原代码缺少DI递增操作,添加add di, 2使字符依次显示
  4. 属性字节处理:当前仅设置一次属性,若需不同颜色需在循环内更新AH

中断处理特殊考量

若此代码用于改写中断向量(如时钟中断08h),还需额外保护更多寄存器:

push    ax bx cx dx si di es ds  ; 保护所有通用寄存器
pushf                            ; 保护标志寄存器

; 显存操作代码...

popf                             ; 恢复标志寄存器
pop     ds es di si dx cx bx ax  ; 恢复寄存器
iret                             ; 中断返回(而非ret)

兼容性说明

  • 对于8086/8088处理器,需确保PUSH的寄存器数量为偶数
  • 在实模式下,段寄存器操作需注意特权级,但DOS环境通常运行在Ring 0
  • time子程序应避免使用未保护的寄存器,或在调用前额外保护

汇编语言虽对寄存器管理要求严格,但通过规范的现场保护机制可确保系统稳定性。这种底层控制能力正是汇编在系统编程中的价值所在,与VB/VC等高级语言的内存管理模式形成互补。





my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2008-12-3 21:16
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 3 楼』:   [已使用 LLM 解释]

恩 ES确实没有保护好
以下是改后的代码 我全贴出来吧, 复制过去,编译下就能运行
我想实现的功能是这样的, 在逐个显示字符期间, 如果有键盘按键。就改变原来的字符颜色。 并用改写int 9 中断的方式去实现。
assume cs:codesg,ds:datasg,ss:stacksg
stacksg segment
db 128 dup(0)
stacksg ends
datasg segment
int9ip dw 0
int9cs dw 0
datasg ends
codesg segment
start:

mov ax,datasg
mov ds,ax
mov ax,0
mov es,ax
mov si,0
mov dx,es:[9*4]
mov word ptr int9ip,dx
mov dx,es:[9*4+2]
mov word ptr int9cs,dx ;保存当前的int 9的中断向量
;
mov word ptr es:[9*4],offset int9
mov word ptr es:[9*4+2],cs ;设置int 9中断向量
push es
mov ax,0b800h
mov es,ax
mov di,160*12+2*40 ;第13行中间开始
mov cx,10
;
mov al,'a'
mov ah,7ch ;颜色
mov es:[di+1],ah
;
s:
mov es:[di],al
call time
inc al
loop s ;循环显示

pop es
mov dx,int9ip
mov word ptr es:[9*4],dx
mov dx,int9cs
mov word ptr es:[9*4+2],dx ;恢复int 9中断向量

mov ax,4c00h
int 21h


;----------------------------------
int9: ;到这里 CS IP 标志寄存器 已经由硬件完成入栈
mov ah,0fch
mov byte ptr es:[di+1],ah ;恢复向量表
iret
;----------------------------------

;用于延时
time proc

push ax
push bx
mov bx,1000h
mov ax,0

s1:
sub ax,1
sbb bx,0
cmp ax,0
jne s1
cmp bx,0
jne s1
pop bx
pop ax
ret
time endp
codesg ends
end start

程序运行 和第一次的结果一样, 在显示字符期间按键盘,字符颜色就改变。 但是,程序运行结束 键盘就不能用了,输入不了字符了。
另外,我在time子程序里 S标号的上一句加了 int 9让程序自身产生中断。 运行结果是,字符的颜色改变,键盘能用。 这就奇怪了直接在程序里写int 9和按键触发的int 9应该一样呀 都是是cs ip 寄存器 入栈。iret 恢复。
LLM 解释

问题分析与解决方案

1. 键盘无法使用的根本原因

您的中断处理程序未完成键盘中断的完整处理流程,导致键盘控制器始终处于等待状态。具体问题:

  • 未读取键盘扫描码:硬件产生键盘中断后,必须从端口60h读取扫描码,否则键盘控制器会持续发送中断请求
  • 未向8259A发送EOI:未执行out 20h, al命令通知中断控制器中断处理完成
  • 未调用原BIOS INT 9处理程序:您的处理程序完全替换了BIOS的键盘处理逻辑,导致系统无法处理按键的后续操作(如ASCII码转换)

2. 程序内int 9与硬件触发中断的区别

  • 程序内int 9:仅模拟了中断调用流程,但不会触发真实硬件操作(无需读取扫描码和EOI)
  • 硬件触发中断:由键盘控制器发起,必须完成完整的硬件交互流程

3. 修正后的代码

assume cs:codesg, ds:datasg, ss:stacksg

stacksg segment
    db 128 dup(0)
stacksg ends

datasg segment
    int9ip dw 0          ; 保存原INT9偏移地址
    int9cs dw 0          ; 保存原INT9段地址
    color_flag db 0      ; 颜色改变标志
datasg ends

codesg segment
start:
    mov ax, datasg
    mov ds, ax
    mov ax, stacksg
    mov ss, ax
    mov sp, 128          ; 初始化栈段
    
    ; 保存原INT9中断向量
    mov ax, 0
    mov es, ax
    push es:[9*4]
    pop int9ip
    push es:[9*4+2]
    pop int9cs
    
    ; 设置新INT9中断向量
    cli                  ; 关中断,避免设置向量时被中断打断
    mov word ptr es:[9*4], offset int9
    mov word ptr es:[9*4+2], cs
    sti                  ; 开中断
    
    ; 初始化显示参数
    mov ax, 0b800h
    mov es, ax           ; ES指向显存
    mov di, 160*12 + 2*40 ; 第13行中间位置
    mov cx, 10           ; 显示10个字符
    mov al, 'a'
    mov ah, 7ch          ; 初始颜色
    
display_loop:
    mov es:[di], al      ; 显示字符
    mov es:[di+1], ah    ; 显示颜色
    
    ; 检查颜色标志并更新
    cmp color_flag, 1
    jne no_change
    mov ah, 0fch         ; 改变后的颜色
    mov color_flag, 0    ; 重置标志
no_change:
    call delay           ; 延时
    inc al               ; 下一个字符
    add di, 2            ; 下一个显示位置
    loop display_loop
    
    ; 恢复原INT9中断向量
    cli
    mov ax, 0
    mov es, ax
    push int9ip
    pop es:[9*4]
    push int9cs
    pop es:[9*4+2]
    sti
    
    mov ax, 4c00h
    int 21h

; 自定义INT9中断处理程序
int9:
    push ax
    push bx
    push es
    
    ; 读取键盘扫描码
    in al, 60h           ; 必须读取端口60h,否则键盘锁死
    
    ; 调用原BIOS INT9处理程序
    pushf                ; 将标志寄存器入栈,模拟中断过程
    call dword ptr ds:[int9ip] ; 调用原INT9 (CS:IP = int9cs:int9ip)
    
    ; 检查是否为按键按下(扫描码最高位为0)
    and al, 80h
    jnz int9_ret         ; 如果是释放扫描码(最高位1),不处理
    
    ; 设置颜色改变标志
    mov ax, datasg
    mov es, ax
    mov byte ptr es:[color_flag], 1
    
int9_ret:
    ; 发送EOI给8259A主控制器
    mov al, 20h
    out 20h, al
    
    pop es
    pop bx
    pop ax
    iret                 ; 中断返回

; 延时子程序
delay proc
    push ax
    push bx
    mov bx, 1000h
    mov ax, 0
delay_loop:
    sub ax, 1
    sbb bx, 0
    cmp ax, 0
    jne delay_loop
    cmp bx, 0
    jne delay_loop
    pop bx
    pop ax
    ret
delay endp

codesg ends
end start

4. 关键改进点说明

  1. 完整的中断处理流程

    • 通过in al, 60h读取键盘扫描码
    • 发送EOI命令out 20h, al通知中断控制器
    • 使用pushf+call dword ptr调用原BIOS INT9处理程序
  2. 使用标志位控制颜色

    • 新增color_flag变量,避免直接操作显存导致的地址冲突
    • 中断处理程序只设置标志,主程序负责更新颜色
  3. 中断安全处理

    • 在修改中断向量时使用cli/sti关开中断
    • 完整保存和恢复寄存器环境(AX、BX、ES)
  4. 栈初始化

    • 显式初始化栈段,避免中断处理时栈溢出

5. 运行说明

  • 程序运行时显示a-j共10个字符
  • 按键时字符颜色变为0FCh(亮青色背景,红色前景)
  • 程序结束后键盘功能完全恢复,可正常输入

此方案遵循了DOS中断处理的规范,既实现了功能需求,又保证了系统资源的正确恢复。



2008-12-4 09:58
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 4 楼』:   使用 LLM 解释/回答一下

DOS中断最要注意重入问题,要调用原中断例程,要在int99(新中断例程)中加入pushf和call dword ptr ds:int9ip链接原中断,才能继续键盘操作。

另外,你的新例程中,DI值来自何处?而且也没有处理键盘输入的程序行,应该是程序不完整吧!因为贴出来的程序段根本不需要挂在int9上。

Last edited by 本是 on 2008-12-4 at 11:43 ]




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2008-12-4 11:28
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 5 楼』:   使用 LLM 解释/回答一下

mov di,160*12+2*40 ;第13行中间开始
因为这个中断例程只是这个程序用 程序执行玩后 就要恢复的 所以这个DI 在在例程中没有重新赋值。
“DOS中断最要注意重入问题,要调用原中断例程,要在int99(新中断例程)中加入pushf和call dword ptr ds:int9ip链接原中断,才能继续键盘操作。”
对这句话不是很理解。
中断产生,也就是我按下键盘 产生的int 9中断。 硬件完成了Cs IP 标志寄存器的入栈, 然后就是调用我的int99 我只要在中断历程中iret一下就可以了。
鄙人不才,还望进一步指点。


2008-12-4 12:11
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 6 楼』:   使用 LLM 解释/回答一下

是不是这样,
我在程序中只是执行了 我定义的int 9中断 但是还要必须执行一次系统原来的int 9中断。


2008-12-4 12:44
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 7 楼』:   [已使用 LLM 解释]

中断例程修改如下:
int9: ;到这里 CS IP 标志寄存器 已经由硬件完成入栈

mov ah,0fch
mov byte ptr es:[di+1],ah ;恢复向量表

pushf push ax
and ah,11111100b
pop ax

;push int9cs
;push int9ip
;jmp dword ptr int9ip ;高地址是cs 低地址是IP
call dword ptr ds:int9ip ;模仿 调用系统的int 9

iret

运行正常 看来还要好好的深入研究中断
系统的int 9中断 做了些什么。
LLM 解释

中断例程修改分析与系统int 9中断功能说明

一、代码功能解析

int9:                           ; 硬件自动完成: CS、IP、标志寄存器入栈
    mov ah,0fch
    mov byte ptr es:[di+1],ah   ; 恢复中断向量表第2字节(CS低8位)
    
    pushf                       ; 保存标志寄存器
    push ax                     ; 保存ax寄存器
    and ah,11111100b            ; 清除AH低2位(键盘扫描码的扩展码标志)
    pop ax                      ; 恢复ax(仅AH被修改)
    
    call dword ptr ds:int9ip    ; 调用原int 9中断处理程序(段间调用)
    iret                        ; 中断返回(自动弹出IP、CS、标志寄存器)

关键操作说明

  1. 中断向量恢复es:[di+1]指向中断向量表中int 9对应的CS低8位,写入0FCh恢复原向量值
  2. 标志寄存器处理pushf保存中断现场标志,确保原中断处理程序能正确获取标志状态
  3. 扫描码处理and ah,11111100b清除键盘扫描码的P位(奇偶校验)和R位(释放标志),仅保留扫描码核心信息
  4. 原中断调用call dword ptr ds:int9ip通过段间调用方式执行原int 9处理程序,保持正确的调用栈结构

二、系统int 9中断核心功能

IBM PC兼容机的BIOS int 9中断(键盘中断)主要完成以下工作:

  1. 扫描码读取

    • 从端口60h读取键盘控制器返回的扫描码(1字节)
    • 扫描码分为通码(按键按下)和断码(按键释放,通码+80h)
  2. 特殊键处理

    • 处理Shift、Ctrl、Alt等修饰键状态,存入BIOS数据区(40:17h)
    • 处理Caps Lock、Num Lock、Scroll Lock的LED指示灯切换(通过端口61h控制)
  3. 字符转换

    • 根据当前键盘状态(Shift/Caps状态、键盘布局)将扫描码转换为ASCII码
    • 结果存入键盘缓冲区(40:1Eh开始的16字节循环队列)
  4. 中断结束处理

    • 向键盘控制器发送应答信号(写端口61h)
    • 执行iret返回被中断程序

三、代码优化建议

  1. 寄存器保护:当前代码未保护esdi寄存器,可能破坏调用者环境,建议添加:

    push es
    push di
    ; ... 原有代码 ...
    pop di
    pop es
    
  2. 向量恢复位置:建议在调用原中断后恢复向量表,避免嵌套中断时向量表状态不一致

  3. 扫描码处理改进:若需完整保留扫描码信息,可使用and ah,11111110b仅清除奇偶校验位

四、中断处理注意事项

  1. 中断嵌套:修改中断向量时需确保关闭中断(cli)或使用原子操作,防止中断嵌套导致的向量表不一致
  2. 栈平衡call指令会自动压入返回地址,与原代码中注释掉的push int9cs; push int9ip; jmp效果相同,但call更符合中断调用规范
  3. 兼容性:不同BIOS的int 9实现可能存在差异,建议通过读取中断向量表获取原中断地址,而非硬编码恢复值

深入理解中断处理机制需结合8259A可编程中断控制器(PIC)的工作原理及键盘控制器(8042)的通信协议。



2008-12-4 12:59
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 8 楼』:   使用 LLM 解释/回答一下

谢谢 本是
这个问题困扰了我三天。


2008-12-4 13:00
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 9 楼』:   使用 LLM 解释/回答一下

不用谢!不过,我觉得你需要系统地学习一些系统知识,如《MS-DOS高级开发指南——编程人员必备的高级技术参考书》(希望电脑公司),里面对中断编程讲得很细,当然网上也应该有资料的。




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2008-12-4 13:45
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
netwinxp
高级用户





积分 741
发帖 366
注册 2007-7-25
状态 离线
『第 10 楼』:   使用 LLM 解释/回答一下

硬件中断服务程序要注意与硬件的“沟通”,你的INT 9既没有对产生INT 9的原因进行“处理”,也没有回调老的中断服务程序进行默认的“处理”,于是,按一下键,就会一直在产生INT 9。


2008-12-5 11:15
查看资料  发短消息  网志   编辑帖子  回复  引用回复
本是
银牌会员





积分 2221
发帖 789
注册 2005-1-27
状态 离线
『第 11 楼』:   使用 LLM 解释/回答一下

Originally posted by netwinxp at 2008-12-5 11:15:
硬件中断服务程序要注意与硬件的“沟通”,你的INT 9既没有对产生INT 9的原因进行“处理”,也没有回调老的中断服务程序进行默认的“处理”,于是,按一下键,就会一直在产生INT 9。


真正的硬件高手!一直喜欢看高手回的贴子。




my major is english----my love is dos----my teacher is the buddha----my friends--how about U
2008-12-5 11:22
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 12 楼』:   使用 LLM 解释/回答一下

Originally posted by netwinxp at 2008-12-5 11:15:
硬件中断服务程序要注意与硬件的“沟通”,你的INT 9既没有对产生INT 9的原因进行“处理”,也没有回调老的中断服务程序进行默认的“处理”,于是,按一下键,就会一直在产生INT 9。

不是一直产生int 9 而是8259A不让通过 因为在接受一个中断后 8259A的EOI位一直为0,不在接受同级或以下级别的中断(被屏蔽了)。 直到EOI标志位为1。 我想,要在进行一次默认的“处理”,其目的是让EOI置1.代码修改后 测试通过

int9:
mov ah,0fch
mov byte ptr es:,ah ;恢复向量表
mov al,20h
out 20h,al ;置EOI 为1
iret


2008-12-12 09:15
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
netwinxp
高级用户





积分 741
发帖 366
注册 2007-7-25
状态 离线
『第 13 楼』:   [已使用 LLM 解释]

其实你的程序根本没必要使用INT 9,除非迫不得已,否则不推荐任意修改硬件中断服务程序。
...
RE:
...
;寄存器入栈
;清理标志寄存器
mov ax,1100H
int 16H
jnz EXIT
;寄存器出栈
;用于显示的语句
...
jmp RE
EXIT:;退出处理
...

Last edited by netwinxp on 2008-12-12 at 09:31 ]
LLM 解释

关于DOS环境下中断处理与INT 16H的技术分析

1. 硬件中断与INT 9的风险说明

  • INT 9的特殊性:INT 9是80x86架构中的键盘硬件中断向量,直接关联键盘控制器(8259A)的IRQ1。修改此中断可能导致:
    • 与DOS内核键盘处理逻辑冲突
    • 键盘输入丢失或重复
    • 系统稳定性问题(如死锁)
  • 推荐替代方案
    • 软中断钩子(如INT 16H键盘BIOS服务)
    • DOS系统调用(INT 21H AH=01H/06H等)
    • 轮询方式(适用于简单应用)

2. 代码片段技术解析

提供的代码片段使用了INT 16H AH=11H功能,这是BIOS提供的键盘状态检查服务:

mov  ax, 1100H   ; AH=11H(检查键盘缓冲区), AL=00H(兼容模式)
int  16H         ; 调用BIOS键盘服务
jnz  EXIT        ; ZF=0表示有按键(AX=按键扫描码),跳转到EXIT
  • 功能特点
    • 非阻塞检查键盘缓冲区
    • 不修改缓冲区内容(与AH=00H读取不同)
    • 返回值:ZF标志位指示状态,AX寄存器保存按键信息

3. 安全的键盘监控实现方案

方案1:INT 16H轮询机制(适用于大多数情况)

POLLING:
    push ax
    mov  ah, 01H        ; 检查是否有按键等待
    int  16H
    jz   NO_KEY         ; 无按键则继续轮询
    
    ; 有按键处理逻辑
    mov  ah, 00H        ; 读取按键
    int  16H            ; AX = 扫描码(高8位)+ASCII码(低8位)
    ; [处理AX中的按键数据]
    
NO_KEY:
    pop ax
    ; [其他程序逻辑]
    jmp POLLING         ; 循环轮询

方案2:INT 16H钩子(软中断接管)

; 安装钩子
install_key_hook:
    cli                 ; 关中断
    mov  ax, 3516H      ; 获取原INT 16H向量
    int  21H            ; ES:BX = 原中断处理程序地址
    mov  [old_int16_off], bx
    mov  [old_int16_seg], es
    
    mov  ax, 2516H      ; 设置新INT 16H向量
    mov  dx, offset new_int16
    int  21H
    sti                 ; 开中断
    ret

; 新中断处理程序
new_int16:
    cmp  ah, 00H        ; 判断是否是读取按键功能
    je   handle_key
    jmp  dword ptr [old_int16_seg]:[old_int16_off]  ; 调用原中断

handle_key:
    ; [自定义按键处理逻辑]
    ; 必须调用原中断完成正常功能
    jmp  dword ptr [old_int16_seg]:[old_int16_off]

; 数据区
old_int16_seg dw 0
old_int16_off dw 0

4. 关键注意事项

  1. 寄存器保护:中断处理程序必须完整保存/恢复所有寄存器(使用PUSHA/POPA指令)
  2. 中断嵌套:硬件中断处理应尽量简短,避免在中断内调用可能触发其他中断的服务
  3. 兼容性:实模式下需注意640KB内存限制和8086指令集兼容性
  4. 清理机制:程序退出前必须恢复原中断向量,避免影响后续程序

5. 适用场景建议

  • 硬件中断(INT 9):仅用于需要直接响应键盘硬件事件(如组合键、热键)的场景
  • 软中断钩子:适用于需要全局监控键盘输入的应用(如TSR程序)
  • 轮询机制:简单应用的首选方案,实现简单且无系统风险

在DOS开发中,应遵循"最小权限原则",优先使用高层BIOS/DOS服务,仅在必要时才操作硬件中断。



2008-12-12 09:25
查看资料  发短消息  网志   编辑帖子  回复  引用回复
zhushouqqq
初级用户





积分 32
发帖 13
注册 2008-12-2
状态 离线
『第 14 楼』:   使用 LLM 解释/回答一下

这个只是书上一个运行不起来的代码。只是为了自己理解。


2008-12-12 09:46
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复
sanchuan
初级用户





积分 113
发帖 51
注册 2008-11-16
来自 武汉
状态 离线
『第 15 楼』:   使用 LLM 解释/回答一下

能够引起探讨的好贴,顶




三川一笑
2008-12-30 17:10
查看资料  发送邮件  发短消息  网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: