中国DOS联盟论坛

中国DOS联盟

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

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

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » 网络日志(Blog) » 【Redtek】 个人网志(学习笔记)
« [1] [2] [3] [4] [5] [6] [7] [8] [9] »
作者:
标题: 【Redtek】 个人网志(学习笔记) 上一主题 | 下一主题
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 91 楼』:  【80x86汇编语言学习笔记】

Windows计算器使用小窍门:

在汇编语言学习过程中,需要经常用到计算器(Windows CALC.exe)来计算二进制或是进行数字的对比,将数字分组功能打开,就会看到数字间隔,方便一眼略知位数。

[ Last edited by redtek on 2007-1-7 at 11:50 AM ]

附件 1: 1.GIF (2007-1-8 00:49, 18.51 K, 下载附件所需积分 1 点 ,下载次数: 2)




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-8 00:49
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 92 楼』:  【80x86汇编语言学习笔记】

内中断

中断信息可以来自CPU的内部和外部。

对于8086CPU,当CPU内部有下面情况发生时,将产生相应的中断信息:

1) 除法错误      (中断类型码:0)
2) 单步执行      (      1)
3) 执行 int0 指令     (      4)
4) 执行 int 指令     (  int n-提供给CPU的中断类型码)


8086CPU 用称为中断类型码的数据来标识中断信息的来源。
中断类型码为一个字节型数据,可以表示256种中断信息的来源。


中断处理程序

根据CPU的设计,中断类型码的作用就是用来定位中断处理程序。
……


中断向量表

CPU用8位的中断类型骊通过中断向量表找到相应的中断处理程序的入口地址。
中断向量表就是中断向量的列表。

中断向量,就是中断处理程序的入口地址。
中断向量表,就是中断处理程序入口地址的列表。

中断向量表在内存中保存,其中存放着256个中断源所对应的中断处理程序的入口。

CPU只要知道中断类型码,就可将中断类型码作为中断向量表的表项号,定位相应表项,从而得到中断处理程序的入口地址。


内存 0000:0000 到 0000:03E8 的1000个单元中存放着中断向量表。

对于8086CPU,这个入口地址包括段地址和偏移地址,所以一个表项占两个字。高地址字存放段地址,低地址字存放偏移地址。


提问:

1) 4号中断源对应的中断处理程序的入口地址为:(0000:0010)

  Quote:
0000:0000  68 10 A7 00 8B 01 70 00-16 00 A9 03 8B 01 70 00

2) 存储N号中断源对应的中断处理程序入口的偏移地址的内存单元的地址为:(N*4)


3) 存储N号中断源对应的中断处理程序入口的段地址的内存单元的地址为:(N*4+2)



中断过程

8086CPU在收到中断信息后,所引发的中断过程:

  1) 取得中断类型码
  2) 标志寄存器的值入栈
  3) 设置标志寄存器的第8位TF和第9位IF的值为0
  4) CS的内容入栈
  5) IP的内容入栈
  6) 从内存地址为 中断类型码*4 和 中断类型码*4+2 的两个字单元中读取中断处理程序的入口地址设置IP和CS。



描述中断过程:

  1) 取得中断类型码N
  2) pushf
  3) TF=0 ,  IF=0
  4) push CS
  5) push IP
  6) (IP)=(N*4), (CS)=(N*4+2)



中断处理程序


CPU随时都可能检测到中断信息,所以中断处理程序必须一直存储在内存某段空间之中。

中断处理程序的入口地址(中断向量)必须存储在对应的中断向量表项中。


中断处理程序的编写步骤:

1) 保存用到的寄存器
2) 处理中断
3) 恢复用到的寄存器
4) 用 iret 指令返回


iret 指令的功能用汇编语法描述为:

  pop  IP
  pop  CS
  popf

iret 通常和硬件自动完成的中断过程配合使用。
iret指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序。


除法错误中断的处理


CPU执行div等除法指令时,如发生了除法溢出错误,将产生中断类型码为0的中断信息。CPU检测到这个信息,引发中断过程。


编程处理0号中断


编程:当发生了除法溢出错误产生0号中断信息,引发中断过程,CPU执行我们编写的0号中断处理程序。
   在屏幕中间显示提示信息: “overflow!” 后,返回到操作系统中。


编写中断处理程序,当中断0发生时:

  1) 相关处理
  2) 向显示缓冲区送字符串 "overflow!"
  3) 返回DOS


8086支持256个中断,实际系统中要处理的中断事件没有达到256个,在中断向量表中有些单元是空的。

从 0000:0200 至 0000:0300 的256个字节的空间所对应的中断向量表项都是空的,操作系统和其他应用程序都不占用。

可以将自己写的中断处理程序扔到内存 0000:0200 处。那么 0000:0200 就是中断入口地址,把它登记在中断向量表的对应表项中。
-d 0:0200
0000:0200  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0210  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0220  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0230  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0240  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0250  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0260  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
0000:0270  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
……
步骤:

1) 编写可以显示 “overflow!” 的中断处理程序
2) 将程序送入内存 0000:0200 处
3) 将程序的入口地址 0000:0200 存储在中断向量表0号表项中
              assume    cs:code
        code  segment
      start:  mov       ax,cs
              mov       ds,ax       ; 源
              mov       si,offset do0
              mov       ax,0
              mov       es,ax       ; 目标
              mov       di,200h
              mov       cx,offset do0end - offset do0
              cld
              rep       movsb
              mov       ax,0        ; 设置中断向量
              mov       es,ax
              mov       word ptr es:[0*4],200h
              mov       word ptr es:[0*4+2],0
              mov       ax,4c00h
              int       21h

        do0:  jmp       short do0start
              db        "overflow!"
   do0start:  mov       ax,cs
              mov       ds,ax
              mov       si,202h     ; ds:si指向字符串
              mov       ax,0b800h
              mov       es,ax
              mov       di,12*160+36*2
              mov       cx,9
          s:  mov       al,[si]
              mov       es:[di],al
              inc       si
              add       di,2
              loop      s
              mov       ax,4c00h
              int       21h
     do0end:  nop
        code  ends
              end       start
CMD 不支持直接写屏操作,DOS下支持~:)


当发生除法溢出时,那个字符串就跳了出来,然后返回到dos。

  Quote:
C:\Masm50>debug
-a
0AF5:0100 mov ax,1000
0AF5:0103 mov bl,1
0AF5:0105 div bl
0AF5:0107
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=0AF5  CS=0AF5  IP=0100   NV UP EI PL NZ NA PO NC
0AF5:0100 B80010        MOV     AX,1000
-t
                                    overflow!
AX=1000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=0AF5  CS=0AF5  IP=0103   NV UP EI PL NZ NA PO NC
0AF5:0103 B301          MOV     BL,01
-t

AX=1000  BX=0001  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=0AF5  CS=0AF5  IP=0105   NV UP EI PL NZ NA PO NC
0AF5:0105 F6F3          DIV     BL
-t

单步中断

CPU在执行完一条指令后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。

单步中断的中断类型码为1,引发的中断过程如下:

  1) 取得中断类型码1
  2) 标志寄存器入栈,TF、IF设置为0
  3) CS、IP入栈
  4) (ip)=(1*4) , (cs)=(1*4+2)

如果TF=1,则执行一条指令后,CPU就会转去执行1号中断处理程序。

Debug 工具也是这样单步跟踪的原理。

CPU提供单中断功能的原因:为单步跟踪程序的执行过程提供了实现机制。



响应中断的特殊情况
0AF5:0100 mov ax,1000
0AF5:0103 mov ss,ax
0AF5:0105 mov ax,0
0AF5:0108 mov sp,0
0AF5:010B
-r
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=0AF5  CS=0AF5  IP=0100   NV UP EI PL NZ NA PO NC
0AF5:0100 B80010        MOV     AX,1000
-t

AX=1000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=0AF5  CS=0AF5  IP=0103   NV UP EI PL NZ NA PO NC
0AF5:0103 8ED0          MOV     SS,AX
-t

AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=1000  CS=0AF5  IP=0108   NV UP EI PL NZ NA PO NC
0AF5:0108 BC0000        MOV     SP,0000
-t

AX=0000  BX=0000  CX=0000  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0AF5  ES=0AF5  SS=1000  CS=0AF5  IP=010B   NV UP EI PL NZ NA PO NC
编写0号中断的处理程序

