1.基础知识(1)
2.基础知识(2)
2.1由机器语言到汇编语言
2.1.1机器语言与机器指令
- 机器语言是机器指令的集合
- 机器语言是机器指令的集合
- 机器指令由一串二进制数表示,例01010000
2.1.2汇编语言与汇编指令
- 汇编语言的主体是汇编指令
- 汇编指令和机器指令的差别在于指令的表示方法上
- 汇编指令和机器指令的差别在于指令的表示方法上
- 汇编指令是机器指令的助记符
- 寄存器:CPU中可以存储数据的器件。一个CPU中有多个寄存器。
机器指令:1000100111011000
操作:将寄存器BX的内容送到AX中
汇编指令:MOV AX,BX
2.1.3用汇编语言编写程序的工作过程
2.2计算机的组成
-
主板上有::CPU:总线:内存(条):扩展槽(接外部设备)
2.2.1计算机的组成
- CPU是计算机的核心部件,它控制整个计算机的运作并进行运算。要想让一个CPU工作,就必须向它提供指令和数据。
- 指令和数据在存储器(内存)中存放。离开了内存,性能再好的CPU也无法工作。
2.2.2指令和数据的表示
- 计算机中的数据和指令,存储在内存或磁盘上。
- 数据和指令,都是二进制信息。
- 问题:二进制信息1000100111011000是数据,还是指令?
- 1000100111011000─>89D8H(数据)
- 1000100111011000─>MOVAX,BX(程序)
- 数据如何表示?
- 1000100111011000B(二进制);
- 89D8H(十六进制);
- 104730O(八进制);
- 35288D(十进制)
- 数据量:B、KB、MB、GB、TB...
2.2.3计算机中的存储单元
存储器被划分为若干个存储单元,每个存储单元从0开始顺序编号
2.2.4计算机中的总线
- 在计算机中专门有连接CPU和其他芯片的导线,通常称为总线。
- 物理上:一根根导线的集合;逻辑上划分为.地址总线.数据总线.控制总线
2.2.5三类总线
- CPU是通过地址总线来指定存储单元的。地址总线宽度,决定了可寻址的存储单元大小。N根地址总线(宽度为N),对应寻址空间2N。
- CPU与内存或其它器件之间的数据传送是通过数据总线来进行的。数据总线的宽度决定CPU和外界的数据传送速度。例:向内存中写入数据89D8H时的数据传送
- CPU通过控制总线对外部器件进行控制。控制总线是一些不同控制线的集合。控制总线宽度决定了CPU对外部器件的控制能力。
2.3内存的读写与地址空间
2.3.1CPU对存储器的读写
- CPU要想进行数据的读写,必须和外部器件进行三类信息的交互:
- 存储单元的地址(地址信息)
- 器件的选择,读或写命令(控制信息)
- 读或写的数据(数据信息)
机器码:101000000000001100000000
16进制:A00300
汇编指令:MOV AL,[3]
含义:从3号单元读取数据送入寄存器AL
2.3.2内存地址空间
- CPU地址总线宽度为N,寻址空间为2NB;8086CPU的地址总线宽度为20,那么可以寻址1MB个内存单元,其内存地址空间为1MB
- 从CPU角度看地址空间分配
2.3.3将各类存储器看作一个逻辑存储器——统一编址
- 所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器;
- 每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间;
- CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。
3.寄存器
3.1寄存器及数据存储
3.1.1CPU的组成
- 运算器进行信息处理;
- 寄存器进行信息存储;
- 控制器协调各种器件进行工作;
- 内部总线实现CPU内各个器件之间的联系。
3.1.2寄存器是CPU内部的信息存储单元
- 8086CPU有14个寄存器:
- 通用寄存器:AX、BX、CX、DX;
- 变址寄存器:SI、DI;
- 指针寄存器:SP、BP;
- 指令指针寄存器:IP;
- 段寄存器:CS、SS、DS、ES;
- 标志寄存器:PSW
- 共性;8086CPU所有的寄存器都是16位的,可以存放两个字节。
- 通用寄存器均可以分为两个独立的8位寄存器使用
3.1.3“字”在寄存器中的存储
-
8086是16位CPU;8086的字长(wordsize)为16bit
-
一个字(word)可以存在一个16位寄存器中;
-
这个字的高位字节存在这个寄存器的高8位寄存器;
-
这个字的低位字节存在这个寄存器的低8位寄存器
-
3.2mov和add指令
注意:汇编指令不区分大小写
3.2.1汇编指令执行的结果
3.3确定物理地址的方法
3.3.1物理地址
- CPU访问内存单元时要给出内存单元的地址。
- 所有的内存单元构成的存储空间是一个一维的线性空间。
- 每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址称为物理地址。
- 事实:
- 8086有20位地址总线,可传送20位地址,寻址能力为1M。
- 8086是16位结构的CPU.运算器一次最多可以处理16位的数据,寄存器的最大宽度为16位。
- 在8086内部处理的、传输、暂存的地址也是16位,寻址能力也只有64KB
3.3.28086CPU给出物理地址的方法
- 8086CPU的解决方法:用两个16位地址(段地址、偏移地址)合成一个20位的物理地址。
- 地址加法器合成物理地址的方法:物理地址=段地址×16+偏移地址
3.4内存的分段表示法
3.4.1用分段的方式管理内存
- 8086CPU用“(段地址×16)+偏移地址=物理地址”的方式给出内存单元的物理地址。
- 内存并没有分段,段的划分来自于CPU!
3.4.2同一段内存,多种分段方案
- 段地址×16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;
- 偏移地址为16位,16位地址的寻址能力为64K,所以一个段的长度最大为64K。
3.4.3段寄存器
- CS-代码段寄存器
- DS-数据段寄存器
- SS-栈段寄存器
- ES-附加段寄存器
3.5CS、IP与代码段
3.5.1两个关键的寄存器
- CS:代码段寄存器
- IP:指令指针寄存器
- CS:IP:CPU将内存中CS:IP指向的内容当作指令执行。
3.6jmp指令
3.6.1修改CS、IP的指令
- 事实:执行何处的指令,取决于CS:IP
- 应用:可以通过改变CS、IP中的内容,来控制CPU要执行的目标指令
- 问题:如何改变CS、IP的值?
- 方法1:Debug中的R命令可以改变寄存器的值——rcs,rip;Debug是调试手段,并非程序方式!
- 方法2:用指令修改
-
- 方法3:转移指令jmp
3.6.2转移指令jmp
- 同时修改CS、IP的内容: jmp段地址:偏移地址
- jmp2AE3:3
- jmp3:0B16
- 功能:用指令中给出的段地址修改CS,偏移地址修改IP。
- 仅修改IP的内容jmp某一合法寄存器jmpax(类似于movIP,ax)
- jmpbx功能:用寄存器中的值修改IP。
3.7内存中字的存储
3.7.1字单元
- 字单元:由两个地址连续的内存单元组成,存放一个字型数据(16位)
- 原理:在一个字单元中,低地址单元存放低位字节,高地址单元存放高位字节
- 在起始地址为0的单元中,存放的是4E20H
- 在起始地址为2的单元中,存放的是0012H
- 问题:
- (1)0地址单元中存放的字节型数据是( 20H)
- (2)0地址字单元中存放的字型数据是( 4E20H)
- (3)2地址单元中存放的字节型数据是( 12H)
- (4)2地址字单元中存放的字型数据是( 0012H)
3.8用DS和[address]实现字的传送
3.8.1要解决的问题:CPU从内存单元中要读取数据
-
要求;CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址;
-
原理;在8086PC中,内存地址由段地址和偏移地址组成(段地址:偏移地址)
-
解决方案:DS和[address]配合:
-
用DS寄存器存放要访问的数据的段地址;
-
偏移地址用[...]形式直接给出
-
3.8.2字的传送
3.9DS与数据段
3.9.1对内存单元中数据的访问
- 对于8086PC机,可以根据需要将一组内存单元定义为一个段。
- 物理地址=段地址×16+偏移地址;
- 将一组长度为N(N≤64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。
- 例:用123B0H~123B9H的空间来存放数据;
- 段地址:123BH 起始偏移地址:0000H 长度:10字节;
- 段地址:1230H起始偏移地址:00B0H长度:10字节;
- 处理方法:(DS):([address])
- 用DS存放数据段的段地址;
- 用相关指令访问数据段中的具体单元,单元地址由[address]指出
3.9.2练习
3.9.3用mov指令操作数据
指令形式 | 例示 |
mov寄存器,数据 | mov ax,8 |
mov寄存器,寄存器 | mov ax,bx |
mov寄存器,内存单元 | mov ax,[0] |
mov内存单元,寄存器 | mov[0],ax |
mov段寄存器,寄存器 | mov ds,ax |
3.9.4加法add和减法sub指令
3.10栈及栈操作的实现
3.10.1栈结构
- 栈是一种只能在一端进行插入或删除操作的数据结构。
- 栈有两个基本的操作:入栈和出栈。
- 入栈:将一个新的元素放到栈顶;
- 出栈:从栈顶取出一个元素。
- 栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出。
- 栈的操作规则:LIFO(LastInFirstOut,后进先出)
- CPU提供的栈机制
- 现今的CPU中都有栈的设计。
- 8086CPU提供相关的指令,支持用栈的方式访问内存空间。
- 基于8086CPU的编程,可以将一段内存当作栈来使用。
PUSH(入栈)和POP(出栈)指令
push ax:将ax中的数据送入栈中
pop ax:从栈顶取出数据送入ax(以字为单位对栈进行操作)
- 8086CPU中,有两个与栈相关的寄存器
- 栈段寄存器SS-存放栈顶的段地址
- 栈顶指针寄存器SP-存放栈顶的偏移地址
- ——任意时刻,SS:SP指向栈顶元素。
3.10.2栈的操作
3.10.3push指令和pop指令的执行过程
3.10.4栈的小结
- push、pop实质上就是一种内存传送指令,可以在寄存器和内存之间传送数据,与mov指令不同的是,push和pop指令访问的内存单元的地址不是在指令中给出的,而是由SS:SP指出的。:
- 执行push和pop指令时,SP中的内容自动改变。
- 8086CPU提供的栈操作机制:
- 在SS,SP中存放栈顶的段地址和偏移地址,入栈和出栈指令根据SS:SP指示的地址,按照栈的方式访问内存单元。
- push指令的执行步骤:
- 1)SP=SP-2;
- 2)向SS:SP指向的字单元中送入数据。
- pop指令的执行步骤:
- 1)从SS:SP指向的字单元中读取数据;
- 2)SP=SP-2
3.11段的总结
- 基础:
- 物理地址=段地址×16+偏移地址
- 做法:
- 编程时,可以根据需要将一组内存单元定义为一个段。
- 可以将起始地址为16的倍数,长度为N(N≤64K)的一组地址连续的内存单元,定义为一个段。
- 将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元——在程序中可以完全由程序员安排。
- 三种段
- 数据段.
- 将段地址放在DS中.
- 用mov、add、sub等访问内存单元的指令时,CPU将我们定义的数据段中的内容当作数据段来访问;
- 代码段.
- 将段地址放在CS中,将段中第一条指令的偏移地址放在IP中.
- CPU将执行我们定义的代码段中的指令;
- 栈段.
- 将段地址放在SS中,将栈顶单元的偏移地置放在SP中.
- CPU在需要进行栈操作(push、pop)时,就将我们定义的栈段当作栈空间来用。
- 数据段.
4.[BX]和loop指令
4.1[...]和(...)
4.1.1[...]的规定与(...)的约定
- [...]——(汇编语法规定)表示一个内存单元
- (...)——(为学习方便做出的约定)表示一个内存单元或寄存器中的内容
4.1.2约定:符号idata表示常量
例:
- mov ax,[idata]:代表movax,[1]、movax,[2]、movax,[3]...
- mov bx,idata:代表movbx,1、movbx,2、movbx,3...
- mov ds,idata:代表movds,1、movds,2...(都是非法指令)
4.2Loop指令
4.2.1Loop指令
- 功能:实现循环(计数型循环)
- 指令的格式:loop 标号
- CPU执行loop指令时要进行的操作
- ①(cx)=(cx)-1;
- ②判断cx中的值不为零则转至标号处执行程序如果为零则向下执行。
- 要求:
- cx中要提前存放循环次数,因为(cx)影响着loop指令的执行结果;
- 要定义一个标号
4.2.2用loop指令编程实例
- 用cx和loop指令相配合实现循环功能的三个要点:
- (1)在cx中存放循环次数;
- (2)用标号指定循环开始的位置;
- (3)在标号和loop指令的中间,写上要循环执行的程序段(循环体)。
问题:计算123x236,结果存储在ax中
方法:用加法实现乘法,将123连加236次
4.3段前缀的使用
4.3.1段前缀的使用
- Debug中,moval,[0]的功能是——将DS:0存储单元的值传给AL
- 编译(masm)并连接(link)后...
- 编译好的程序中,moval,[0]变成了将常量0传给AL
4.3.2 访问连续的内存单元——loop和[bx]联手
- 问题:计算ffff:0~ffff:b字节单元中的数据的和,结果存储在dx中
- 分析:
- (1)运算后的结果是否会超出dx所能存储的范围?ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0~255之间,12个这样的数据相加,结果不会大于65535,可以在dx中存放下。
- (2)是否可以将ffff:0~ffff:b中的数据直接累加到dx中?adddx,ds:[addr];(dx)=(dx)+?期望:取出内存中的8位数据进行相加实际:取出的是内存中的16位数据
- (3)是否可以将ffff:0~ffff:b中的数据直接累加到dl中?adddl,ds:[addr];(dl)=(dl)+?期望:取出内存中的8位数据相加实际:取出的是内存中的8位数据,但很有可能造成进位丢失。
- 对策:取出8位数据,加到16位的寄存器
- mov al,ds:[addr]
- mov ah,0
- add dx,ax
5.包含多个段的程序
5.1在代码段中使用数据
5.1.1应用案例
5.1.2这个程序有问题
5.1.3改进
5.2在代码段中使用栈
5.3 将数据、代码、栈放入不同段
6.更灵活的定位内存地址的方法
6.1处理字符问题
6.2[bx + idata]方式寻址
6.3SI和DI寄存器
6.4 [bx+si]和[bx+di]方式寻址
6.5[bx+si+idata]和[bx+di+idata]
6.6不同的寻址方式的灵活应用
6.7用于内存寻址的寄存器
7.数据处理的两个基本问题
7.1在哪里?有多长?
7.2寻址方式的综合应用
7.3用div指令实现除法
7.4用dup设置内存空间