文章目录
1.debug的六种指令
Debug是DOS、Windows都提供的实模式(8086)程序的调试工具。使用它可以查看CPU各种寄存器中的内容、内存情况和在机器码级跟踪程序的运行。
- 用Debug的R命令查看、改变CPU寄存器的内容
- 用Debug的D命令查看内存中的内容
- 用Debug的E命令改写内存中的内容
- 用Debug的U命令将内存中的机器指令翻译成汇编指令
- 用Debug的T命令执行一条机器指令
- 用Debug的A命令以汇编指令的格式在内存中写入一条机器指令
实操:
- 用Debug的R命令查看、改变CPU寄存器的内容
- 首先输入debug进入Debug模式
- 然后输入
r
查看寄存器内容 - 输入
r ax
可以改变ax中的内容 - 输入
5678
回车,即可看见AX=5678
-
用Debug的D命令查看内存中的内容
如果想要知道内存10000H处的内容,可以用“d 段地址:偏移地址”的格式进行查看
-
输入
d 1000:0
-
输入
d 0000:9
可见它从第九位开始输出内容
-
-
用Debug的E命令改写内存中的内容
-
如果我们想改写
0000:0000
地址以后的数据 -
我们输入
e 0000:0000 12 23 34 45 56 67 78
代表从0000:0000
这个地址往后7个地址进行改写 -
我们输入
d 0000:0000
进行查看可见0000:0000
往后7个地址内容已经被改变
-
我们可以输入
e 0000:0000
回车 然后会出现逐个改变 -
我们将
12->AB 23->CD
回车 -
输入
d 0000:0000
可以查看内容已经被更改
-
-
用Debug的A命令以汇编指令的格式在内存中写入一条机器指令
- 我们输入
a 073F:0100
回车 - 输入
add bx,ax
回车,再输入mov cx,ax
指令,回车
- 我们输入
-
用Debug的T命令执行一条机器指令
-
我们连续
t
即可执行上面写入的机器指令 -
可见
BX:0000->5678 CX:0000->5678
-
-
用Debug的U命令将内存中的机器指令翻译成汇编指令
-
我们输入
d 073F:0100
可见内存中有01 C3 89 C1
-
然后输入
u 073F:0100
可见将指令翻译成汇编指令
-
2.mov、add、sub指令
1.mov指令
mov 寄存器,数据
mov ax,8
mov 寄存器,寄存器
mov ax,bx
mov 寄存器,内存单元
mov ax,[0]
mov 内存单元,寄存器
mov [0],ax
mov 段寄存器,寄存器
mov ds,ax
- 我们输入
a 073F:0100
输入指令 - 然后输入三次
t
执行指令 - 可见
AX:0000->0008 BX:0000->0008 CX:0000->1000
mov ah,13
意思就是将13赋给ax的高八位AX:0008->1308
mov bl,22
意思就是将22赋给bx的低八位BX:0008->0022
mov ch,ah
意思就是将ah的高八位给cx的高八位CX:1000->1300
2.add指令
add 寄存器,数据
add ax,8
add 寄存器,寄存器
add ax,bx
add 寄存器,内存单元
add ax,[0]
add 内存单元,寄存器
add [0],ax
- 我们输入
a
将指令存进去 add ax,3
意思就是将ax+3,因为十六进制08+03=B
,所以1308->130B
add bx,4
意思就是将bx+4,因为十六进制22+04=26
,所以0022->0026
add cx,bx
意思就是将bx加到cx身上,因为十六进制0026+1300=1326
3.sub指令
sub 寄存器,数据
sub ax,9
sub 寄存器,寄存器
sub ax,bx
sub 寄存器,内存单元
sub ax,[0]
sub 内存单元,寄存器
sub [0],ax
- 我们输入
a
将指令存进去 sub ax,8
意思就是ax-8,所以130B-8=1303
sub bx,F
意思就是bx-F,所以0026-F=0017
sub ax,bx
意思就是ax-bx,所以1303-0017=12EC
3.其它指令
1.mul指令
mul指令是乘法指令
注意点:
- 两个相乘的数:两个相乘的数,要么都是8位,要么都是16位。如果8位,一个默认放在AL中,另一个放在8位reg或内存字节单元中;如果是16位,一个默认放在AX中,另一个放在16位reg或内存字单元中。
- 结果:如果是8位乘法,结果默认是放在AX中;如果是16位乘法,结果高位默认放在DX中,低位在AX中放。
实操:
mov ax,64
mov bx,A
- 使用
t
指令操作指令存放数据 mul bl
0064*000A=03E8
mov ax,64
mov bx,2710
mul bx
- 因为是十六进制,所以
64*2710=F4240
高位在DX中存放,低位在AX中存放
2.div指令
div是除法指令,使用div做除法的时候应该注意以下问题:
- 除数:有8位和16位两种,在一个reg或内存单元中。
- 被除数:默认放在AX或DX和AX中,如果除数为2位,被除数则为16位,默认在AX中存放;如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位
- 结果:如果除数为8位,则AL存储除法操作的商,AH存储除数操作的余数;如果除数为16位,则AX存储除数操作的商,DX存储除数操作的余数。
实操:
mov ax 2711
mov bl,64
div b1
- 2711的十进制10001,64十进制100,10001/100余数为1,存放在AH
3.and指令
逻辑与指令,按位进行与运算
例如指令:
mov al,01100011B
and al,00111011B
执行结果:al = 00100011B
(两位都为1才为1)
通过该指令可将操作对象的相应为设为0,其他位不变
4.or指令
逻辑或指令,按位进行或运算
例如指令:
mov al,01100011B
or al,00111011B
执行结果:al = 01111011B
(只要一位为1就为1)
通过该指令可将操作对象的相应位设位1,其他位不变
5.shl指令
shl是逻辑左移指令,它的功能为:
- 将一个寄存器或内存单元中的数据向左移位
- 将最后移出的一位写入CF中
- 最低位用0补充
指令:mov al 01001000B
shl al,1
执行结果:al = 10010000b CF=0
6.shr指令
shr是逻辑右移指令,它的功能:
- 将一个寄存器或内存单元中的数据向右移位
- 将最后移出的一位写入CF中
- 最低位用0补充
如果移动位数大于1,必须将移动位数放在cl中
mov al,01010001b
mov cl,3
shl al,cl
执行结果:al = 10001000b CF = 0
上述操作:左移一位变成90,右移一位回到48
7.inc指令
类似于i++操作
8.dec指令
类似于i–操作
9.xchg指令
- 作用:用于交换两个数据的内容的一个指令
10.neg指令
- 即用0减操作数,并将求得的结果存入指定的寄存器或内存单元(把操作数按位取反,末位加1)
4.寄存器
1.通用寄存器
8086CPU的所有寄存器都是16位,可以存放两个字节。AX、BX、CX、DX这四个寄存器通常用来存放一般性数据,被称为通用寄存器。
8086CPU的AX、BX、CX、DX这四个寄存器都可分为两个可独立使用的8位寄存器来使用:
- AX可分为AH和AL
- BX可分为BH和BL
- CX可分为CH和CL
- DX可分为DH和DL
2.字在寄存器中的存储
8086CPU可以一次性处理以下两种尺寸的数据:
- 字节:记为byte,一个字节由8个bit组成,可以存在8位寄存器中
- 字:记为word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节
3.物理地址
CPU访问内存单元时,要给出内存单元的地址。所有内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们称为物理地址。
CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。在CPU向地址总线上发出物理地址之前,必须要在内部先形成这个物理地址。不同的CPU可以有不同的形成物理地址的方式。
8086CPU有20位地址总线,可以传送20位地址,达到1MB的寻址能力。8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。从8086CPU的内部结构来看,如果将地址简单的发出去,那么它只能送出16位地址,表现出的寻址能力只有64KB。
4.段地址x16+偏移地址=物理地址
- 本质含义:CPU在访问内存时,用一个基=基础地质(段地址X16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
5.CS和IP
CS和IP是8086CPU中两个最关键的寄存器,他们指示了CPU当前要读取指令的地址。CS为代码寄存器,IP为指令指针寄存器。
在8086CPU中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存MX16+N单元开始,读取一条指令并执行。
- 我们存放几条指令,发现
t
指令没有执行 - 然后我们将cs和ip指向
2000:0000
然后执行t
指令,发现指令执行
6.jmp指令
-
作用:同时修改CS、IP的内容,可用形如
jmp 段地址:偏移地址
的指令完成 -
例如:
-
jmp 2AE3:3
执行后:CS = 2AE3H IP = 0003H
CPU将从2AE33H开始读取指令 -
jmp 3:0B16
执行后:CS = 0003H IP = 0B16H
CPU将从30B16开始读取指令 -
jmp ax
指令执行前:AX = 1000H CS = 2000H IP = 0003H
执行指令后:
AX = 1000H CS = 2000H IP = 1000H
-
-
jmp 某一合法寄存器
之类的功能:用寄存器中的值修改为IP -
jmp ax
在含义上好似:mov IP,ax
实操:
- 输入以上指令
- 我们首先执行
t
指令执行,发现AX:0006->6622
- 再次执行
t
指令,可见CS和IP的地址变成了1000:0003
- 执行
t
指令,发现AX:6622->0000
- …
7.push、pop指令
8086CPU中,有两个寄存器,段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素。push和pop指令执行时,CPU从SS和SP中得到栈顶的地址。
实操:
- 将10000H-1000FH这段空间当作栈,初始状态栈是空的
- 设置AX=001AH,BX=001BH
- 将AX和BX中的数据入栈
- 然后将AX、BX清零
- 从栈中恢复AX、BX原来的内容
代码如下:
mov ax,1000H
mov ss,ax ;不能直接向段寄存器中送入数据,所以用ax中转
mov sp,0010H
mov ax,001AH
mov bx,001BH
push ax
push bx
sub ax,ax ;将ax清零
sub bx,bx
pop bx ;恢复AX,BX中原来内容,所以需要先pop bx,再
pop ax
pop ax
5.寻址方式
1.[bx+idata]
我们用[bx]来指明一个内存单元,还可以用一种更为灵活的方式来指明内存单元。[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata(bx中的数值加上idata)
mov ax,[bx+200]
将一个内存单元的内容送入ax,这个内存单元的长度为2个字节,存放一个字,偏移地址为bx中的数值加上200,段地址在ds中
实操:
- 首先我们在内存
2000:1000
写入数据BE 00 06
- 然后使用
a
指令存入指令 - 使用
t
指令操作指令 - 发现
mov ax,2000H
执行后AX: 0000->2000
- 发现
mov ds,ax
执行后DS:073F->2000
- 发现
mov bx,1000H
执行后BX:0000->1000
- 发现
mov ax,[bx]
执行后AX:2000->00BE
- 发现
mov cx,[bx+1]
执行后CX:0000->0006
2.[bx+si]、[bx+di]
[bx+si]表示一个内存单元,它代表的偏移地址为(bx)+(si)
mov ax,[bx+si]
将一个内存单元的内容送入ax,这个内存单元的长度为2字节,存放一个字,偏移地址为bx中的数值加上si中的数值,段地址在ds中
实操:
- 首先我们使用
a
指令存入数据 - 我们使用
t
指令执行指令 - 发现
mov ax,[bx+si]
执行后AX:2000->00BE
- 发现
mov cx,[bx+si]
执行后CX:0000->0600
- 发现
add cx,[bx+di]
执行后CX:0600->0606
6.标志寄存器
1.ZF
零标志位,它记录相关的指令执行后,其结果是否为0,如果结果为0,那么ZF=1;如果结果不为0,那么ZF=0
实操:
mov ax,1
sub ax,1
结果为0,ZF=1
mov ax,2
sub ax,1
结果为1,ZF=0
2.PF
奇偶标志位,它记录相关的指令执行后,其结果的所有bit位中1的个数是否为偶数。如果1的个数为偶数,PF=1,如果为奇数,PF=0。
实操:
mov al,1
add al,10
结果为:00001011B,3(奇数)个1,则PF=0
3.SF
符号标志位,它记录相关的指令执行后,其结果是否为负。如果为负数,SF=1,如果非负,SF=0。
实操:
mov al,10000001B
add al,1
结果为:10000010B
SF=1
mov al,10000001B
add al,0111111B
结果:0
SF=0
4.CF
进位标志位,一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从更高位的借位值。
5.OF
在进行有符号数运算的时候,结果如果超过了机器所能表示的范围,称为溢出。
溢出标志位,发生溢出,OF=1,没有溢出,OF=0。
、