在除法溢出发生时,在屏幕中间显示字符串 "divide rror!",然后返回到DOS。
              assume    cs:code

        code  segment
      start:  mov       ax,cs
              mov       ds,ax
              mov       si,offset do0
              mov       ax,0h
              mov       es,ax
              mov       di,200h
              mov       cx,offset doend - offset do0
              cld
              rep       movsb
              mov       ax,0h
              mov       es,ax
              mov       word ptr es:[0*4],200h  ; 0:200 Int 0
              mov       word ptr es:[0*4+2],0h
              mov       ax,4c00h
              int       21h

        do0:  jmp       short do1
              db        "my name is redtek",0
        do1:  mov       ax,cs
              mov       ds,ax
              mov       si,202h
              mov       ax,0b800h
              mov       es,ax
              mov       di,160*20+(160-18*2)/2
              mov       cx,18
              mov       ah,02h
          s:  mov       al,[si]
              mov       es:[di],ax
              inc       si
              add       di,2
              loop      s
              mov       ax,4c00h
              int       21h
      doend:  nop

        code  ends
              end       start
修改中断向量前、后对比:

  Quote:
C:\Masm50>debug
-d 0:0
0000:0000  68 10 A7 00 8B 01 70 00-16 00 A9 03 8B 01 70 00   h.....p.......p.
0000:0010  8B 01 70 00 B9 06 12 02-40 07 12 02 FF 03 12 02   ..p.....@.......
0000:0020  46 07 12 02 0A 04 12 02-3A 00 A9 03 54 00 A9 03   F.......:...T...
0000:0030  6E 00 A9 03 88 00 A9 03-A2 00 A9 03 FF 03 12 02   n...............
0000:0040  A9 08 12 02 A4 09 12 02-AA 09 12 02 5D 04 12 02   ............]...
0000:0050  B0 09 12 02 0D 02 E1 02-C4 09 12 02 8B 05 12 02   ................
0000:0060  0E 0C 12 02 14 0C 12 02-1F 0C 12 02 AD 06 12 02   ................
0000:0070  AD 06 12 02 A4 F0 00 F0-37 05 12 02 94 2D 00 C0   ........7....-..
-q

C:\Masm50>p240.exe

C:\Masm50>debug
-d 0:0
0000:0000  00 02 00 00 8B 01 70 00-16 00 A9 03 8B 01 70 00   ......p.......p.
0000:0010  8B 01 70 00 B9 06 12 02-40 07 12 02 FF 03 12 02   ..p.....@.......
0000:0020  46 07 12 02 0A 04 12 02-3A 00 A9 03 54 00 A9 03   F.......:...T...
0000:0030  6E 00 A9 03 88 00 A9 03-A2 00 A9 03 FF 03 12 02   n...............
0000:0040  A9 08 12 02 A4 09 12 02-AA 09 12 02 5D 04 12 02   ............]...
0000:0050  B0 09 12 02 0D 02 E1 02-C4 09 12 02 8B 05 12 02   ................
0000:0060  0E 0C 12 02 14 0C 12 02-1F 0C 12 02 AD 06 12 02   ................
0000:0070  AD 06 12 02 A4 F0 00 F0-37 05 12 02 94 2D 00 C0   ........7....-..

[ Last edited by redtek on 2007-1-9 at 12:26 AM ]

附件 1: 1.GIF (2007-1-9 13:26, 7.25 K, 下载附件所需积分 1 点 ,下载次数: 1)




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-9 03:49
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 93 楼』:  【80x86汇编语言学习笔记】

Int 指令


格式: int n
相当于引发一个n号中断的中断过程。


1) 取中断类型码n
2) 标志寄存器入栈,IF=0,TF=0
3) CS、IP入栈
4) (IP)=(n*4), (CS)=(n*4+2)


先运行自编的0号中断程序(安装)并修改中断向量表。(位于92楼 P240.EXE)
然后调用 int 0 引发0号中断:
C:\Masm50>debug
-a
0AF5:0100 int 0
0AF5:0102
-g

C:\Masm50>
CPU执行 int 0 指令时,将引发中断过程,执行0号中断处理程序。
而0号中断处理程序的功能就是显示一行字符串(如上:92楼0号中断处理程序)

int 指令的最终功能和call指令相似,都是调用一段程序。



编写供应用程序调用的中断例程


编写、安装中断7ch的中断例程,功能:求一word型数据的平方。

参数:(AX)=要计算的数据
返回:DX、AX中存放结果的高16位和低16位。

求:2*3456^2
              assume    cs:code
        code  segment
      start:  mov       ax,3456
              int       7ch         ; 调用中断 7ch 的中断例程,计算ax中的数据的平方
              add       ax,ax       ; 低位相加
              adc       dx,dx       ; 再加高位和进位
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
1) 编写实现平方功能程序
2) 安装程序
3) 设置中断向量表,指定入口地址

安装程序
              assume    cs:code
        code  segment
      start:  mov       ax,cs       ; 安装代码
              mov       ds,ax
              mov       si,offset sqr
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset sqrend - offset sqr
              cld
              rep       movsb
              mov       ax,0
              mov       es,ax
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h

        sqr:  mul       ax          ; 中断7ch例程
              iret
     sqrend:  nop
        code  ends
              end       start
执行过程验证

  Quote:
C:\Masm50>debug p242.exe
-r
AX=0000  BX=0000  CX=000E  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0000   NV UP EI PL NZ NA PO NC
0B49:0000 B8800D        MOV     AX,0D80
-u
0B49:0000 B8800D        MOV     AX,0D80
0B49:0003 CD7C          INT     7C
0B49:0005 03C0          ADD     AX,AX
0B49:0007 13D2          ADC     DX,DX
0B49:0009 B8004C        MOV     AX,4C00
0B49:000C CD21          INT     21
0B49:000E E270          LOOP    0080
0B49:0010 83C406        ADD     SP,+06
0B49:0013 B8C805        MOV     AX,05C8
0B49:0016 50            PUSH    AX
0B49:0017 8D4680        LEA     AX,[BP-80]
0B49:001A 50            PUSH    AX
0B49:001B E83E0D        CALL    0D5C
0B49:001E 83C404        ADD     SP,+04
-t

AX=0D80  BX=0000  CX=000E  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0003   NV UP EI PL NZ NA PO NC
0B49:0003 CD7C          INT     7C
-p

AX=4000  BX=0000  CX=000E  DX=00B6  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0005   NV UP EI PL NZ NA PO NC
0B49:0005 03C0          ADD     AX,AX
-t

AX=8000  BX=0000  CX=000E  DX=00B6  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0007   OV UP EI NG NZ NA PE NC
0B49:0007 13D2          ADC     DX,DX
-t

AX=8000  BX=0000  CX=000E  DX=016C  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0009   NV UP EI PL NZ NA PE NC

CPU执行 int 7ch 指令进入中断例程之前,标志寄存器、当前的CS和IP被压入栈中,在执行完中断例程后,用 iert 指令恢复 int 7ch 执行前的标志寄存器和CS、IP的值。

int 指令和 iret 指令的配合使用与 call 指令和 ret 指令的配合使用具有相似的思路。



编写、安装中断7ch的中断例程。

功能:将一个全是字母,以0结尾的字符串转化为大写。
参数:ds:si指向字符串的首地址
              assume    cs:code
        data  segment
              db        'conversation',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
7ch 中断例程安装程序
              assume    cs:code
        code  segment
      start:  mov       ax,cs
              mov       ds,ax
              mov       si,offset capital
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset capitalend - offset capital
              cld
              rep       movsb
              mov       ax,0
              mov       es,ax
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h

    capital:  push      cx          ; 保存寄存器值,避免冲突
              push      si
     change:  mov       cl,[si]
              mov       ch,0
              jcxz      ok          ; 遇到字符串尾0,则转向结束
              and       byte ptr [si],11011111b
              inc       si
              jmp       short change
         ok:  pop       si
              pop       cx
              iret
capitalend:  nop
        code  ends
              end       start
跟踪结果

  Quote:
-t

AX=0B49  BX=0000  CX=001F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B4A  IP=0003   NV UP EI PL NZ NA PO NC
0B4A:0003 8ED8          MOV     DS,AX
-t

AX=0B49  BX=0000  CX=001F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B49  ES=0B39  SS=0B49  CS=0B4A  IP=0005   NV UP EI PL NZ NA PO NC
0B4A:0005 BE0000        MOV     SI,0000
-t

AX=0B49  BX=0000  CX=001F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B49  ES=0B39  SS=0B49  CS=0B4A  IP=0008   NV UP EI PL NZ NA PO NC
0B4A:0008 CD7C          INT     7C
-p

