汇编指令和机器指令的差别在于指令的表示方式上。汇编指令是机器指令便于记忆的书写格式。
汇编指令:机器码的助记符,有对应的机器码
伪指令:没有对应的机器码,由编译器执行,计算机并不执行
其他符号:如+、-、*、/等,由编译器识别32万
汇编指令决定了汇编语言的特性
指令和数据在存储器中存放
存储单元的地址(地址信息)
器件的选择,读或写的命令(控制信息)
读或写的数据(数据信息)
CPU用地址总线来指定存储器单元
CPU与内存或其他器件的数据传送是通过数据总线来进行的
数据总线的宽度决定了CPU和外界的数据传送速度
8086CPU的数据总线宽度为16
CPU对外部器件的控制是通过控制总线来进行的
和CPU的总线相连
CPU对它们进行读或写的时候都通过控制控制线发出内存读写命令
内存地址空间的大小受CPU地址总线宽度的限制
8086CPU的地址总线宽度为20,可以传送2^20个不同的地址信息
8086CPU的内存地址空间大小为1MB
在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
[1111 1111 , 0111 1111]
即
[-127 , 127]
原码是人脑最容易理解和计算的表示方式.
反码的表示方法是:
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.
补码的表示方法是:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.
-R 查看修改CPU寄存器内容
-D 查看内存中内容
-E 改写内存中内容
-U 将内存中的机器语言翻译成汇编指令
-T 执行一条汇编指令
-A 以汇编指令的格式在内存中写入一条机器指令
8086CPU有14个寄存器,分别为:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW
AX,BX,CX,DX 称作为数据寄存器:
AX (Accumulator):累加寄存器,也称之为累加器;
AX可分为AH和AL
低8位构成了AL寄存器,高8位构成AH寄存器
BX (Base):基地址寄存器;
CX (Count):计数器寄存器;
DX (Data):数据寄存器;
SP 和 BP 又称作为指针寄存器:
SP (Stack Pointer):堆栈指针寄存器;
BP (Base Pointer):基指针寄存器;
SI 和 DI 又称作为变址寄存器:
SI (Source Index):源变址寄存器;
DI (Destination Index):目的变址寄存器;
IP (Instruction Pointer):指令指针寄存器;
FLAG:标志寄存器;
CS (Code Segment):代码段寄存器;
DS (Data Segment):数据段寄存器;
SS (Stack Segment):堆栈段寄存器;
ES (Extra Segment):附加段寄存器;
字节:记为byte,一个字节由8个bit组成,可以存在8位寄存器中
字:记为word,一个字由两个字节组成,这两个字节分别被称为这个字的高位字节和低位字节
8086CPU有20位地址总线,可以传送20位地址,但它只能送出16位的地址
采用两个16位地址合成的方法来形成一个20位的物理地址
当8086CPU要读写内存时
地址加法器采用物理地址=段地址*16+偏移地址
基础地址+偏移地址=物理地址
段地址*16必然是16的倍数,所以一个段的起始地址也不一定是16的倍数,16位地址的寻址能力为64KB
CPU可以用不同的段地址和偏移地址形成同一个物理地址
偏移地址16位,变化范围为0~FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元
8086CPU有4个段寄存器:CS,DS,SS,ES
CS为代码段寄存器
IP为指令指针寄存器
读取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令
1.从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
2.IP=IP+所读取指令的长度,从而指向下一条指令
3.执行指令。转到步骤1,重复这个过程
CPU将CS:IP指向的的内容看作指令,因为在任何时候,CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。
8086CPU为CS、IP提供了另外的指令来改变它们的值。能够改变CS、IP的内容的指令被统称为转移指令
jmp指令
jmp段地址:偏移地址
功能:用指令中给出的段地址修改CS,偏移地址修改IP
若想仅修改IP的内容,可用形如“jmp 某一合法寄存器”的指令完成
功能:用寄存器中的值修改IP
CPU中用16位寄存器来存储一个字。高八位存放高位字节,第八位存放低位字节。
即存放一个字型数据(16位)的内存单元,有两个地址连续的内存单元组成。高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节
任何两个地址连续的内存单元,N号单元和N+1号单元,可以把它们看成两个内存单元,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元
DS 寄存器通常用来存放要来访问的数据的段地址
“[…]”表示一个内存单元
“[0]”中的0表示内存单元的偏移地址
8086CPU自动取ds中的数据为内存单元的段地址
8086CPU不支持将数据直接送入段寄存器的操作,只好用一个寄存器来进行中转,即先将1000H送入一个一般的寄存器,如bx,再将bx 中的内容送入ds
mov ax,[0]l;1000:0处的字型数据送入ax
mov [0],cx;cx中的16位数据送到1000:0处
栈是一种具有特殊的访问方式的存储空间。它的特殊性就在于,最后进入这个空间的数据,最先出去
PUSH入栈
执行步骤:1.sp=sp-2;2.向SS;SP指向的字单元中送入数据
POP出栈
执行步骤:1.从SS:SP指向的字单元中读取数据;2.sp=sp+2
出栈和入栈操作都是以字为单位进行的
段寄存器SS和寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。任意时刻,SS:SP指向栈顶元素,CPU从SS和SP中得到栈顶的地址
入栈时,栈顶从高地址向低地址方向增长
栈空的时候 SP=0010H
8086CPU不保证我们对栈的操作不会超界。它只会考虑当前的情况:当前的栈顶在何处、当前要执行的指令是哪一条
栈空时:SP=0000H
1.编写汇编源程序
2.对源程序进行编译连接
3.执行可执行执行文件中的程序
汇编指令是有对应的机器码的指令,可以被编译为机器语言,最终为CPU所执行。伪指令没有对应的机器指令,最终不被CPU所执行。伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作。
segment和ends的功能是定义一个段
段名 segment
.
.
.
段名 ends
end是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了伪指令end,就结束对源程序的编译
assume的含义为假设。它假设某一段寄存器和程序中的某一个用segment…ends定义的段相关联
assume cs:codesg
将段codesg和CPU中的段寄存器CS联系起来
mov ax,4c00H
int 21H
masm进行编译
link进行连接
1.内存单元的地址
2.内存单元的长度
[bx]同样也表示一个内存单元,它的偏移地址在bx中
mov ax,[bx]将一个内存单元的内容送入ax,这个内存单元的长度为2字节,存放一个字,偏移地址在bx中,段地址在ds中
mov al,[bx]将一个内存单元的内容送入al,这个内存单元的长度为1字节,存放一个字,偏移地址在bx中,段地址在ds中
Inc bx的含义是bx 中的内容加1
格式为:loop 标号
CPU 执行loop指令的时候,要进行两步操作
1.(cx)=(cx)-1
2.判断cx中的值,不为零择转至标号处执行程序,如果为零则向下执行
我们用loop指令来实现循环功能,cx中存放循环次数
用“()”来表示一个寄存器或一个内存单元中的内容
在汇编源程序中,数据不能以字母开头,所以要在前面加0
在汇编源程序中,如果用指令访问一个内存单元,则在指令中必须用“[…]”来表示内存单元,如果在“[]”里用一个常量idata直接给出内存单元的偏移地址,就要在“[]”的前面显式地给出段地址所在的段寄存器
mov al,ds:[0]
如果没有在“[]”前面显式地给出段地址所在的段寄存器
mov al,[0]
那么,编译器masm将把指令中的“[idata]”解释为“idata”
1.(dx)=(dx)+内存中的8位数据
2.(dl)=(dl)+内存中的8位数据
出现在访问内存单元的指令中,用于显式地说明内存单元的段地址的“ds:”“cs:”“ss:”“es:”
0:200~0:2ff
含义是定义字形数据
dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
这里使用dw定义了8个字型数据
它们在代码段中,程序在运行的时候CS中存放代码段的段地址,所以可以从CS中得到它们的段地址。它们的的偏移地址,由于在代码段的最开始,所以开始为0,所以依次为CS:0、CS:2、CS:4、CS:6、CS:8、CS:A、CS:C、CS:E
1.由其他的程序将可执行文件中的程序加载入内存
2.设置CS:IP指向程序的第一条要执行的指令,从而使程序得以运行
3.程序运行结束后,返回到加载者
assume cs:code
code segment
.
.
数据
.
.
start:
.
.
代码
.
.
code ends
end start+
and指令:逻辑与指令,按位进行与运算
只有1和1为1
mov al,01100011B
and al,00111011B
执行后:al=00100011B
or指令:逻辑或指令,按位进行或运算
只有0和0为0
mov al,01100011B
and al,00111011B
执行后:al=01111011B
db:定义二进制数
大写字母+20H=小学字母
s:mov al,[bx]
and al ,11011111B
将al中的ASCII码的第5位置为0,变为大写字母
小写字母-20H=大写字母
s:mov al,[bx]
or al ,00100000B
将al中的ASCII码的第5位置为1,变为小写字母
只有这四个寄存器可以用在“[…]”中来进行内存单元的寻址
在[…]中这4个寄存器可以单独出现或者组合出现
在[…]中使用寄存器bp,而指令中没有显性地给出段地址,段地址默认在ss中
指令执行前一刻 ,它将要处理的数据所在的位置
内存单元
CPU内部,寄存器
CPU内部,指令缓存器
直接包含在机器指令中的数据(执行前在CPU的指令缓存器中)
指令要处理的数据在寄存器中
指令要处理的数据在内存中
div是除法指令
除数:有8位和16位
被除数:放在AX或DX和AX中
结果:如果除数为8位,则AL中存放除法操作的商,AH存储除法操作的余数;如果除数为16位,则AX中存放除法操作的商,DX存储除法操作的余数
当除数是8位的时候,被除数为16位,放在AX中存放,AL中存放除法操作的商,AH存储除法操作的余数
当除数是16位的时候,被除数为32位,放在DX和AX中存放,AX中存放除法操作的商,DX存储除法操作的余数
dd是用来定义字节型数据的
db是用来定义字型数据的
dw是用来定义dword型数据的
db 重复的次数 dup(重复的字节型数据)
dw 重复的次数 dup(重复的字型数据)
dd 重复的次数 dup(重复的双字型数据)
可以修改IP,或同时修改CS和IP的指令统称为转移指令
段内转移:只修改IP
段间转移:同时修改CS和IP
段内转移又分为短转移和近转移
短转移IP的修改范围为-128~127
近转移IP的修改范围为-32768~32767
功能是取得标号的偏移地址
jmp为无条件转移指令
jmp要给出两种信息:
1.转移的目的地址
2.转移的距离(段间转移、段内短转移、段内近转移)
jmp short 标号
段内短转移
CPU在执行jmp指令的时候并不需要转移的目的地址
jmp far ptr 标号
段间转移,远转移
jmp word ptr 内存单元地址(段内转移)
jmp dword ptr 内存单元地址(段间转移)
为有条件转移指令
循环指令
短转移
用栈中的数据,修改IP的内容,从而实现近转移
用栈中的数据,修改CS和IP的内容,从而实现远转移
两步操作
1.将当前的IP或CS和IP压入栈内
2.转移
call标号(将当前的IP压栈后,转到标号处执行指令)
call far ptr 标号
实现段间转移
call 16位reg
call word ptr 内存单元地址
call dword ptr 内存单元地址
可以利用call和ret来实现子程序的机制
框架
assume cs:code
code segment
main:
.
.
call sub1 ;调用子程序sub1
.
.
mov ax ,4c00h
int 21h
sub1: ;子程序sub1开始
.
.
call sub2 ;调用子程序sub2
.
.
ret ;子程序返回
sub2: ;子程序sub2开始
.
.
ret ;子程序返回
code ends
end main
mull是乘法指令
两个相乘的数要么都是8位,要么都是16位。
当8位的时候,一个默认放在AL中,另一个放在8位reg或内存字节单元中,结果默认放AX中
当16位的时候,一个默认放在AX中,另一个放在16位reg或内存字节单元中,结果高位默认放DX中,低位在AX中放