汇编语言学习笔记-4 0x00 内中断 中断意思就是:CPU不再接着(刚执行完的指令)向下执行,而是转去处理特殊信息(中断信息) 。
那什么时候CPU会马上处理中断信息呢?
CPU根据中断信息可以找到要执行的处理程序,因此中断信息和处理程序的入口地址间需建立联系。中断类型码用于定位中断处理程序。
通过中断向量表 ,可以使用中断类型码(8位),来确定中断处理程序的段地址与偏移地址。中断向量表保存在内存里,里面存放着256个中断处理程序的入口地址。中断向量表在0000:0000~0000:03FF
中,共1024个字节。
中断过程(硬件自动执行,程序员无法干预) :用中断类型码可在中断向量表中找到中断处理程序的入口(即中断向量 ),并用它设置CS和IP,使CPU执行中断过程(需要先保存原来CS与IP的值,以便执行完中断后回到原程序点)。具体如下图所示:
由于CPU随时都可能进行中断处理,因此中断处理程序必须一直存储在内存中,且中断处理程序的入口地址(也就是中断向量)必须存储在对应的中断向量表项中。
中断处理程序 其书写方法与子程序类似,具体如下图:
注:iret从栈中依次弹出IP、CS、标志寄存器,汇编语法描述为:pop IP; pop CS; popf
。
Q&A 已知:
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 assume cs:code, ds:data data segment db "overflow!" data ends code segment do0: mov ax, data mov ds, ax mov si, 0 mov ax, 0b800H ; 显示overflow字符串 mov es, ax mov di, 12*160+36*2 ; es:di指向显存空间的中间位置 mov cx, 9 s: mov al, ds:[si] mov es:[di], al inc si add di, 2 loop s mov ax, 4c00H ; 溢出后直接结束了,不返回 int 21H start: mov ax, 0H mov ds, ax mov si, offset do0 mov ax, 0000H mov es, ax mov di, 0200H ; 将do0的代码送入到0000:0200 mov cx, offset start; 也可以写成mov cx, offset start - offset do0 sub cx, offset do0 cld rep movsb mov ax, 1000H mov bh, 1 div bh mov ax, 4c00H int 21H code ends end start
上述代码有两个问题:
此程序执行完成后,如果再触发div溢出错误,由于data段数据以被回收,因此会显示随机字符串。
并没有改变中断向量表第一项,也就是入口地址为0000:0200
。
修改后的程序为:
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 assume cs:code code segment do0: jmp short do0start db "overflow!" do0start: mov ax, 0000H mov ds, ax mov si, 0202H ; 0:200H 有指令jmp short do0start(2字节长) mov ax, 0b800H ; 显示overflow字符串 mov es, ax mov di, 24*160+36*2 ; es:di指向显存空间的中间位置 mov cx, 9 s: mov al, ds:[si] mov es:[di], al inc si add di, 2 loop s mov ax, 4c00H ; 溢出后直接结束了,不返回 int 21H start: mov ax, 0H mov ds, ax mov si, offset do0 mov ax, 0000H mov es, ax mov di, 0200H ; 将do0的代码送入到0000:0200 mov cx, offset start - offset do0 cld rep movsb mov ax, 0 mov es, ax mov word ptr es:[0], 0200H mov word ptr es:[2], 0000H int 0 ; 进入中断处理程序 mov ax, 4c00H int 21H code ends end start
单步中断 CPU执行完一条指令之后,如果检测到标志寄存器的TF(Trace Flag)位为1,则产生单步中断,引发中断过程 。
单步中断的中断类型码为1,中断过程如下:
有一个问题:Debug的T指令在执行一条指令后,就显示各个寄存器的状态,如何实现的?
(1)T命令执行指令时先设置将TF=1
,则CPU工作于单步中断方式,使CPU执行完一条程序指令后就引发单步中断。
(2)执行对应中断处理程序。寄存器的内容被显示在屏幕上,并且等待输入命令。
补充 有些情况下,CPU 在执行完当前指令后,即便是发生中断,也不会响应。例如,在执行完向ss寄存器传送数据的指令后,即便是发生中断,CPU 也不会响应。 为啥咧?因为ss:sp
联合指向栈顶,对它们的设置应连续完成。若设置ss的指令后CPU响应中断,中断过程将CS和IP值入栈,此时ss改变而sp未改变,ss:sp
指向的不是正确的栈顶,将引起错误。
那么debug的单步中断是如何避免这个问题的呢?(那么之前实验,出现的单步运行时,mov ss,ax
之后一条指令没有被显示,这个原因我们就知道啦。)
0x01 int指令 中断信息可以来自于CPU的内部或者外部,int指令引发的中断是内中断。int n
的执行过程如下:
Q&A
安装程序如下(安装7cH中断):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 assume cs:code code segment cube: mul ax iret start: mov ax, cs ; ds:[si]->es:[di] mov ds, ax mov si, offset cube mov ax, 0000H mov es, ax mov di, 0200H cld mov cx, offset start - offset cube rep movsb mov ax, 0 ; 设置中断表 mov es, ax mov word ptr es:[7cH*4], 0200H mov word ptr es:[7cH*4+2], 0000H code ends end start
应用程序如下:
1 2 3 4 5 6 7 8 9 10 11 assume cs:code code segment start: ; 计算2*3456^2 mov ax, 3456 int 7cH add ax, ax adc dx, dx mov ax, 4c00H int 21H code ends end start
注:int
与iret
类似于call
与ret
。
安装程序:
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 assume cs:code code segment upper: push si push bx s0: mov bl, ds:[si] cmp bl, 0H je upper_end and bl, 11011111B mov ds:[si], bl inc si loop s0 upper_end: pop bx pop si iret start: mov ax, cs ; ds:[si]->es:[di] mov ds, ax mov si, offset upper mov ax, 0000H mov es, ax mov di, 0200H mov cx, offset start - offset upper cld rep movsb mov ax, 0000H mov es, ax mov word ptr es:[7cH*4], 0200H mov word ptr es:[7cH*4+2], 0000H mov ax, 4c00H int 21H code ends end start
应用程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 assume cs:code, ds:data data segment db 'aaabbb', 0 data ends code segment start: mov ax, data mov ds, ax mov si, 0 int 7cH mov ax, 4c00H int 21H code ends end start
应用程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 assume cs:code code segment start: mov ax, 0b800H mov es, ax mov si, 160*12 mov bx, offset s_end - offset s mov cx, 80 s: mov byte ptr es:[si], '!' add si, 2 int 7cH s_end: mov ax, 4c00H int 21H code ends end start
安装程序:
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 assume cs:code code segment install: push bp mov bp, sp cmp cx, 0 jna install_end dec cx sub [bp+2], bx install_end: pop bp iret start: mov ax, 0000H mov es, ax mov di, 0200H mov ax, cs mov ds, ax mov si, offset install mov cx, offset start - offset install cld ; 控制正向还是反向 rep movsb mov ax, 0000H mov es, ax mov word ptr es:[7cH*4], 0200H mov word ptr es:[7cH*4+2], 0000H mov ax, 4c00H int 21H code ends end start
最大位移为FFFFH。
安装程序为:
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 assume cs:code code segment install: push bp mov bp, sp add ss:[bp+2], bx pop bp iret start: mov ax, cs mov ds, ax mov si, offset install mov ax, 0000H mov es, ax mov di, 0200H mov cx, offset start - offset install cld rep movsb mov ax, 0000H mov es, ax mov es:[7cH*4], 0200H mov es:[7cH*4+2], 0000H mov ax, 4c00H int 21H code ends end start
0x02 BIOS与DOS提供的中断例程 BIOS(Basic Input Output System)在主板ROM中,里面存放着这些内容:
(1)硬件系统的检测与初始化程序。
(2)外部中断与内部中断 的中断例程。
(3)对硬件设备进行I/O操作 的中断例程。
操作系统DOS也提供了中断例程,从操作系统的角度来看,DOS的中断例程就是操作系统向程序员提供的编程资源 。
程序员用int调用BIOS和DOS的中断例程 。
DOS与BIOS的中断例程是如何安装到内存中去的? (1) 开机后CPU初始化(CS)=0FFFFH,(IP)=0,从FFFF:0处开始执行第一条指令,该指令为一条转跳指令。
(2)CPU转去执行BIOS中的硬件系统检测 和初始化程序 (将BIOS的中断例程的入口地址登记在中断向量 表中)。
(3) 硬件系统检测和初始化完成后,调用int 19h
进行操作系统的引导。从此将计算机交由操作系统DOS 控制。
(4)DOS 启动后,除完成其它工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量 。
0x03 BIOS中断例程应用 int 10h
是BIOS提供的中断例程,包含了多个 与屏幕输出相关的子程序。当中断例程包含多个子程序时,用传递的参数来决定执行哪个子程序(用ah
来传递内部子程序的编号) 。
int 10h
举例(设置光标位置 )
1 2 3 4 5 6 7 ah -> 子程序编号 bh -> 页参数 dh -> 行参数 dl -> 列参数 al -> 字符 bl -> 颜色属性 cx -> 字符重复个数
注:在80*25字符模式下,行号取值范围为0-24
,列号取值范围为0-79
。
而bh页号的含义为:
注:BL
颜色属性的格式为:
例子:在屏幕第5行12列显示3个红底高亮闪烁绿色的’a’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 assume cs:code code segment start: ; 设置光标到:第0页-第5行-第12列 mov ah, 2 mov bh, 0 mov dh, 5 mov dl, 12 int 10h mov ah, 9 mov al, 'a' mov bl, 11001010B mov bh, 0 mov cx, 3 int 10h mov ax, 4c00H int 21H code ends end start
0x04 DOS中断例程应用 int 21h
中断例程是DOS提供的中断例程。
例如程序返回功能:
DOS的int 21h
也可以在在光标位置显示字符串,格式如下:
1 2 3 ds:dx ; 指向要显示的字符串,以'$'作为结束符 mov ah, 9 ; 功能号9,表示在光标位置处显示字符串 int 21H
例子,在屏幕的第5行12列显示字符串”Welcome to masm!”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 assume cs:code, ds:data data segment db 'Welcome to masm!$' data ends code segment start: ; 设置光标到:第0页-第12行-第5列 mov ah, 2 mov bh, 0 mov dh, 5 mov dl, 12 int 10h mov ax, data mov ds, ax mov dx, 0 mov ax, 0900H int 21h mov ax, 4c00H int 21H code ends end start
0x05 端口 CPU可以直接读写3个地方的数据:CPU 内部的寄存器;内存单元;端口。
端口读写不能用mov
、push
、pop
等内存读写指令。
端口的读写指令有:in
表示从端口读取数据,out
表示向端口写入数据。
举例说明:in al, 60H
,表示从60h
号端口读入一个字节,执行流程如下:
(1)CPU通过地址总线 将地址信息60h发出;
(2)CPU通过控制总线 发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;
(3)端口所在的芯片将60h端口中的数据通过数据总线 送入CPU。
注:in和out指令与端口进行数据读写时,只能使用固定的寄存器ax
或者al
。
端口读写举例:
1 2 3 4 5 6 7 ; 0-255端口 in al, 20h ;从20h端口读入一个字节 out 20h, al;向20h端口写入一个字节 ; 256-65535端口 mov dx, 3f8H in al, dx ;从3f8H端口读入一个字节 out dx, al ;向3f8H端口写入一个字节
0x06 CMOS RAM芯片 PC机中有一个CMOS RAM芯片,其有如下特征:
(1)包含一个时钟和一个有128字节的RAM存储器。
(2)该芯片靠电池供电。所以,关机后其内部的实时钟仍可正常工作, RAM 中的信息不丢失。
(3)128 个字节的 RAM 中,内部时钟占用 0-0dh单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。
(4)此芯片有两个端口:70h地址端口与71h数据端口。70h存放要访问的CMOS RAM单元的地址;71h存放从选定的CMOS RAM单元中读取的数据,或要写入到其中的数据。
例如,要读取CMOS RAM的2号单元:
1 2 3 mov al, 2 out 70h, al in al, 71h
再比如,写入CMOS RAM的2号单元0。
1 2 3 4 mov al, 2 out 70h, al mov al, 0 out 70h, al
CMOS RAM中有128字节的RAM,其中0-0Dh放着当前时间,具体为:
给出一个题目,如下:
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 assume cs:code code segment start: ; 取出月份信息 mov al, 8 out 70h, al in al, 71h mov ah, al mov cl, 4 shr ah, cl and al, 00001111B ; 将月份信息转为ascii码 add ah, 30H add al, 30H ; 打印到屏幕上 mov bx, 0b800H mov es, bx mov byte ptr es:[160*12+40*2], ah mov byte ptr es:[160*12+40*2+2], al mov ax, 4c00H int 21H code ends end start
0x07 shl与shr指令 逻辑移位指令。例如shl
为左移指令:将一个寄存器或内存单元中的数据向左移位;将移出的一位写入CF中;最低位补0。
当移动位数大于1时,移动位数要放入cl
中。
0x08 外中断 CPU能够执行指令进行运算,并对外部I/O设备进行控制。
PC的主板上有接口芯片,接口芯片内部有很多寄存器,CPU将这些寄存器当作端口来访问。 外设与CPU靠接口芯片(端口)来进行联系,如下所示:
CPU 在执行完当前指令后,可以检测到外设发送过来的中断信息,引发中断过程,处理外设的输入。
中断类型 可屏蔽中断与不可屏蔽中断。可屏蔽中断是CPU可以不立即响应的(可以屏蔽的)外中断。
标志寄存器的IF位决定CPU是否响应可屏蔽中断:
(1)如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程;
(2)如果IF=0,则不响应此可屏蔽中断。
回顾内中断的中断过程:
(1)取中断类型码n
。
(2)标志寄存器入栈,IF=0
,TF=0
;IF=0代表禁止其他的可屏蔽中断。sti
用于设置IF=1,cli
用于设置IF=0
(3)CS、IP入栈。
(4)(IP)=(n*4)
,(CS)=(n*4+2)
,由此转去执行中断处理程序。
内中断的中断类型码是在CPU内部产生的。可屏蔽外中断的信息来自于CPU外部,中断类型码是通过数据总线送入CPU的;
不可屏蔽中断是CPU必须响应的外中断。 当CPU 检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。8086CPU不可屏蔽中断的中断类型码固定为2。
不可屏蔽中断的中断过程为:
(1)标志寄存器入栈,IF=0
,TF=0
;CS、IP入栈。
(2)(IP)=(8)
,(CS)=(0AH)
几乎所有由外设引发的外中断都是可屏蔽中断。
键盘输入的处理过程 (1)键盘输入。(2)引发9号中断。(3)执行int 9
中断例程。
键盘中有芯片扫描键盘上每个键的开关状态:按下一个键时,该芯片产生一个扫描码(通码,对应于按下键的位置),通码被送入主板上的相关接口芯片内端口地址为60H的寄存器。松开按下的键时,产生扫描码(断码,对应于松开键的位置),断码被送入60H端口中。
其中,断码与通码之间的关系为:断码=通码+80h
。具体流程为:
补充:BIOS键盘缓冲区是系统启动后,BIOS用于存放int 9
中断例程所接收的键盘输入的内存区,可以存储15个键盘输入,一个键盘输入用一个字存放,高位存放扫描码,低位存放字符码(ascii)。
如果要按下若是控制键(如 Ctrl )和切换键(如 CapsLock),则会改变键盘状态字节,其具体描述如下:
编写int 9中断例程 题目: 编程在屏幕中间依次显示a-z
,并可以让人看清。在显示的过程中,按下Esc键后,改变显示的颜色。
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 assume cs:code code segment ; 循环100000h次,能让人看清 empty_cycle: push ax push bx mov ax, 0 mov bx, 10h s1: sub ax, 1 sbb bx, 0 cmp ax, 0 jne s1 cmp dx, 0 jne s1 pop bx pop ax ret start: mov bx, 0b800H mov es, bx mov cx, 26 mov al, 'a' s0: mov es:[160*12+40*2], al inc al call empty_cycle loop s0 mov ax, 4c00H int 21H code ends end start
上述代码实现了编程在屏幕中间依次显示a-z
,并可以让人看清,那怎么改变颜色呢?
补充:int
与call
的比较。
那么如果要用call来模仿int的话,就是:
1 2 3 4 5 6 7 pushf ; (1)标志寄存器入栈 pushf ; (2)IF=0,TF=0 pop ax and ah, 11111100B push ax popf call dword ptr ds:[0] ; (3)
题目思路如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 in al, 60h ; (1)从60h端口读取键盘输入 ;(2)由于int 9被重写了,所以不能直接用Int 9来进行步骤2,那么假设旧的int 9入口放在了ds:[0]中,那么就要调用它 pushf pushf pop ax and ah, 11111100B push ax popf call dword ptr ds:[0] ; (3)如何改变颜色呢? ; 字符显示在b800:160*12+40*2;其字符属性的控制字节:b800:160*12+40*2+1。 ; inc b800:[160*12+40*2+1] 就可以改变颜色 ; 注意:要在该程序返回前,将中断向量表中的int 9中断例程的入口地址恢复为原来的地址。否则程序返回后,别的程序将无法使用键盘。
最终程序为:(不用持久化安装int9例程 )
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 assume cs:code, ss:stack, ds:data stack segment db 128 dup(0) stack ends data segment dw 2 dup(0) data ends code segment ;--------------------------- 新的 int 9 例程 ---------------------------- int9: push ax push bx push es in al, 60h ; 获取低位,al内容是ascii码 ; 对int进行模拟 pushf pushf pop bx and bh, 11111100B push bx popf call dword ptr ds:[0] cmp al, 1h ; Esc的扫描码为1 jne int9_end ; Esc改变字符颜色 mov bx, 0b800H mov es, bx inc byte ptr es:[160*12+40*2+1] int9_end: pop es pop bx pop ax iret ;--------------------------- 新的 int 9 例程 --------------------------- ;--------------------------- 空循环 ------------------------------------ ; 循环100000h次,能让人看清 empty_cycle: push ax push bx mov ax, 0 mov bx, 10h s1: sub ax, 1 sbb bx, 0 cmp ax, 0 jne s1 cmp dx, 0 jne s1 pop bx pop ax ret ;--------------------------- 空循环 ------------------------------------ ;--------------------------- 安装新的int 9 例程 ------------------------ int9_install: ; 保存旧的int 9地址到 ds:[2], ds:[0] mov ax, 0000H mov es, ax push es:[9*4] ; 旧的int 9偏移地址 pop ds:[0] push es:[9*4+2] ; 新的int 9段地址 pop ds:[2] ; 设置新的int9的入口地址 ; 0000:[9*4] 中放入 offset int9,0000:[9*4+2] 中放入 cs。 mov ax, 0000H mov es, ax mov es:[9*4], offset int9 mov es:[9*4+2], cs jmp start_1 ;--------------------------- 安装新的int 9 例程 ------------------------ ;--------------------------- 主程序 ----------------------------------- start_0: ; 初始化堆栈 mov ax, stack mov ss, ax mov sp, 128 ; 初始化data段 mov ax, data mov ds, ax ; 安装新的int 9例程 jmp int9_install start_1: ; 屏幕上依次显示a-z mov ax, 0b800H mov es, ax mov cx, 26 mov al, 'a' s0: mov es:[160*12+40*2], al inc al call empty_cycle loop s0 ; 将旧的int 9例程地址放回原位 mov ax, 0000H mov es, ax push ds:[0] pop es:[9*4] push ds:[2] pop es:[9*4+2] ; 程序结束 mov ax, 4c00H int 21H ;--------------------------- 主程序 ----------------------------------- code ends end start_0
题目:安装一个新的int 9中断例程,在DOS下,按Esc键后改变当前屏幕的显示颜色,其他的键照常处理。
注:如何改变屏幕颜色?改变从B800开始的4000个字节中的所有奇地址单元中的内容,当前屏幕的显示颜色即发生改变。
以下是int9_new_install
安装程序:
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 assume cs:code, ss:stack stack segment db 128 dup(0) stack ends code segment ;------------------ int9_new ---------------------------- int9_new: push ax push bx push cx push es ; 取当前键盘输入的元素 in al, 60H ; 放入标志寄存器 pushf pushf pop bx and bx, 11111100B push bx popf mov ax, 0000H mov es, ax call dword ptr es:[0200H] ; 更改屏幕颜色 cmp al, 3BH jne int9_new_end mov ax, 0B800H mov es, ax mov cx, 2000 mov bx, 0 s0: inc byte ptr es:[bx+1] add bx, 2 loop s0 int9_new_end: pop es pop cx pop bx pop ax iret ;------------------ int9_new ---------------------------- ;------------------ main -------------------------------- start: ; 初始化堆栈 mov ax, stack mov ss, ax mov sp, 128 ; 保存int9_old的地址 mov ax, 0000H mov es, ax push es:[9*4] pop es:[0200H] push es:[9*4+2] pop es:[0200H+2] ; 安装int9_new ; ds:[si]->es:[di] mov ax, cs mov ds, ax mov si, offset int9_new mov ax, 0000H mov es, ax mov di, 0210H mov cx, offset start - offset int9_new cld rep movsb ; 改变入口地址 mov ax, 0000H mov es, ax cli mov word ptr es:[9H*4], 0210H mov word ptr es:[9H*4+2], 0000H sti mov ax, 4c00H int 21H ;------------------ main -------------------------------- code ends end start
以下是call
调用程序:
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 assume cs:code, ss:stack stack segment db 128 dup(0) stack ends code segment ;------------------ empty_cycle --------------------- empty_cycle: push ax push bx mov ax, 0 mov bx, 0FFFFH s0: sub ax, 1 sbb bx, 0 cmp ax, 0 jne s0 cmp bx, 0 jne s0 pop bx pop ax ret ;------------------ empty_cycle --------------------- ;------------------ main ---------------------------- start: call empty_cycle mov ax, 4c00H int 21H ;------------------ main ---------------------------- code ends end start
以下是int9_new_uninstall
卸载程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 assume cs:code, ss:stack stack segment db 128 dup(0) stack ends code segment ;------------------ main ---------------------------- start: ; 将旧的 int9 地址还原 mov ax, 0000H mov es, ax push es:[0200H] pop es:[9*4] push es:[0200H+2] pop es:[9*4+2] mov ax, 4c00H int 21H ;------------------ main ---------------------------- code ends end start
调了好久都没调好(不知道为啥,cli无法屏蔽外部中断),什么勾八程序。
CPU对外设输入的处理方法:
(1)外设的输入送入端口;
(2)向CPU 发出外中断(可屏蔽中断)信息;
(3)CPU检测到可屏蔽中断信息,如果IF=1,CPU在执行完当前指令后响应中断,执行相应的中断例程;
(4)可在中断例程中实现对外设输入的处理。