AX=0B49  BX=0000  CX=001F  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B49  ES=0B39  SS=0B49  CS=0B4A  IP=000A   NV UP EI PL NZ NA PO NC
0B4A:000A B8004C        MOV     AX,4C00
-d ds:0
0B49:0000  43 4F 4E 56 45 52 53 41-54 49 4F 4E 00 00 00 00   CONVERSATION....
0B49:0010  B8 49 0B 8E D8 BE 00 00-CD 7C B8 00 4C CD 21 C4   .I.......|..L.!.
0B49:0020  04 C7 86 FE FE 00 00 EB-05 90 FF 86 FE FE A1 56   ...............V
0B49:0030  07 39 86 FE FE 73 7D 8B-9E FE FE D1 E3 D1 E3 8B   .9...s}.........
0B49:0040  87 BE 22 0B 87 C0 22 74-E1 8B 9E FE FE D1 E3 D1   .."..."t........
0B49:0050  E3 8B 87 BE 22 8B 97 C0-22 89 86 FA FE 89 96 FC   ...."...".......
0B49:0060  FE C4 9E FA FE 26 8A 47-0C 2A E4 40 50 8B C3 05   .....&.G.*.@P...
0B49:0070  0C 00 52 50 E8 19 46 83-C4 04 50 8D 86 00 FF 50   ..RP..F...P....P

[ Last edited by redtek on 2007-1-9 at 12:05 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-9 23:32
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 94 楼』:  【80x86汇编语言学习笔记】

对 int、iret和栈的深入理解




) 用 7ch 中断例程完成 jmp near ptr s 指令的功能,用bx向中断例程传送转移位移。

  在屏幕的第 12 行显示 data 段中,以 0 结尾的字符串。



调用者:
              assume    cs:code
        data  segment
              db        'conversation',0
        data  ends
        code  segment
      start:  mov       ax,data
              mov       ds,ax
              mov       si,0
              mov       ax,0b800h
              mov       es,ax
              mov       di,160*12

          s:  cmp       byte ptr [si],0
              je        ok
              mov       al,[si]
              mov       es:[di],al
              mov       es:[di].1,al
              inc       si
              add       di,2
              mov       bx,offset s - offset ok
              int       7ch
         ok:  mov       ax,4c00h
              int       21h
        code  ends
              end       start
中断例程:
              assume    cs:code
        code  segment
      start:  mov       ax,cs
              mov       ds,ax
              mov       si,offset do0
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset doend - offset do0
              cld
              rep       movsb
              mov       ax,0
              mov       es,ax
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h

        do0:  push      bp
              mov       bp,sp
              add       [bp+2],bx   ; 设置IP位移量
              pop       bp
              iret
      doend:  nop

        code  ends
              end       start
) 编程:用7ch中断例程完成loop指令的功能。
  在屏幕中间显示80个‘!’。
              assume    cs:code
        code  segment
      start:  mov       ax,0b800h
              mov       es,ax
              mov       di,160*12
              mov       bx,offset s - offset se ; 存储模拟loop的转移位移
          s:  mov       byte ptr es:[di],'!'
              add       di,2
              int       7ch
         se:  nop

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
进入中断处理程序之前的压栈次序:

  标志寄存器入栈,(TF=0、IF=0);
  CS入栈
  IP入栈
  (IP)=(N*4), (CS)=(N*4+2)
  ------------------------------------------------------- 16位

  最后,栈指针(SP)指向最后入栈的16位内容所在的地址。


7ch中断例程……当CPU进行一系列动作时,其压入IP的内容并不是在调用程序中的 int 7ch 所在的IP。
根据CPU执行指令的原理,当CPU读入IP所指向地址的指令时,CPU会另IP指向一下条指令。

所以,当调用 int 7ch 中断之前,CPU 所压入的 IP 是指向一下条指令的,是为了准备执行完当前 int 指令后返回继续执

行之备。

所以,被压入栈的 IP 就是调用代码中“se:  nop”这行 se 标号所在的地址~:)
而且,当要 pop 弹出时,则应逆序要弹出的也是 IP ,所以进入 int 7ch 中断处理程序后,其 SP 一直指向 IP 。

当执行 7ch 中断例程时,调用者已将从 se 到 s 标号的位移(使用 offset 指令计算的)存到了 bx 中。

然后将 CS:IP 指向 s 标号(就是将 CS 指向 s 所在的段地址,让 IP 指向 S 所在的偏移地址就行了)。
当 int 7ch 中断例程内,将栈中所压的 IP 与 CS 值改写以后,当执行 iret 指令时,CPU会自动恢复中断前的寄存器

的值,但这值已被我们修改,所以恢复的就是我们修改过的 CS:IP(它指向了 s 标号处)。


下面是调试出错的代码,当 dec cx (递减)时,cx=0 时再递减就发生了为负值,结果进入了死循环。

  Quote:
AX=B800  BX=FFF7  CX=0000  DX=0000  SP=FFFA  BP=0000  SI=0000  DI=078A
DS=0B39  ES=B800  SS=0B49  CS=0000  IP=0200   NV UP DI PL NZ NA PO NC
0000:0200 55            PUSH    BP
-t

AX=B800  BX=FFF7  CX=0000  DX=0000  SP=FFF8  BP=0000  SI=0000  DI=078A
DS=0B39  ES=B800  SS=0B49  CS=0000  IP=0201   NV UP DI PL NZ NA PO NC
0000:0201 8BEC          MOV     BP,SP
-t

AX=B800  BX=FFF7  CX=0000  DX=0000  SP=FFF8  BP=FFF8  SI=0000  DI=078A
DS=0B39  ES=B800  SS=0B49  CS=0000  IP=0203   NV UP DI PL NZ NA PO NC
0000:0203 49            DEC     CX
-t

AX=B800  BX=FFF7  CX=FFFF  DX=0000  SP=FFF8  BP=FFF8  SI=0000  DI=078A
DS=0B39  ES=B800  SS=0B49  CS=0000  IP=0204   NV UP DI NG NZ AC PE NC
0000:0204 E304          JCXZ    020A

原来在 int 7ch 中多写了一个 dec cx ,jczx 的判断为0语句被夹在中间,这样它永远也不能正确。


调用者:
              assume    cs:code
        code  segment
      start:  mov       ax,0b800h
              mov       es,ax
              mov       di,160*12
              mov       bx,offset s - offset se ; 模拟loop的转移位移
              mov       cx,80
          s:  mov       byte ptr es:[di],'!'
              mov       byte ptr es:[di].1,cl   ; 变换不同颜色
              add       di,2
              int       7ch
         se:  nop

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
7ch 中断例程安装
              assume    cs:code
        code  segment
      start:  mov       ax,cs       ; int 7ch 例程安装
              mov       ds,ax
              mov       si,offset do0
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset doend - offset do0
              cld
              rep       movsb
              mov       ax,0
              mov       es,ax
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h

        do0:  push      bp          ; int 7ch 中断例程
              mov       bp,sp
              dec       cx
              jcxz      lpret       ; 当 cx 值递减至0时结束,准备返回调用者
              add       [bp+2],bx   ; 修改 IP 位移
                                    ; 调用者 se + bx中与 s标号处之间的位移,就是s的偏移量
                                    ; 因为栈中又压入了 bp(占16位,2字节),所以+2指向栈底方向的IP
      lpret:  pop       bp
              iret
      doend:  nop

        code  ends
              end       start
) 上面的内容中,用 7ch 中断例程实现 loop 的功能,上面的 7ch 中断例程所能进行的最大转移位移是多少?
  
  因为 loop 位移是 short 型段内短转移指令。
  它的位移量是有符号数,最大位移范围是: -128 ~~ + 127 



运行界面

[ Last edited by redtek on 2007-1-9 at 09:46 PM ]

附件 1: 1.GIF (2007-1-10 07:38, 11.38 K, 下载附件所需积分 1 点 ,下载次数: 1)




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-10 07:38
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 95 楼』:  【80x86汇编语言学习笔记】

BIOS和DOS所提供的中断例程


在系统板的ROM中存放着一套程序,称为BIOS(基本输入输出系统),BIOS中主要包括:

1) 硬件系统的检测和初始化程序
2) 外部中断和内部中断的中断例程
3) 用于对硬件设备进行 I/O 操作的中断例程
4) 其他和硬件系统相关的中断例程。


操作系统DOS也提供了中断例程。
从操作系统角度来看DOS的中断例程就是操作系统向程序员提供的编程资源。


BIOS和DOS所有提供的中断例程中包含了许多子程序。程序员在编程的时候可以用int指令直接调用中断例程来完成工作。


BIOS和DOS中断例程的安装过程:

1) 开机后,CPU加电,初始化(CS)=0FFFFH,(IP)=0。
   自动从FFFF:0单元开始执行程序。
   FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。

2) 初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。
   对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可,因它是固化到ROM中的程序,一直在内存中。

3) 硬件系统检测和初始化完成后,调用 int 19h 进行操作系统的引导。从此将计算机交由操作系统控制。

4) DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。



BIOS中断例程应用

一个供程序调用的中断例程中往往包括多个子程序,中断例程内部用传递进来的参数来决定执行哪一个子程序。


BIOS和DOS提供的中断程序,都用AH来传递内部子程序的编号。


