汇编发展至今,有两类指令组成:真汇编指令:这些是真指令,每一个都有对应的机器码;伪指令:由汇编编译器翻译成多条真指令,并没有真实对应的机器指令;
实验环境配置:汇编语言基础从零开始详解【第零话】汇编实验环境配置
1. 寄存器
CPU是核心,使用汇编就相当于再软件层面控制CPU,如果想让CPU工作你就必须给他提供指令和数据,指令和数据都放在存储器(内存)里面。在我们看来,指令和数据有着区别,但在机器看来是没有区别的,我们需要利用CPU暂存的寄存器区分开指令和数据。寄存器的作用就相当中转站。以8086PC为例子,有14个寄存器:
- 通用寄存器:ax,bx,cx,dx
- 段寄存器:cs,ss,ds,es
- 地址寄存器:ip,sp,bp
- 状态字寄存器:psw
- 索引寄存器:si,di
1.1 通用寄存器
通用寄存器一般是16bit,也就是那些以x结尾的寄存器,我们是可以把一个16b的寄存器拆为两个8b的寄存器使用的,我们可以把一个x寄存器拆为h和l
例如:ax=ah+al
在寄存器里面的数据类型按数据的尺寸进行分类,分为byte(字节)和word(字)
一个word一般是两个byte
指令:
mov 寄存器,寄存器/数据
add 寄存器,寄存器/数据
sub 寄存器,寄存器/数据
【问题1】寄存器的溢出问题
因为一个通用寄存器只有16b,当运算结果长于16b的时候就会溢出。
4b=1个十六进制位=1个十六进制0
执行以下指令:
mov ax,8226h
mov bx,8226h
add ax,bx
我们在VS2019的监视窗口里面可以跟踪到ax最后的数据是044c,但实际上8226+8226=1044c
,但因为ax是16b,只能存4个十六进制位。
【问题2】拆分寄存器使用的时候运算也是拆开运算,进位也会可能溢出。
执行以下指令:
mov ax,00aah
mov bx,00a6h
add al,bl
监视ax的变化,会发现最后只有0050。虽然aa+a6=150,但因为是拆分之后运算的,所以进的位不会存到高位的,所以发生溢出。
【问题3】实现自身数值乘2
add self,self
1.2 段寄存器和地址寄存器
在学习段寄存器和地址寄存器之前,我们必须先学习8086CPU是如何读写内存的。如下图:
小朋友你是否有这样的问号:16+16为毛=20?
实际上,20位的物理地址是由存储硬件本身条件决定的,但是由于CPU手上的位数不够,就只能用两个组合地址来表示一个物理地址了,而地址加法器的公式:
用十进制来看
物理地址=段地址x16+偏移地址
这个16就相当于16进制的数后面多加一个0。
举例:
已知段地址1230h,偏移地址0236h
12300+0236=12536
当CPU想要访问内存单元的时候,他需要知道段地址和偏移地址,而我们存放段地址的
用的是段寄存器,存放偏移地址的地址寄存器。
1.2.1 代码指令型地址寄存器:CS和IP
假如我们从内存里面拿指令出来:
最常用的搭配就是CS和IP,(代码型段寄存器和指令指针寄存器)。
如何修改段寄存器和指令指针寄存器的内容?
对于通用寄存器,我们修改寄存器的内容用的是mov命令,但是mov缺不能用于CS和IP寄存器,我们使用专门的地址修改命令:jmp。一般来说,一个物理地址的表示:(段地址:偏移地址)。
所以,跳转到一个新的物理地址的指令:
jmp 段地址:偏移地址(同时修改CS和IP)
jmp 偏移地址值(仅修改IP)
jmp 某一寄存器 (取该寄存器的值作为新的地址)好似:mov IP,ax
jmp 2ae3:3
jmp ax
1.2.2 数据型地址寄存器:DS
对于存放指令的内存部位我们使用 CS:IP的形式访问,如果是普通的数据,我们就会利用(数据段地址寄存器)DS:[address]的形式访问。