【Chapter4】汇编语言及其程序设计,《微机系统》第一版,赵宏伟
一、汇编语言概述
**指令:**指使计算机完成某种操作的命令。
**程序:**完成某种功能的指令序列。
**软件:**各种程序总称。
**机器语言:**计算机能直接识别的语言。用机器语言写出的程序称为机器代码。
**汇编语言:**用字符记号代替机器指令。用汇编语言编写的程序叫汇编语言源程序。
**汇编程序:**一种翻译程序,把助记符翻译成机器语言
在计算机上运行汇编语言程序的步骤:
二、汇编语言语句格式
汇编语句格式有4个字段:
[名字] 操作符 操作数; [注释]
[名字]:
-
一种标识符
-
**组成:**AZ,az,0~9;专用符号 ? . @ _ $
-
限制:
- 第一个字符不能是数字
- “.” 必须是第一个字符
- 前31个字符有效
- 不能为关键字
-
**类型:**标号-指令符号地址
变量-数据符号地址
操作符:
- **组成:**CPU指令、伪指令、宏指令
[注释]:
- 说明程序、指令的功能,增加程序的可读性
三、指令格式
一条指令由五部分组成:前缀、操作码、{寻址方式、偏移量、立即数}(操作数)
3.1 前缀
**前缀:**是对指令的某种限定或说明。可分为下面四种:
- **指令前缀:**说明指令的相关特性。如LOCK、REP、REPE/REPZ、REPNE/REPNZ
- 段超越前缀:用超越段取代默认段。三种情况禁止段超越:串操作(ES)、堆栈指令(SS)、代码段(CS)
- **操作数大小前缀:**改变默认的数据长度。16→32,32→16。
- **地址大小前缀:**改变默认的地址长度。
- 在实地址、虚拟8086方式下,隐含寻址16位。
- 在保护方式下,隐含寻址由段描述符中的D位确定,D = 0默认是16位,D = 1默认是32位
- 指令前缀和段超越前缀用于改变显式特性,2选1,由编程人员编写
- 操作数大小前缀和地址大小前缀用于改变隐式特性,可共存,由汇编程序自动加入。
3.2 操作码
**操作码:**规定了微处理器执行的操作,如加、减、传送等。
Pentium微处理器指令的操作码长为1或2个字节。第一个字节的前6位是操作码,其余两位中的D位用来指示数据流的方向、W位用来指示数据的长度是字节还是字或双字。
- D=1,R/M -> REG
- D=0,REG-> R/M
- W = 1,字,或双字
- W = 0,字节
3.3 寻址方式
**寻址方式:**用来指出CPU获取操作数的方式,如寄存器寻址、直接寻址、寄存器间接寻址等。
(1)MOD域
MOD域:规定所选指令的寻址方式,选择寻址类型及所选的类型是否有位移量。
MOD域 共2位4种组合含义如下:
(2)REG域 & MOD = 11下 的R/M域
REG域或者MOD=11时表示R/M选中R,三位代码组合的8种情况的含义如下:
其实就是4个数据寄存器和4个指针和变址寄存器
在W 指示 数据长度为 字节、字、双字时分别表示寄存器使用8、16、32位
(3)R/M域
MOD != 11时,表示用于存储器寻址
其含义如下:
- MOD = 00、01、11分别表示:无偏移量、8位偏移量、16位偏移量
- 表格中每一项上下分别表示:段内偏移 和 寻址方式的隐含段
3.4 位/偏移量及立即数
**位/偏移量:**允许指令中直接给出寻址方式所需的位/偏移量。
**偏移量: ** 直接寻址的地址,无符号数,如 MOV AX,[2000H]
位移量: 相对寻址中的地址数据,有符号数,如 MOV AX,[SI+6]
立即数:允许指令中直接给出操作数。
四、寻址方式
一条汇编指令要解决2个问题:
- 做什么
- 对象,或对象来源,即寻址方式
**寻址方式掌握要点:**侧重理解操作数的寻址过程,如何找到一个操作数。
有2类寻址:
- 对操作数寻址
- 对转移地址、调用地址寻址
4.1 数据的寻址方式
Pentium系统中使用字节(8位)、字(16位)、双字(32位)和4倍字(64位)。采用低端存储方式。
与数据有关的寻址方式有11种:
- 立即数寻址
- 寄存器寻址
- 存储器寻址
- 直接寻址
- 寄存器间接寻址
- 寄存器相对寻址
- 基址变址寻址
- 相对基址变址寻址
- 比例变址寻址
- 相对比例变址寻址
- 基址比例变址寻址
- 相对基址比例变址寻址
4.1.1 立即寻址
**立即寻址:**操作数是指令的一部分。完整地取出该条指令之后也就获得了操作数。这种操作数称为立即数。
主要用于对寄存器赋值,速度快。
汇编语言规定: 立即数必须以数字开头,以字母开头的十六进制数前必须以数字0做前缀;数制用后缀表示,(B表示二进制数,H表示十六进制数,(D或者缺省表示十进制数,Q表示八进制数,程序员可以用自己习惯的计数制书写立即数。汇编程序在汇编时,对于不同进制的立即数一律汇编成等值的二进制数,有符号数以补码表示。
此外,立即数还可以是用+、-、x、/ 表示的算术表达式。汇编程序按照先乘除后加减的规则自动计算,也可以用圆括号改变运算顺序。
立即寻址的例子
MOV AL, 01010101B MOV BX, 1234H MOV EAX, 12315678H
4.1.2 寄存器寻址
**寄存器寻址:**操作数在CPU的某个寄存器中,指令指定寄存器号。
寄存器寻址是最通用的数据寻址方式。对于8位操作数,寄存器有AH、AL、BH、BL、CH、CL、DH和DL;对于16位操作数,寄存器可以是AX、BX、CX、DX、SP、BP、SI和DI;在80386以上的微处理器中,还可以是32位操作数,寄存器有EAX、EBX、ECX、EDX、ESP、EBP、EDI和ESI。
有些用寄存器寻址的MOV、PUSH和POP指令可寻址16位的段寄存器(CS、ES、DS、SS、FS和GS)。
寄存器寻址的例子:
MOV DS, AX MOV EAX, ECX MOV DL, BH
4.1.3 存储器寻址
**存储器寻址:**操作数在存储器中
存储器地址:
- 物理地址
- 逻辑地址: 段基址:偏移量
CPU要访问存储器操作数,必须先计算存储器的物理地址。
在实地址和保护方式下,段基址的获取方式不同,但偏移量的获取思想基本一致。
在存储器寻址方式中,要解决的问题是如何取得操作数的偏移地址。
有效地址EA:Effective Address,在8086~Pentium微处理器里,把操作数的偏移地址称为有效地址EA。
有效地址的计算
E A = 基址 + ( 变址 × 比例因子 ) + 位移量 EA = 基址 + (变址\times 比例因子) + 位移量 EA=基址+(变址×比例因子)+位移量
基址:基址寄存器中的内容。基址寄存器通常用于编译程序指向局部变数据段中数组或字符串的首地址。
变址:变址寄存器中的内容。变址寄存器用于访问数组或字符串的元素
**比例因子:**32位机的寻址方式。寻址中,用变址寄存器的内容乘以比例因子得到变址值。该方式对访问数组特别有用。(就类比c语言,字符指针+1是移动1个字节,int指针是4个字节,这里的比例因子就起到类似作用,为1就是一次8位,2就是一次16位)
**位移量:**指令中的一个数,但不是立即数,而是一个地址。
8086/286是16位寻址,80386及以后机型是32位寻址,也可用16位寻址。
9种存储器寻址方式
如下表:(星号代表二者选一个)
我们发现相对寻址都是带位移量的,比例寻址都是带比例因子的
存储器寻址举例
如下表:
- 我们汇编指令中,用“[]”括起来的操作数代表EA
- 由于我们处理器是分页存储,我们还需要知道段基址,前面提过了指令格式中的寻址方式是有隐含段的
寻址方式的段约定和段超越
我们描述段超越的方式就是:在间址前面加上段名加“:”
下面是一些示例:
MOV AL, DS: [BP] ; 用BP间址访问数据段 MOV AL, ES: [BP] ; 用BP间址访问ES附加段 MOV AL, FS: [EBP] ; 用EBP间址访问FS附加段 MOV AL, CS: [BX] ; 用BX间址访问代码段 MOV AL, ES: [SI+5] ; 用SI变址寻址,访问ES附加段 MOV AL, GS: [EAX+10] ; 用EAX基址寻址,访问GS附加段
为提高程序的可读性和效率,要尽量少使用段超越
各存储器操作类型的隐含段、可使用超越段、段内偏移量描述如下:
4.2 转移地址的寻址方式
**转移地址寻址:**用于确定转移指令和CALL指令的转向地址。
转移指令使程序不再顺序执行,而是按指令中给出的操作数转移到相应的目的地址。
转移地址:转移指令中的操作数是转移的目的地址,称为转移地址。
转移指令调用指令分为:
- 段内(IP/EIP)转移
- 直接(相对)转移
- 间接
- 段间(CS:IP/EIP)转移
- 直接
- 间接
4.2.1 段内相对寻址
(位移量+IP = EA)→IP/EIP,即把有效地址EA送给IP/EIP
位移量是相对值,所以称为段内相对寻址。
因为是相对值,所以便于程序再定位。
用于条件转移、无条件转移,条件转移只能用此方式。
**短跳转:**JMP SHORT AA9 ;位移量 8位,-128 ~ +127
**近跳转:**JMP NEAR PTR AA8 ;位移量 16位 ± 32K,32位 ± 2G
4.2.2 段内间接寻址
- 寄存器(存储器)内容 = EA→IP/EIP
- 这种寻址方式不能用于条件转移指令。
- JMP BX
- JMP WORD PTR[BX + AA7]
- JMP ECX
4.2.3 段间直接寻址
指令给出一个逻辑地址,段地址送给CS,段内偏移送给IP或EIP
- 目标段地址:偏移量 = CS:IP/EIP
- JMP FAR PTR AA6
4.2.4 段间间接寻址
- 连续的存储器单元内容 = CS:IP/EIP
- JMP DWORD PTR [SI];[SI]指向的字送入IP,[SI + 2]指向的字送入CS。
4.3 堆栈地址寻址
**堆栈:**以“先进后出”方式工作的一个特定的存储区。
一端固定,称为栈底;另一端浮动,称为栈顶,只有一个出入口。
**堆栈作用:**保存传递参数、现场参数、寄存器内容、返回地址。
80x86规定:
- 堆栈向小地址方向增长。
- 必须使用堆栈段SS。
- PUSH指令压入数据时,先修改指针,再按照指针指示的单元存入数据。
- POP指令弹出数据时,先按照指针指示的单元取出数据,再修改指针。
- 压入和弹出的数据类型(数据长度)不同,堆指针修改的数值也不同。
16位堆栈地址操作,还是32位堆栈地址操作,由堆栈段SS寄存器内的数提段描述符的属性说明,确定用SP还是ESD,是一种隐含属性。
五、指令系统
**指令系统:**指令的集合。软硬件交界面。
**指令系统掌握要点:**侧重掌握指令的功能和使用方法,为后续程序设计打基础。
- 8086-110条指令
- 80286-143条指令
- 80386-154条指令
- 80486-160条指令
- Pentium - 165条指令
Pentium指令系统按功能分为10类:
数据传送指令、算术运算指令、BCD码调整指令、逻辑运算指令、位处理指令、控制转移指令、条件设置指令、串操作指令、处理器控制
指令、保护模式系统控制指令。
5.1 数据传送指令
**数据传送指令功能:**源 -> 目
指令执行后,源操作数不变,不影响状态标志。
5.1.1 MOV 传送(move)
格式:MOV DST, SRC ; (DST)
- 段内(IP/EIP)转移
- 说明程序、指令的功能,增加程序的可读性