int 10h 中断例程设置光标位置
              assume    cs:code
        code  segment
      start:  mov       ah,2        ; 调用10号中断例程2号子程序: 置光标位置
              mov       bh,0        ; 0页
              mov       dh,5        ; 行号
              mov       dl,12       ; 列号
              int       10h
              int       20          ; 行: 0~24  列: 0~79

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
置光标位置用在批处理里,可以将光标定位在屏幕的任何地方。
再使用 SET /P=要显示的文字 <NUL 就可以完成类似“填表格”等特殊显示应用。

关于BIOS或是DOS功能调用专门有手册可以查阅,除特殊情况基本都不用记背。

bh 中的页号的含义,显示缓冲区分为8页。(80*25彩色字符模式)每页 160每行 * 25行 = 4000 字节。


int 10h 中断例程在当前光标位置处写属性和字符
              assume    cs:code
        code  segment
      start:  mov       ah,9        ; 调用10h号中断例程9号子程序: 在当前光标位置处写属性和字符
              mov       al,'a'      ; AL=要显示的字符; BH=页号; BL=字符属性; CX=写字符个数
              mov       bh,0
              mov       bl,26
              mov       cx,3
              int       10h
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
在屏幕的5行12列显示红底高亮闪烁(cmd全屏下闪烁无效)绿色的'a'。
              assume    cs:code
        code  segment
      start:  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,10
              int       10h

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
颜色属性

  Quote:
7          6    5     4       3             2     1    0
---------------------------------------------------------------
BL  R G B  I    R G B
------      --------------       -----          ---------------
闪烁  背   景  高亮   前   景

R:红色  G:绿色  B:蓝色

DOS中断例程应用


int 21h中断例程是DOS提供的中断例程,其中包含了DOS提供给程序员在编程时调用的子程序。

int 21h 中断例程 4ch 号功能,结束程序(带返回码结束)。
              mov       ah,4ch
              mov       al,0
              int       21h
int 21h中断例程在光标位置显示字符串功能


在屏幕的5行12列显示字符串:“Welcome to masm”。
              assume    cs:code

        data  segment
              db        'Welcome to masm','$'
        data  ends

        code  segment
      start:  mov       ah,2        ; To 光标:5,12列
              mov       bh,0
              mov       dh,5
              mov       dl,12
              int       10h

              mov       ax,data
              mov       ds,ax
              mov       dx,0
              mov       ah,9
              int       21h

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
5行(是指从0~5),12例(是指从0~12)
$ 本身不显示,起边界作用。



编写应用中断例程


编写并安装 int 7ch 中断例程,功能为显示一个用0结束的字符串,中断例程安装在0:200处。

参数:(DH)=行号,(DL)=列号,(CL)=颜色,DS:SI指向字符串首地址。


inc 7ch 安装程序
              assume    cs:code
        code  segment
      start:  mov       ax,cs       ; 安装
              mov       ds,ax
              mov       si,offset do0
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset doend - offset do0
              cld
              rep       movsb
              mov       ax,0
              mov       es,ax
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h


        do0:  push      dx          ; int 7ch
              push      cx          ; 参数:(DH)=行号,(DL)=列号,(CL)=颜色
              push      ax
              push      di
              push      es
              mov       si,0
              mov       ax,0b800h
              mov       es,ax
              mov       ax,160
              mul       dh
              mov       di,ax
              mov       dh,0
              add       dx,dx
              add       di,dx
          s:  mov       ch,[si]
              cmp       ch,0
              je        send
              mov       es:[di],ch
              mov       es:[di].1,cl
              inc       si
              add       di,2
              jmp       short s
       send:  pop       es
              pop       di
              pop       ax
              pop       cx
              pop       dx
              iret
      doend:  nop
        code  ends
              end       start
调用者
              assume    cs:code
        data  segment
              db        "welcome to masm!",0
        data  ends

        code  segment
      start:  mov       dh,10       ; 行号
              mov       dl,10       ; 列号
              mov       cl,2        ; 颜色
              mov       ax,data
              mov       ds,ax
              mov       si,0
              int       7ch
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
Debug 跟踪观察 int、iret指令执行前后CS、IP和栈中的状态。



编写并安装 int 7ch 中断例程,功能为完成 loop 指令的功能。

参数:(CX)=循环次数, (BX)=位移

在屏幕中间显示80个‘!’。

调用者:
              assume    cs:code
        code  segment
      start:  mov       ax,0b800h
              mov       es,ax
              mov       di,160*12
              mov       bx,offset s - offset se
              mov       cx,80
          s:  mov       byte ptr es:[di],'!'
              add       di,2
              int       7ch
         se:  nop
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
int 7ch 安装
              assume    cs:code
        code  segment
      start:  mov       ax,cs
              mov       ds,ax
              mov       si, offset do0
              mov       ax,0
              mov       es,ax
              mov       di,200h
              mov       cx,offset doend - offset do0
              cld
              rep       movsb
              mov       word ptr es:[7ch*4],200h
              mov       word ptr es:[7ch*4+2],0
              mov       ax,4c00h
              int       21h

        do0:  push      bp
              mov       bp,sp
              dec       cx
              jcxz      doreturn
              add       [bp+2],bx
   doreturn:  pop       bp
              iret
      doend:  nop

        code  ends
              end       start
需要注意的地方

当使用 BP 寄存器时寻址时,所操作的是 SS:[  ]
当使用非 BP 寄存器寻址时,所操作的默认为 DS:[ ] 或指定。

ADD     [BP+02],BX

  Quote:
AX=B800  BX=FFF7  CX=004F  DX=0000  SP=FFF8  BP=FFF8  SI=0000  DI=0782
DS=0B39  ES=B800  SS=0B49  CS=0000  IP=0206   NV UP DI PL NZ AC PO NC
0000:0206 015E02        ADD     [BP+02],BX                         SS:FFFA=0017


-d ss:fffa
0B49:FFF0                                17 00 49 0B 06 32             ..I..2

分别在屏幕的第2、4、6、8行显示四句英文诗,补全程序

  Quote:
              assume    cs:code
        code  segment
         s1:  db        'Good,btter,best,','$'
         s2:  db        'Never let it rest,','$'
         s3:  db        'Till good is better,','$'
         s4:  db        'And better,best.','$'
          s:  dw        offset s1,offset s2,offset s3,offset s4
        row:  db        2,4,6,8

      start:  mov       ax,cs
              mov       ds,ax
              mov       bx,offset s
              mov       si,offset row
              xor       ax,ax
              mov       cx,4
         ok:  mov       bh,0
              mov       dh,[si]     ; 行号
              mov       dl,0        ; 0列
              mov       ah,2
              int       10h

              mov       dx,[bx]
              mov       ah,9
              int       21h


              inc       si          ; 下移指针
              add       bx,2
              loop      ok
              mov       ax,4c00h
              int       21h
        code  ends
              end       start

[ Last edited by redtek on 2007-1-10 at 04:24 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-10 10:50
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
pengfei
银牌会员




积分 1218
发帖 485
注册 2006-7-21
来自 湖南.娄底
状态 离线
『第 96 楼』:  



  Quote:
Originally posted by redtek at 2006-12-10 00:48:
【80x86 汇编语言学习笔记】 —— 一句话学习总结


) 找一本认为最难的书学习,更是为了总结最适合自己的学习方法。
  只有读那些看上去 “最难的” 书,才最能挖掘更适合自己的有效学习规律与方法。

) 读看一本很难读的书,才最容易看到自己思想上与能力上的弱点。

) 学与悟的重点放在书上所讲的原理,就等于拥有了创造一万种方法的灵感与能力。

) 无论是解读汇编语言还是解读任何一本书,其实都是在悟读着自己。

) 某个阶段,读到认为掌握了很多,那就是并没有学透多少;读到好象什么都不会了,那是已经读透了部分,要再继续。

) 读适合启发自己思维方式的书,读这样的书才能加倍成长。

) 基础知识就是巨厦的地基,它的深浅有一半注定了最终的计算机水平,它的另一半是对数学的理解。

) 跟着书读是白读。先拉后跟的读是真读。用自己的思考方式一边超前预想一边读,会把见解与书的思想碰撞,这才是读。

) 学习某种编程语言的过程,如果发现只有死记硬背才能继续学下去,那么这个时候就意味着基础没有掌握好,应去补基础。

) 把需要死记硬背才能向下学习的过程,分解成不需要记忆照样可以学下去的过程,那就是掌握它的原理深度来降低记忆强度。

看了兄写的这段学习总结, 感慨良多, 每一点都命中要害.

以前我读书吊儿郎当, 很容易满足, 自学的一年半年里慢慢地找到了学习的方法, 更重要的是磨练了自己的意志, 如果能够做到为了掌握一个知识点连续作战十几个小时, 还有什么困难可以难倒你.

Redtek兄说的对, 学习重在理解, 做事做人都在于领悟, 也许苦学几载不如一朝顿悟.

