微机原理与接口技术笔记
汇编语言(8086为例)
—-基于《汇编语言第三版》王爽
1.基础知识
- 8086 CPU的简介
(1) 16位微处理器;
(2) 采用高速运算性能的
HMOS
工艺制造,芯片上集成了2.9万只晶体管;(3) 使用单一的
+5V
电源,40
条引脚双列直插式封装;(4) 时钟频率为
5MHz~10MHz
,基本指令执行时间为0.3ms~0.6ms
;(5) 16根数据线和 20根地址线,可寻址的地址空间达
1MB
(毕竟 16根地址线只可以寻址 64KB,太小了) ;
- 冯诺依曼架构
冯·诺伊曼结构(英语:Von Neumann architecture),也称范·诺伊曼模型(Von Neumann model)或普林斯顿结构(Princeton architecture),是一种将程序指令存储器和数据存储器合并在一起的电脑设计概念结构。该结构包含:运算器、控制器、存储器、输入设备、输出设备。
结构特点:
- 以运算单元为中心
- 采用存储程序原理
- 存储器是按地址访问、线性编址的空间
- 控制流由指令流产生
- 指令由操作码和地址码组成
- 数据以二进制编码
- 存储单元
1 KB=1024 B(字节)
1 字(word)=2 字节
1 B=8 bit
- 总线
总线包含:数据总线,地址总线,控制总线
地址总线:假设一个CPU有N根地址总线(即地址总线宽度为N),最多可以寻找2的N次方个内存单元。
数据总线:N根数据总线一次可以传输N位二进制数据。
8088 CPU数据总线宽度为8;8086 CPU数据总线宽度为16。
控制总线:N根代表N种控制。
2.寄存器
一个典型的CPU由:运算器,控制器,寄存器等器件构成。同时他们通过总线在内部相连接(地址,数据,控制)。对于汇编程序员来说,CPU的主要器件就是寄存器。
8086寄存器特征:16位 (数据最大为2^16-1)
8086 CPU的寄存器种类:
- AX
- BX
- CX
- DX // 以上四个为通用寄存器,用于存放一般性数据
- SI
- DI
- SP
- BP
- IP
- CS
- SS
- 通用寄存器
AX,BX,CX,DX四个寄存器通常用来存放一般性数据,因此内成为通用寄存器。
8086的上一代CPU的寄存器是8位的,为了兼容性,这四个寄存器也可以当丞8个8位寄存器使用。
AX—-AH,AL
BX—-BH,BL
CX—-DH,DL
DX—-DH,DL (L和H指的是low和high,即低位和高位)
- 8086 CPU的物理地址给出方法
物理地址=段地址*16+偏移地址 (段地址*16 可以理解为段地址向左移四位)
一个物理地址可以可以有不同的段地址和偏移地址
偏移地址为16位,寻址能力为2^16即 64 KB,所以一个段的长度不能超过 64 KB
- 段寄存器
8086 CPU 的段寄存器:
- CS
- DS
- SS
- ES
- CS 和 IP
对于8086 CPU来说,CS和IP一起指示了当前要读取指令的地址:CS :IP ,执行该位置的语句后IP会自动增加,从而可以进行下一指令的执行。
CS 和 IP 寄存器的修改
*
- 情况一:当你在写汇编脚本或者直接向内存中写入汇编指令时
1
2
3
4
5
6
7
使用 JMP 指令
使用方法: JMP 段地址:偏移地址
eg: JMP 2AE3:3 //CS=2AE3,IP= 0003(均为16进制)
或者(不想改变段地址时)
JMP ax, # 修改IP为 AX的值- 情况二: 在debug.exe(MASM32)中想要修改当前程序运行位置时(后面将会介绍)
1
2
3
4
5例如在 dosBox中:
debug.exe #进入debug模式
-r CS
CS 073f
:XXXX(输入你需要位置) # IP寄存器同理,通用寄存器也同上代码段
即定义一片区域用于输入需要执行的代码。
- debug的使用
1 | -r #显示CPU各个寄存器的值 |
3.寄存器(内存访问)
- 字型数据
CPU用16位寄存器存在出一个字。高八位存放高位字节,低八位存放低位字节。
- DS和[address]
物理地址=段地址*16+偏移地址 (段地址16 可以理解为段地址向左移四位),因此如果想要读写某个地址,首先应该知道其段地址和偏移地址,8086 CPU通过寄存器DS来获取段地址,[N]来表示偏移地址,*[ … ]用来表示一个内存单元()**。
注意:8086CPU 不支持将数据直接送入段寄存器。
- 字型数据的传送
eg:
1 | mov bx,1000H |
- 栈
使用8086 CPU编程时,可以将一段内存当做栈来使用。提供入栈和出栈指令,即PUSH 和 POP
任意时刻,SS:SP 指向栈顶元素
同时,可以通过设置 SS,SP 寄存器的数据来修改栈的容量,地址。
push pop指令
1 | push [0] ;将 DS :0 处的字压入栈 |
4.第一个程序
- 源程序(后缀 .asm)的编写
1 | ;1.asm |
5.[bx]和loop指令
bx
[bx]也表示一个内存单元,它的偏移地址在bx中
loop
通用寄存器CX存储循环次数,循环一次:(cx)= (cx)- 1;
案例程序:
- 实现2^12
1 | assume cs:code |
- 实现将内存
ffff:0 ~ ffff:b
单元中的数据复制到0:200 ~ 0:20b
单元中。
1 | assume cs:code |
6.包含多个段的程序
- 在代码中使用数据
1 | ;计算 8 个数据的和存到 ax 寄存器 |
- 在代码中使用栈
1 | ;利用栈,将程序中定义的数据逆序存放。 |
- 将数据、代码、栈放入不同的段
1 | assume cs:code,ds:data,ss:stack |
7.更灵活灵活的定位内存地址的方法
* **and 和 or 指令**
1 | mov al , 01100011B |
- ASCII
- 以字符的形式给出数据
1 | assume cs:code,ds:data |
- 大小写转换
小写字母的ASCII码值比大写字母的ASCII码值大20H
大写字母ASCII码的第5位为0,小写字母的第5位为1(其他一致)
1 | assume cs:codesg,ds:datasg |
- SI 和 DI
SI 和 DI 是8086 CPU中和 bx 功能相近的寄存器,但是 SI 和 DI 不能分成连个该8为寄存器使用。
idata : 立即数,直接的数据
1 | mov ax, 1 ;对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中) |
- 处理数据的长度
8086CPU的指令,可以处理两种尺寸的数据,byte和word(字节和字)。
通过寄存器名指明要处理的数据的尺寸。
例如: mov al, ds:[0] 寄存器al指明了数据为1字节在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以为word或byte。
例如:mov byte ptr ds:[0], 1 byte ptr 指明了指令访问的内存单元是一个字节单元有些指令默认了访问的是字单元还是字节单元
例如,push [1000H],push 指令只进行字操作。
- div指令、dd、dup、mul指令
div :除法指令。
除数:有8位和16位两种,在一个寄存器或内存单元中。
被除数:默认放在AX或DX和AX中,
如果除数为8位,被除数则为16位,默认在AX中存放;
如果除数为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。结果:
如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数;
如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。
1 | ;利用除法指令计算100001/100。 |
dd:
db 和 dw 定义字节型数据和字型数据。
dd 是用来定义dword(double word,双字(四个字节))型数据的伪指令
1 | dd 100001 |
操作符:
与db、dw、dd等数据定义伪指令配合使用,用来进行数据的重复
1 | db 3 dup (0) ;定义了3个字节,它们的值都是0,相当于db 0,0,0。 |
mul 指令 :
mul是乘法指令,使用 mul 做乘法的时候:相乘的两个数:要么都是8位,要么都是16位。
乘数:
- 8 位:
AL
中和8位寄存器
或内存字节单元
中;- 16 位:
AX
中和16 位寄存器
或内存字单元
中。结果:
- 8位:AX中;
- 16位:DX(高位)和 AX(低位)中
1 | ; 8 位 |
8.数据处理的两个基本问题
寻址方式
只有四个寄存器可以通过 [ … ] 进行内存单元的寻址
- 以下代码为错误代码
1 | mov ax,[cx] |
- 在 [ … ] 中四个寄存器可以单独出现,或只能以四种组合出现
- bx 和 si
- bx 和 di
- bp 和 si
- bp 和 di
1 | mov ax,[bx+si] |
处理的数据的大小
- 一般是字或者字节
在没有寄存器名的情况下可以使用
X ptr
指明内存单元的长度
1 | mov word ptr ds:[0],1 |
9.转移指令
可以修改IP,或同时修改CS和IP的指令统称为转移指令。概括地讲,转移指令就是可以控制CPU执行内存中某处代码的指令。
1 | jmp ax ; 段内转移 |
offset
操作符offset在编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址。
1 | ;将s处的一条指令复制到s0处 |
jmp指令
jmp 为无条件转移,转到标号处执行指令可以只修改IP,也可以同时修改CS和IP;
jmp 指令要给出两种信息:
转移的目的地址
转移的距离(段间转移、段内短转移,段内近转移)
jmp short 标号 jmp near ptr 标号 jcxz 标号 loop 标号 等几种汇编指令,它们对 IP的修改是根据转移目的地址和转移起始地址之间的位移来进行的。在它们对应的机器码中不包含转移的目的地址,而包含的是到目的地址的位移距离。
- jmp short 标号
- 实现段内短转移修改范围(-128-127)
1 | assume cs:code |
- jmp near ptr
- 实现段内近转移(修改范围大于(-128-127)但是小于-32768~32767,编译成功但链接失败),这是jmp short 实现不了的。
1 | assume cs:code |
- jmp far ptr
- 实现段间转移(修改范围超过-32768~32767)
1 | assume cs:code |
- 转移地址在寄存器或内存中的jmp指令
- jmp 寄存器,直接修改ip为寄存器的值
- jmp word ptr 内存单元
1 | mov ax, 0123H |
jxcz 标号
如果(cx)=0,转移到标号处执行;若(cx) != 0,继续向下执行
1 | assume cs:code,ds:data,ss:stack |
10.call和ret指令
- ret和retf
- ret指令用栈中的数据,修改IP的内容,从而实现近转移
对于ret:相当于一次 pop,把数据放在ip里
- retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移。
对于ret:相当于两次 pop,第一次数据放在ip里,第二次放cs里
- call指令
类似于jmp,但是多了一个功能:将当前的 IP 或 CS和IP 压入栈中,此外,call没有短转移
- call和ret的连招
1 | assume cs:code |
10.错题
一、下列关于8086CPU的工作原理的描述错误的是__3__。
1、 汇编程序员可以通过对各种寄存器中内容的修改实现对CPU的控制。
2、 CPU在访问内存时,采用“段地址*16+偏移地址”的形式给出要访问的内存单元的物理地址。
3、 任意时刻,CS:IP指向的内容即是此刻CPU正在执行的指令。
4、 传送指令能够更改所有通用寄存器的内容。注解:
1、正确,见课本P13 2、正确 3、错误。课本P24,8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。此处的含义是**将要执行**,比如输入T,CPU读取CS:IP的内容,载入指令执行,而不是正在执行。 4、通用寄存器是AX、BX、CX、DX,传送指令是mov,mov指令可以改变4个通用寄存器的内容
六、下列说法中正确的是:4
1、 8086CPU采用“段地址*16+偏移地址=物理地址”的寻址模式,所以内存是由一个一个的段组成,每一个段有一个段地址。
2、 物理地址为ffff0H的内存单元的偏移地址可能为ffffH。
3、 一个段的大小可以是8Byte。
4、 在一段没有任何跳转指令的程序中,超出64K的部分将不会被执行。注解:
1、第一句、第三句正确,第二句错误。内存没有分段,段的划分来自于CPU.见课本P22 2、错误,不可能,若偏移地址为FFFFH,则段地址为EFFF1H,是不对的 3、段大小最小16B(Byte) 4、正确,CPU执行指令取决于CS;IP,IP最大65535,超过64K的IP不识别,CPU也就无法执行。
五、16位结构的CPU 不一定具备的特性是:4
1、 运算器一次最多可以处理16位的数据
2、 寄存器的最大宽度为16位
3、 寄存器和运算器之间的通路为16位
4、 地址总线为16根注解:见课本P18
16位CPU特征:运算器一次最多可以处理16位的数据
寄存器的最大宽度为16位
寄存器和运算器之间的通路为16位
8086CPU有20根地址总线,可以传送20位地址。故选择4
5.若将以1000H为段地址的整个段空间当作栈使用,那么寄存器SP的初始值最合理的设置是_____。 (1)
1、 0000H
2、 0001H
3、 FFFFH
4、 FFFEH注解:以1000H为段地址的整个段空间,偏移地址为0-FFFFH,当栈中只有1个字时,偏移地址是FFFEH,当栈为空时,SP=SP+2=FFFF+2=0000,所以选择1
下列指令的书写正确的是: 3 。
1、 push al
2、 mov cs:[0],ds:[10]
3、 pop si
4、 mov ds:[0],2解析:答案1错误,压堆指令一次性操作一个字;答案2错误,内存空间之间不能互相传送;答案3正确;答案4错误,不能将立即数送入内存空间