过去一失败就垂头丧气, 现在觉得失败或许也是成功的预兆, 要善于失败之后找出自己的不足, 设法弥补它.

思想是重要的, 做任何事情, 自己的决心和态度往往是成败的关键.

开弓没有回头箭, 坚持下去你就是最强的, 最后送兄一句:

得意失意, 切莫在意.  顺境逆境, 切莫止境!



业精于勤而荒于嬉,形成于思而毁于随。
2007-1-10 11:42
查看资料  发送邮件  发短消息 网志  OICQ (573381312)  编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 97 楼』:  

支持!
我学C的情景跟redtek兄学汇编差不多,千军万马中冲出一条血路!

2007-1-10 12:01
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 98 楼』:  

“得意失意, 切莫在意.  顺境逆境, 切莫止境! ”,欣赏~~~

听pengfei兄讲学习感受和GOTOmsdos兄的鼓励真是受益非浅~:)))



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-10 22:17
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 99 楼』:  【80x86汇编语言学习笔记】

端口


各种存府器都和CPU的地址线、数据线、控制线相连。
CPU在操控它们的时候,把它们都当作内存来对待,把它们总的看做一个由若干存储单元组成的逻辑存储器,称其为内存地址空间。



PC机系统中,和CPU通过总线相连的芯片除各种存储器外,还有以下3种芯片:

1) 各种接口卡(网卡、显卡、……)上的接口芯片,它们控制接口卡进行工作
2) 主板上的接口芯片,CPU通过它们对部分外设进行访问
3) 其他芯片,用来存储相关的信息,或进行相关的输入输出处理


从CPU角度,将这些寄存器都当作端口,对它们进行统一编址,从而建立了一个统一端口地址空间。每个端口在地址空间中都有一个地址。


CPU可以直接读写3个地方的数据:

1) CPU内部的寄存器
2) 内存单元
3) 端口



端口的读写


访问端口时CPU通过端口地址来定位端口,端口所在芯片和CPU通过总线相连。端口地址和内存地址一样,通过地址总线来传送。

CPU最多可以定位64K个不同的端口。端口地址的范围为: 0~65535。

in 和 out。



访问端口: 

in al,60h         ; 从60h号端口读入一个字节


执行时与总线相关的操作:

1) CPU通过地址线将地址信息60H发出
2) CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据
3) 端口所在的芯片将60H端口中的数据通过数据线送入CPU



在in和out指令中,只能使用ax或al来存放从端口中读入的数据或要发送到端口中的数据。

访问8位端口时用al,访问16位端口时用ax。



对0~255以内的端口进行读写时:

in  al,20h   ; 从20H端口读入一个字节
out 20h,al   ; 往20H端口写入一个字节


对256~65535的端口进行读写时,端口号放在dx中:

mov dx,3f8h  ; 将端口号3F8H送入dx
in  al,dx    ; 从3F8H读入一个字节
out dx,al    ; 向3F8H端口写入一个字节



CMOS RAM芯片

0~0DH单元保存时间信息,其余大部分用于保存系统配置信息,供系统启动时BIOS程序读取。

芯片内部有两个端口,端口地址为70H和71H。CPU通过这两个端口写CMOS RAM。

70H为地址端口,存放要访问的CMOS RAM单元地址
71H为数据端口,存放从选定的CMOS RAM单元中读取的数据。

CPU对CMOS RAM的读写分两步进行。

例:读CMOS RAM的2号单元:

  1) 将2送入端口70H
  2) 从71H读出2号单元的内容


读取CMOS RAM的2号单元内容
              mov       al,2
              out       70h,al
              in        al,71h
向CMOS RAM的2号单元写入0
C:\Masm50>debug
-a
0AF5:0100 mov al,2
0AF5:0102 out 70,al
0AF5:0104 mov al,0
0AF5:0106 out 71,al
CMOS RAM中存储的时间信息


CMOS RAM 各字节的含义(部分):

===============================================================
偏移值(Offset)    数据字段的意义描述(Description)
---------------------------------------------------------------
00h               目前系统时间的“秒数”字段
01h               预约警铃时间的“秒数”字段
02h               目前系统时间的“分钟”字段
03h               预约警铃时间的“分钟”字段
04h               目前系统时间的“小时”字段
05h               预约警铃时间的“小时”字段
06h               星期几(星期一=01,星期二=02,依次类推)
07h               目前系统日期字段(0~31)
08h               系统公元纪年的后两位(00~99;00=2000,01=2001,以此类推)



(关于上面BIOS更详细的内容,传说中有一本书,研读完了可以自己开发BIOS,哈哈……)

(关于这本书的介绍:   《BIOS研发技术剖析》 )

  Quote:
【内容简介】
本书是全球第一本针对新一代计算机平台的BIOS核心技术做深入剖析的技术性书籍,内附完整的BIOS源代码以及相关的技术文献,完备程度超过二十年前那本IBM BIOS Bible,将这个业界研发技术缺口至少拉近了十八、九年,所以本书的出现,绝对可以说是难得的创举! 本书不仅着重于BIOS的结构剖析,还指导读者如何制作及修改BIOS,更难能可贵的是本书附赠了最重要的源程序代码,让读者能实际动手做BIOS。本书主要针对具有基本汇编语言基础,熟悉DOS操作指令且从事软件开发、编程的读者编写而成。  

索引CMOS内容对照(摘自互联网,原作者不详)

  Quote:
CMOS内容对照
地址 内容 地址 内容 地址 内容 地址 内容
00h Time - Seconds 20h Reserved 40h Extended CMOS 60h User Password
01h Alarm - Seconds 21h Reserved 41h Extended CMOS 61h User Password
02h Time - Minutes 22h Reserved 42h Extended CMOS 62h Extended CMOS
03h Alarm - Minutes 23h Reserved 43h Extended CMOS 63h Extended CMOS
04h Time - Hours 24h Reserved 44h Extended CMOS 64h Extended CMOS
05h Alarm - Hours 25h Reserved 45h Extended CMOS 65h Extended CMOS
06h Date - Day of the week 26h Reserved 46h Extended CMOS 66h Extended CMOS
07h Date - Day 27h Reserved 47h Extended CMOS 67h Extended CMOS
08h Date - Month 28h Reserved 48h Extended CMOS 68h Extended CMOS
09h Date - Year 29h Reserved 49h Extended CMOS 69h Extended CMOS
0Ah Status Register A 2Ah Reserved 4Ah Extended CMOS 6Ah Extended CMOS
0Bh Status Register B 2Bh Reserved 4Bh Extended CMOS 6Bh Extended CMOS
0Ch Status Register C 2Ch Reserved 4Ch Extended CMOS 6Ch Extended CMOS
0Dh Status Register D 2Dh Reserved 4Dh Extended CMOS 6Dh Extended CMOS
0Eh Diagnostic Status 2Eh CMOS Checksum (high byte) 4Eh Extended CMOS 6Eh Extended CMOS
0Fh Shutdown Status 2Fh CMOS Checksum (low byte) 4Fh Extended CMOS 6Fh Extended CMOS
10h A; 30h Extended Memory (high byte) 50h Extended CMOS 70h Extended CMOS
11h Reserved 31h Extended Memory (low byte) 51h Extended CMOS 71h Extended CMOS
12h 0 32h Date - Century 52h Extended CMOS 72h Extended CMOS
13h Reserved 33h Power On Status 53h Extended CMOS 73h Extended CMOS
14h Equipment Installed 34h Reserved 54h Extended CMOS 74h Extended CMOS
15h Base Memory (high byte) 35h Reserved 55h Extended CMOS 75h Extended CMOS
16h Base memory (low byte) 36h Reserved 56h Extended CMOS 76h Extended CMOS
17h Extended Memory (high byte) 37h Reserved 57h Extended CMOS 77h Extended CMOS
18h Extended Memory (low byte) 38h Reserved 58h Extended CMOS 78h Extended CMOS
19h 0 (C:) Hard Disk Type 39h Reserved 59h Extended CMOS 79h Extended CMOS
1Ah 1 (D:) Hard Disk Type 3Ah Reserved 5Ah Extended CMOS 7Ah Extended CMOS
1Bh Reserved 3Bh Reserved 5Bh Extended CMOS 7Bh Extended CMOS
1Ch Supervisor Password 3Ch Reserved 5Ch Extended CMOS 7Ch Extended CMOS
1Dh Supervisor Password 3Dh Reserved 5Dh Extended CMOS 7Dh Extended CMOS
1Eh Reserved 3Eh Reserved 5Eh Extended CMOS 7Eh Extended CMOS
1Fh Reserved 3Fh Reserved 5Fh Extended CMOS 7Fh Extended CMOS

在 CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。这6个信息的长度都为1个字节,存放见上面列表。

这些数据以 BCD 码的方式存放。
BCD码是以4位二进制数表示十进制数码的编方法。


例:数值 26,用BCD码表示为:0010 0110



一个字节可以表示两个BCD码。
CMOS RAM存储时间信息的单元中,存储了用两个BCD码表示的两位十进制数,高4位BCD码表示十位,低4位BCD码表示个位。

例:00010100B表示14。



编程:在屏幕中间显示当前的月份。
              assume    cs:code
        code  segment
      start:  mov       al,8        ; 读 CMOS RAM 8号单元
              out       70h,al
              in        al,71h
              mov       ah,al       ; 分离取出的BCD码为十位和个位
              mov       cl,4
              shr       ah,cl
              and       al,00001111b
              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
编程:以 “年/月/日 时:分:秒” 的格式,显示当前日期、时间。
;---------------------------------------------------
;
;             年/月/日  时:分:秒
;---------------------------------------------------

              assume    cs:code
        data  segment
              db        9,8,7,4,2,0 ; (年月日时分秒)在CMOS中的地址
              db        '/','/',' ',':',':'     ; 日期时间间隔符号
        data  ends
        code  segment
      start:  mov       ax,20h
              mov       ss,ax
              mov       sp,16
              mov       ax,data
              mov       ds,ax
              mov       ax,0b800h
              mov       es,ax
              mov       si,0
              mov       di,0
              xor       ax,ax

              mov       cx,6
          s:  mov       al,[si]     ; 读CMOS信息
              out       70h,al
              in        al,71h
              mov       ah,al       ; 转BCD码
              push      cx
              mov       cl,4
              shr       ah,cl
              pop       cx
              and       al,00001111b
              add       ah,30h
              add       al,30h
              mov       byte ptr es:[160*12+30*2+di],ah
              mov       byte ptr es:[160*12+30*2+di].2,al

              mov       al,ds:[si+6]            ; 显示日期与时间间隔符号
              mov       es:[160*12+30*2+di].4,al

              inc       si
              add       di,6
              loop      s

              mov       ax,4c00h
              int       21h
        code  ends
              end       start
[ Last edited by redtek on 2007-1-11 at 08:36 PM ]

附件 1: 1.GIF (2007-1-12 09:35, 6.59 K, 下载附件所需积分 1 点 ,下载次数: 1)




    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-11 05:30
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
lxmxn
版主




积分 11386
发帖 4938
注册 2006-7-23
状态 离线
『第 100 楼』:  


  好久没有来兄这里看了,惭愧……

  好想和兄一起学习汇编,但是由于学业比较繁重,很多课程都来不及搞,所以只有先把汇编放一放了,等有时间再来和兄一起学习汇编,呵呵,恐怕到那时候兄已经是汇编牛人了,^_^


2007-1-11 09:29
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 101 楼』:  

等兄有时间了我们一起学习更多更好玩的东东~:)
经常看到批处理区兄的精彩代码,水平越来越高,真是为之高兴~:)
希望经常看到兄的创造性思想和好玩的代码~:)))



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-11 23:35
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 102 楼』:  【80x86汇编语言学习笔记】

逻辑移位指令


shl和Shr逻辑移位指令。

shl 左移
shr 右移



SHL逻辑左移指令,功能

1) 将一个寄存器或内存单元中的数据向左移位
2) 将最后移出的一位写入CF中
3) 最低位用0补充



指令:
              assume    cs:code
        code  segment
      start:  mov       al,01001000b
              shl       al,1
              mov       ah,4ch
              int       21h
        code  ends
              end       start
结果:

  Quote:
C:\Masm50>p256.exe

C:\Masm50>echo %errorlevel%
144

返回值144(十进制)它的二进制是:10010000B ,左移了一位~:)



最后移出的一位写入CF中
              assume    cs:code
        code  segment
      start:  mov       al,10010000b
              shl       al,1
              mov       ah,4ch
              int       21h
        code  ends
              end       start
红色标示CF
绿色标示结果

  Quote:
C:\Masm50>debug p256.exe
-r
AX=0000  BX=0000  CX=0008  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0000   NV UP EI PL NZ NA PO NC
0B49:0000 B090          MOV     AL,90
-u
0B49:0000 B090          MOV     AL,90
0B49:0002 D0E0          SHL     AL,1
0B49:0004 B44C          MOV     AH,4C
0B49:0006 CD21          INT     21
0B49:0008 8D867AFE      LEA     AX,[BP+FE7A]
0B49:000C 50            PUSH    AX
0B49:000D E8E270        CALL    70F2
0B49:0010 83C406        ADD     SP,+06
0B49:0013 B8C805        MOV     AX,05C8
0B49:0016 50            PUSH    AX
0B49:0017 8D4680        LEA     AX,[BP-80]
0B49:001A 50            PUSH    AX
0B49:001B E83E0D        CALL    0D5C
0B49:001E 83C404        ADD     SP,+04
-t

AX=0090  BX=0000  CX=0008  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0002   NV UP EI PL NZ NA PO NC
0B49:0002 D0E0          SHL     AL,1
-t

AX=0020  BX=0000  CX=0008  DX=0000  SP=0000  BP=0000  SI=0000  DI=0000
DS=0B39  ES=0B39  SS=0B49  CS=0B49  IP=0004   OV UP EI PL NZ NA PO CY

如果移动位数大于1时,必须将移动位数放在CL中。
              assume    cs:code
        code  segment
      start:  mov       al,01010001b
              mov       cl,3
              shl       al,cl
              mov       ah,4ch
              int       21h
        code  ends
              end       start
左移了3位,值:10001000B



右移,与左移shl操作相反。

1) 将一个寄存器或内存单元中的数据向右移位
2) 将最后移出的一位定入CF中
3) 最高位用0补充


将X逻辑左移一位,相当于执行 X=X*2
将X逻辑右移一位,相当于执行 X=X/2





编程:用加法和移位指令计算(AX)=(AX)*10


加法运算(AX)=(AX)*10
运算 3*10
              assume    cs:code
        code  segment
      start:  mov       ax,0
              mov       cx,10
          s:  add       ax,3
              loop      s
              mov       ah,4ch
              int       21h
        code  ends
              end       start
结果

  Quote:
C:\Masm50>p258.exe

C:\Masm50>echo %errorlevel%
30

移位指令计算(AX)=(AX)*10
计算 3*10

X左移1位就相当于X*2
X左移2位…………  X*4
X左移3位…………  X*8

(AX)*10=(AX)*2+(AX)*8
(AX)*10=(AX)左移1位+(AX)左移3位
              assume    cs:code
        code  segment
      start:  mov       al,3
              mov       cl,3
              shl       al,cl
              add       al,3
              add       al,3
              mov       ah,4ch
              int       21h
        code  ends
              end       start
[ Last edited by redtek on 2007-1-11 at 12:08 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-11 23:50
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
ccwan
金牌会员




积分 2725
发帖 1160
注册 2006-9-23
来自 河北廊坊
状态 离线
『第 103 楼』:  

这样的网志堪称经典了,向兄学习。



三人行,必有吾师焉。   学然后知不足,教然后知困,然后能自强也。
2007-1-12 06:54
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 104 楼』:  

有ccwan兄的不断鼓励,我准备把这网志写溢出了,哈哈……

[ Last edited by redtek on 2007-1-11 at 08:44 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-12 09:39
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
redtek
金牌会员





积分 2902
发帖 1147
注册 2006-9-21
状态 离线
『第 105 楼』:  【80x86汇编语言学习笔记】

外中断


接口芯片和端口


在PC系统的接口卡和主板上,装有各种接口芯片。
这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口来访问。


外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中。
CPU向外设输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。

CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的端口中,然后再由相关的芯片根据命令对外设实施控制。


CPU通过端口和外部设备进行联系。


外中断信息


在PC系统中,外中断源一共有两类:

1) 可屏蔽中断


可屏蔽中断中CPU可以不响就的外中断。
IF=1,则CPU在执行完当前指令后响应中断,引发中断过程。
IF=0,则不响应可屏蔽中断。

IF位于FLAG第9位。


关于中断所引发的中断过程:

1) 取中断类型码N
2) 标志寄存器入栈 IF=0,TF=0
3) CS、IP入栈
4) (IP)=(N*4), (CS)=(N*4+2)

可屏蔽中断所引发的中断过程,除与第1步实现上有所不同外,基本和内中断的中断过程相同。

因为可屏蔽中断信息来自于CPU外部,中断类型是通过数据总线送入CPU的。
而内中断的中断类型码是在CPU内部产生的。

将IF置0的原因:在进入中断处理程序后,禁止其他的可屏蔽中断。


如果在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置1:
8086CPU提供设置IF指令:


  STI  用于设置IF=1 (允许响应中断)
  CLI  用于设置IF=0 (不响应中断)


2) 不可屏蔽中断


不可屏蔽中断是CPU必须响应的外中断。


对于8086CPU,不可屏蔽中断的中断类型码固定为2。
所以中断过程中,不需要取中断类型码。



不可屏蔽中断的中断过程为:

  1) 标志寄存器入栈 IF=0, TF=0;
  2) CS、IP入栈
  3) (IP)=8, (CS)=(0AH)



几乎所有由外设引发的外中断,都是可屏蔽中断。



PC机键盘的处理过程


键盘输入的处理过程:

1) 键盘产生扫描码
2) 扫描码送入60H端口
3) 引发9号中断
4) CPU执行INT9中断例程处理键盘输入

上面第1、2、3步均由硬件完成。



BIOS键盘缓冲区是系统启动后,BIOS用于存放INT9中断例程所接收键盘输入的内存区,可存储15个键盘输入。

INT9中断例程除了接收扫描码外,还要产生和扫描码对应的字符码,所以BIOS键盘缓冲区中,一个键盘输入用一个字单元存放。

高位字节存放扫描码,低位字节存放字符码。


0040:17 单元存储键盘状态字节,该字节记录了控制键和切换键的状态。




显示从 a ~~ z :
              assume    cs:code
        code  segment
      start:  mov       ax,0b800h
              mov       es,ax
              mov       ah,'a'
          s:  mov       es:[160*12+40*2],ah
              inc       ah
              cmp       ah,'z'
              jna       s
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
简单延时-循环
              assume    cs:code
        code  segment
      start:  mov       dx,0afffh
              mov       ax,0ffffh
          s:  sub       ax,1
              sbb       dx,0
              cmp       ax,0
              jne       s
              cmp       dx,0
              jne       s
              mov       ax,4c00h
              int       21h
        code  ends
              end       start
显示从 a ~~ z 字母,每隔一定时间显示下一个字母
              assume    cs:code
       stack  segment
              db        128 dup (0)
       stack  ends
        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128
              mov       ax,0b800h
              mov       es,ax
              mov       ah,'a'
          s:  mov       es:[160*12+40*2],ah
              call      delay
              inc       ah
              cmp       ah,'z'
              jna       s
              mov       ax,4c00h
              int       21h


      delay:  push      ax          ; 循环延时
              push      dx
              mov       dx,1000h
              mov       ax,0
         s1:  sub       ax,1
              sbb       dx,0
              cmp       ax,0
              jne       s1
              cmp       dx,0
              jne       s1
              pop       dx
              pop       ax
              ret

        code  ends
              end       start
键盘输入到达60H端口后,就会引发9号中断,CPU则转去执行INT9中断例程。要求编写INT9中断例程,功能如:

1) 从60H端口读出键盘的输入
2) 调用BIOS的INT9中断例程,处理其他硬件细节
3) 判断是否为ESC键扫描码,如果是,改变显示的颜色后返回;
   如果不是则直接返回。


编写自己的INT9中断例程,但原INT9有一些复杂的硬件细节处理,所以在我们自己的INT9中断例程中还要调用原INT9。

所以,在中断向量表内将INT9中断例程入口地址改写为我们自己的中断例程前,需要先保存原INT9。


当保存原INT9中断例程的偏移地址和段地址后,再调用它时就不能使用INT9来调用了。需要用别的指令来对INT指令进行模拟。


在用其它指令对INT指令进行模拟前,需要先看一下INT指令在执行的时候CPU是如何工作的:

1) 取中断类型码 N
2) 标志寄存器入栈
3) IF=0、 TF=0
4) CS、IP入栈
5) (IP)=(N*4), (CS)=(N*4+2)


取中断类型码是为了定位中断例程的入口地址。
但是,当我们将原INT9中断入口地址保存到另一个内存区域时,我们就不需要中断类型码了,因为我们知道那块自己指定的在内存在哪。




假设已将原INT9中断例程的入口地址保存到了 ds:0 与 ds:2 单元中。现在模拟int过程:

1) 标置寄存器入栈
2) IF=0、TF=0
3) CS、IP入栈
4) (IP)=((DS)*16+0) , (CS)=((CS)*16+2)


上面第3步是CS、IP入栈,因为如果不入栈调用完中断或是子程序就回不到调用者了。
不过,如果是引发INT中断例程的话,CPU是会帮我们做保存CS与IP(入栈)的,所以不用我们自己来。

可是,现在不是要调用INT中断例程,因为原INT9已被我们备份到另一个地址(它的入口地址已经不在中断向量表项中了)。所以我们如果需要调用INT9(就是要执行它,然后再返回到调用者处)就必须使用call命令。

而CALL命令有一个特点:执行CALL命令时,IP指向CALL命令下一条指令(为的是将来返回调用者继续执行CALL后面的指令)。如果CALL是段内CALL,则CPU将IP压栈(不用我们压,这个过程是CPU自动完成的);如果CALL是段间(即:CS:IP)方式,则CPU会自动压入CS、IP(都要压入,不然回不来了)。

所以,上面的CALL的过程和INT调用过程在压入CS、IP入栈的过程是一模一样的。




CALL与调用中断例程不一样的地方是:调用中断例程时CPU自动先压标志寄存器,然后……

而CALL执行时CPU压IP或是CS:IP,但它并不压标志寄存器入栈。
所以如果想用CALL来模拟调用中断例程的方式使用存在另一块内存地址的 DS:0 和 DS:2 的原INT9中断例程,则需要我们:

  (1) 自己压入标志寄存器
  (2) 自己设置IF=0,TF=0(这些得自己做,CALL指令不会帮我们做的,只有INT调用CPU才会帮我们做)
  (3) 使用 call dword ptr ds:[0] 的方式(4字)调用原INT9入口地址,执行原INT9例程。




如何将标志寄存器入栈? 

pushf指令可以实现。



如何将标志寄存器的IF与TF的值设置为0?

  IF 标志寄存器的第9位 
  TF 标志寄存器的第8位

关于IF与TF的含义:

  IF 表示可屏蔽中断
  TF 表示单步中断



为什么要禁止单步中断?

当TF=1(允许单步中断)时,CPU在执行完一条指令后将此发单步中断,转去执行中断处理程序。

而中断处理程序也是由一条条指令组成,如果在执行中断处理程序之前,TF=1,则CPU在执行完中断处理程序的第一条指令后又要产生单步中断,则又要转去执行单步中断的中断处理程序,在执行完中断处理程序的第一条指令后,又要产生单步中断,则又要转去执行单步中断的中断处理程序……无穷无尽的下去……

所以,有时候必须将TF=0(设置为禁卡单步中断),这样才能正确的连续的执行需要的过程。


不可屏蔽的中断类型码固定为:2
中断过程中不需要取中断类型码。不可屏蔽中断过程的寻址部分:

  (IP)=(8), (CS)=(0AH)

其实上面的计算过程如下原理:

  (IP)=(2*4)
  (CS)=(2*4+2)

  不可屏蔽中断是在系统中有必须处理的紧急情况发生时用来通知CPU的中断信息。




编程:在屏幕中间依次显示 a~~z ,延时处理显示在屏幕上。
   在显示过程中,按下 Esc 键后,改变显示颜色。

              assume    cs:code
       stack  segment
              db        128 dup (0)
       stack  ends
        data  segment
              dw        0,0
        data  ends
        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128

              mov       ax,data
              mov       ds,ax

              mov       ax,0
              mov       es,ax

              push      es:[9*4]    ; 备份原int 9中断例程入口地址
              pop       ds:[0]
              push      es:[9*4+2]
              pop       ds:[2]

              mov       word ptr es:[9*4],offset int9
              mov       es:[9*4+2],cs

              mov       ax,0b800h   ; 显示从 'a'~'z' 字母
              mov       es,ax
              mov       ah,'a'
          s:  mov       es:[160*12+40*2],ah
              call      delay       ; 延时
              inc       ah
              cmp       ah,'z'
              jna       s
              mov       ax,0
              mov       es,ax

              push      ds:[0]      ; 恢复原int9中断向量表项中的入口地址
              pop       es:[9*4]
              push      ds:[2]
              pop       es:[9*4+2]

              mov       ax,4c00h
              int       21h


      delay:  push      ax          ; 延时子程序
              push      dx
              mov       dx,1000h
              mov       ax,0
         s1:  sub       ax,1
              sbb       dx,0        ; 再计算高位并减去借位
              cmp       ax,0
              jne       s1
              cmp       dx,0
              jne       s1          ; 当 ax 与 dx 值都为0时才算递减尽
              pop       dx
              pop       ax
              ret


       int9:  push      ax          ; ------------------------------
              push      bx          ; 自定义 int 9 中断例程
              push      es          ; ------------------------------

              in        al,60h

              pushf                 ; 备份标志寄存器的值
              pushf                 ; 压入标志寄存器用来修改IF、TF值
              pop       bx
              and       bh,11111100b
              push      bx
              popf                  ; 弹出修改好的flag值,修改当前标志寄存器值

              call      dword ptr ds:[0]

              cmp       al,1        ; 比对是否按了 Esc 键 (Esc 键扫描码: 01 )
              jne       int9ret

              mov       ax,0b800h
              mov       es,ax
              inc       byte ptr es:[160*12+40*2+1]         ; 改变颜色

    int9ret:  pop       es
              pop       bx
              pop       ax
              iret

        code  ends
              end       start
) 分析上面int9中断例程,精简指令

  进入中断例程后,IF和TF都已经置0。

  
  pushf
  pushf
  pop ax
  and ah,11111100b
  push ax
  popf
  call dword ptr ds:[0]
  
  上面批令可以精简为:

  
  pushf
  call dword ptr ds:[0]
  
精减后的全部代码如下:
              assume    cs:code
       stack  segment
              db        128 dup (0)
       stack  ends
        data  segment
              dw        0,0
        data  ends
        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128

              mov       ax,data
              mov       ds,ax

              mov       ax,0
              mov       es,ax

              push      es:[9*4]    ; 备份原int 9中断例程入口地址
              pop       ds:[0]
              push      es:[9*4+2]
              pop       ds:[2]

              mov       word ptr es:[9*4],offset int9
              mov       es:[9*4+2],cs

              mov       ax,0b800h   ; 显示从 'a'~'z' 字母
              mov       es,ax
              mov       ah,'a'
          s:  mov       es:[160*12+40*2],ah
              call      delay       ; 延时
              inc       ah
              cmp       ah,'z'
              jna       s
              mov       ax,0
              mov       es,ax

              push      ds:[0]      ; 恢复原int9中断向量表项中的入口地址
              pop       es:[9*4]
              push      ds:[2]
              pop       es:[9*4+2]

              mov       ax,4c00h
              int       21h


      delay:  push      ax          ; 延时子程序
              push      dx
              mov       dx,1000h
              mov       ax,0
         s1:  sub       ax,1
              sbb       dx,0        ; 再计算高位并减去借位
              cmp       ax,0
              jne       s1
              cmp       dx,0
              jne       s1          ; 当 ax 与 dx 值都为0时才算递减尽
              pop       dx
              pop       ax
              ret


       int9:  push      ax          ; ------------------------------
              push      bx          ; 自定义 int 9 中断例程
              push      es          ; ------------------------------

              in        al,60h

              pushf                 ; 备份标志寄存器的值
              call      dword ptr ds:[0]

              cmp       al,1        ; 比对是否按了 Esc 键 (Esc 键扫描码: 01 )
              jne       int9ret

              mov       ax,0b800h
              mov       es,ax
              inc       byte ptr es:[160*12+40*2+1]         ; 改变颜色

    int9ret:  pop       es
              pop       bx
              pop       ax
              iret

        code  ends
              end       start
) 分析上面主程序
  在主程序中,如果执行设置INT9中断例程的段地址和篇移地址的指令之间发生了键盘中断,
  则CPU将转去一个错误的地址并执行,将发生错误。
  
排除潜在错误的完全代码:
              assume    cs:code
       stack  segment
              db        128 dup (0)
       stack  ends
        data  segment
              dw        0,0
        data  ends
        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128
              mov       ax,data
              mov       ds,ax
              mov       ax,0
              mov       es,ax

              cli                   ; 不响应可屏蔽中断
              push      es:[9*4]    ; 备份原int 9中断例程入口地址
              pop       ds:[0]
              push      es:[9*4+2]
              pop       ds:[2]
              mov       word ptr es:[9*4],offset int9
              mov       es:[9*4+2],cs
              sti                   ; 响应可屏幕中断

              mov       ax,0b800h   ; 显示从 'a'~'z' 字母
              mov       es,ax
              mov       ah,'a'
          s:  mov       es:[160*12+40*2],ah
              call      delay       ; 延时
              inc       ah
              cmp       ah,'z'
              jna       s
              mov       ax,0
              mov       es,ax

              cli
              push      ds:[0]      ; 恢复原int9中断向量表项中的入口地址
              pop       es:[9*4]
              push      ds:[2]
              pop       es:[9*4+2]
              sti
              mov       ax,4c00h
              int       21h


      delay:  push      ax          ; 延时子程序
              push      dx
              mov       dx,1000h
              mov       ax,0
         s1:  sub       ax,1
              sbb       dx,0        ; 再计算高位并减去借位
              cmp       ax,0
              jne       s1
              cmp       dx,0
              jne       s1          ; 当 ax 与 dx 值都为0时才算递减尽
              pop       dx
              pop       ax
              ret


       int9:  push      ax          ; ------------------------------
              push      bx          ; 自定义 int 9 中断例程
              push      es          ; ------------------------------
              in        al,60h
              pushf                 ; 备份标志寄存器的值
              call      dword ptr ds:[0]
              cmp       al,1        ; 比对是否按了 Esc 键 (Esc 键扫描码: 01 )
              jne       int9ret

              mov       ax,0b800h
              mov       es,ax
              inc       byte ptr es:[160*12+40*2+1]         ; 改变颜色

    int9ret:  pop       es
              pop       bx
              pop       ax
              iret

        code  ends
              end       start
 
 
 
  


编程:安装新的 int 9 中断例程,使得原 int 9 中断例程的功能得到扩展。
   在DOS下,按F1键后改变当前屏幕的显示颜色,其他的键照常处理。
              assume    cs:code

       stack  segment
              db        128 dup (0)
       stack  ends

        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128
              push      cs
              pop       ds
              mov       ax,0
              mov       es,ax
              mov       si,offset int9
              mov       di,204h
              mov       cx,offset int9end - offset int9
              cld
              rep       movsb
              push      es:[9*4]
              pop       es:[200h]
              push      es:[9*4+2]
              pop       es:[202h]
              cli
              mov       word ptr es:[9*4],204h
              mov       word ptr es:[9*4+2],0
              sti
              mov       ax,4c00h
              int       21h



       int9:  push      ax
              push      bx
              push      cx
              push      es
              in        al,60h
              pushf
              call      dword ptr cs:[200h]
              cmp       al,3bh
              jne       int9ret
              mov       ax,0b800h
              mov       es,ax
              mov       bx,1
              mov       cx,2000
          s:  inc       byte ptr es:[bx]
              add       bx,2
              loop      s
    int9ret:  pop       es
              pop       cx
              pop       bx
              pop       ax
              iret
    int9end:  nop

        code  ends
              end       start
在 Windows CMD 下调试先运行安装程序。然后进入一个16位程序界面(DEBUG、EDIT等),然后在里面按F1键有效。

此代码正常运行环境: MS-DOS





编程:安装新的 int 9 中断例程

   在DOS下,按下 “A” 键后,除非不再松开,如果松开,就显示满屏幕 “A” ,其他键照常处理。

   按下一个键时产生的扫描码称为通码
   松开一个键时产生的扫描码称为断码
   断码=通码+80H
              assume    cs:code

       stack  segment
              db        128 dup (0)
       stack  ends

        code  segment
      start:  mov       ax,stack
              mov       ss,ax
              mov       sp,128
              push      cs
              pop       ds
              mov       si,offset int9
              mov       ax,0
              mov       es,ax
              mov       di,204h
              mov       cx,offset int9end - offset int9
              cld
              rep       movsb
              push      es:[9*4]
              pop       es:[200h]
              push      es:[9*4+2]
              pop       es:[202h]
              cli
              mov       word ptr es:[9*4],204h
              mov       word ptr es:[9*4+2],0
              sti
              mov       ax,4c00h
              int       21h

       int9:  push      ax
              push      bx
              push      cx
              push      es
              in        al,60h
              pushf
              call      dword ptr cs:[200h]
              add       al,80h
              cmp       al,1eh
              jne       int9iret
              mov       ax,0b800h
              mov       es,ax
              mov       bx,0
              mov       cx,2000
          s:  mov       byte ptr es:[bx],'A'
              add       bx,2
              loop      s
   int9iret:  pop       es
              pop       cx
              pop       bx
              pop       ax
              iret
    int9end:  nop

        code  ends
              end       start
上面的代码原理从个人理解角度讲,已经可以做好玩的东东了~:)



指令系统总结

1 数据传送指令
2 算术运算指令
3 逻辑指令
4 转移指令
5 处理机控制指令
6 串处理指令

[ Last edited by redtek on 2007-1-13 at 11:06 PM ]



    Redtek,一个永远在网上流浪的人……

_.,-*~'`^`'~*-,.__.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._,_.,-*~'`^`'~*-,._
2007-1-12 09:44
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
« [1] [2] [3] [4] [5] [6] [7] [8] [9] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


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



论坛跳转: