(꒪⌓꒪)
1字节 = 8位
字节是最小的寻址单位!
1字 = 2字节 = 16位
WORD 字 16位
DWORD 双字 32位
Intel x86微处理器的寄存器结构
通用寄存器:主要用于算术运算
和数据传送
AX通常称为累加器
BX基地址寄存器,作为存储器指针来用
CX计数寄存器
DX数据寄存器
BP常用来寻址堆栈而不是数据段
标志位:CF(进位)、ZF(零)、SF(符号)、OF(溢出)、AF(辅助进位)、PF(奇偶)
16位系统寻址方式
1.立即寻址
1 | MOV AX, im ; im:立即数 MOV AX, 43H |
2.直接寻址
1 | MOV AX, [ARRAY] ;加上方括号 |
3.寄存器寻址
1 | MOV DS, AX |
4.寄存器间接寻址
操作数放在存储器中,操作数的16位段内偏移地址存放在SI、DI、BP、BX这四个寄存器之一中
若以SI、DI、BX间接寻址,则操作数存放在现行数据段中,此时,数据段寄存器
DS
的内容加上SI、DI、BX
中的16位段内偏移地址,即得操作数地址若以BP间接寻址,操作数存放在堆栈段区域中,此时,堆栈段寄存器
SS
的内容加上BP
中的16位段内偏移地址,即得操作数地址
1 | MOV AX, [SI] ;设DS=2000H,SI=1000H 则操作数地址=21000H |
DS、SS需左移四位
5.寄存器相对寻址
操作数存放在存储器中,操作数地址是由段寄存器内容(SI、DI、BX对应DS,BP对应SS)
加上SI、DI、BX、BP
其中之一的内容,再加上由指令中所指出的8位或16位带符号相对地址偏移量
而得到的
1 | MOV AX, DISP[SI] ;操作数地址为DISP+SI+DS(DS需左移4位) |
6.基址变址寻址
在8086/8088中,通常把BX和BP作为基址寄存器,而把SI、DI作为变址寄存器,将这两种寄存器联合起来进行的寻址就称为基址+变址寻址。
此时,操作数的地址为段寄存器的内容(DS或SS BX对应DS BP对应SS)
加上基址寄存器的内容(BX或BP)
,再加上变址寄存器内容(SI或DI)
1 | MOV AX, [BX][SI] ;操作数地址为BX+SI+DS(DS<<4) |
7.基址变址相对寻址
1 | MOV AX, DISP[BX][SI] ;BX+SI+DISP+DS(DS<<4) |
8.PC相对寻址
1 | LOOP L1 ; PC相对寻址 |
9.隐含寻址
在有些指令中,不仅包含有操作码的信息,而且还隐含了操作数地址的信息。
汇编语言
大小写不敏感 标识符不能以数字开头
R 寄存器
M 内存
AL 寄存器低八位
h 十六进制 b 二进制 q/o八进制 r 编码实数 d 十进制
注意:0A3h
一、定义数据
BYTE 8位无符号整数 SBYTE 8位有符号整数
WORD 16位无符号整数 SWORD 16位有符号整数
DWORD 32位无符号整数 SDWORD 32位有符号整数
FWORD 48位整数
QWORD 64位整数
db 字节 8位
dw 字 = 2字节 16位
dd 双字 = 4字节
小端存储
符号常量不占用任何实际的存储空间
1 | ; 计算数组和字符串的大小 |
二、和数据相关的操作符和伪指令
预定义符号$
表示当前这条指令在代码段中的偏移量
表示字符串结束 0dh,0ah换行
OFFSET
操作符
返回数据标号的偏移地址(标号据数据段开始的距离,以字节为单位)
1 | .data |
PTR
操作符
用来重载操作数的默认尺寸
必须和以下标准数据类型联合使用:BYTE,SBYTE,WORD,SWORD,DWORD,SDWORD,FWORD,QWORD,TBYTE
1 | .data |
TYPE
操作符
返回按字节计算的变量的单个元素的大小
DUP
伪指令
duplicate 重复初始化数据
1 | str1 db 10 dup('!@#') ;十个'!@#' |
LENGTHOF
操作符
计算数组中元素的个数
1 | .data |
SIZEOF
操作符
SIZEOF返回值 = LENGTHOF返回值 × TYPR返回值
INVOKE
伪指令
自动在堆栈上压入参数并调用程序
1 | INVOKE Swap,ADDR Array,ADDR [Array+4] |
PROTO
伪指令
为一个已存在的过程创建原型。
原型声明了过程的名字和参数列表,允许一个过程在被定义之前就可以在其他地方被调用。
三、数据传送指令
操作数类型
立即操作数(immediate)
imm:8、16或32位立即数
imm8:8位立即数(字节)
imm16:16位立即数(字)
imm32: 32位立即数(双字)
寄存器操作数(register)
reg:任意的通用寄存器
sreg:16位段寄存器CS、DS、SS、ES、FS、GS
r8:AH、AL、BH、BL、CH、CL、DH、DL
16:AX、BX、CX、DX、SI、DI、SP、BP
r32:EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP
内存操作数(memory)
- mem:8、16或32位内存操作数
直接内存操作数
1 | .data |
MOV
指令
- 两个操作数的尺寸必须一致。
- 两个操作数不能同时为内存操作数。
- 目的操作数不能是CS,EIP和IP。
- 立即数不能直接送至段寄存器。
XCHG
指令
交换两个操作数内容
1 | ;格式 不能直接交换两个内存操作数 |
四、布尔和比较指令
1.AND
指令
按位与 两操作数大小必须相同 用于特定位置清0
将结果放在目标操作数中
1 | ; 允许操作数形式: |
- 总是清除OF (溢出)和 CF(进位)
- 根据结果修改SF(符号)、ZF(零)、PF(奇偶)
2.OR
指令
按位或 用于特定位置置1
1 | ; 将0-9间整数转换为对应ASCII码数字 |
3.XOR
指令
按位异或
4.NOT
指令
数据位按位取反,结果为反码
不影响任何标志位
1 | ;格式 |
5.TEST
指令
格式同AND指令
两操作数按位相与,根据结果设置标志位,但不修改目的操作数
用于测试操作数某一位是0还是1
影响标志位:清除OF、CF 修改SF、ZF、PF
6.CMP
指令
1 | ;格式同AND指令 |
执行目的操作数-源操作数,但不回送结果,只影响标志位
根据相减结果修改OF、SF、ZF、CF、AF、PF
7.设置和清除单个CPU标志
五、算术运算
INC
和DNC
指令
increment 即 +1
decrement 即 -1
1 | ;格式 |
INC和DEC指令不影响进位标志
ADD
指令
格式同MOV指令
两个操作数不能同时为内存操作数
1 | .data |
SUB
指令
格式同MOV指令
1 | .data |
影响标志位:CF(进位)、ZF(零)、SF(符号)、OF(溢出)、AF(辅助进位)、PF(奇偶)
NEG
指令
negate 求补 即求相反数
将操作数按位取反、末位加1
1 | ;格式 |
影响标志位同上
mul
乘法
乘数与被乘数大小必须保持一致
被乘数AL(8位) -> 积AX(16位)
被乘数AX(16位) -> 积DX:AX
1 | ;8位无符号数乘法 |
div
除法
1 | ;无符号数 8003h/100h |
8位无符号除法 被除数在AX(高8位清零) 除数8位 商在AL 余数在AH
16位无符号除法 被除数在DX:AX(DX清零) 除数16位 商在AX 余数在DX
六、控制转移 JMP
和LOOP
指令
控制转移分为:
- 无条件转移:JMP
- 条件转移:LOOP
LOOP
指令
ECX
用作循环计数器,实地址模式下CX
用作循环计数器
1 | mov ax,0 |
七、条件跳转指令
基于特定CPU
标志值的跳转指令
1 | JZ/JE ;为0则跳转 ZF=1 |
基于CMP
指令的跳转
1 | JE ;相等则跳转 |
无符号整数:
1 | JA ;大于则跳转 同JNBE不小于或等于则跳转 |
有符号整数:
1 | JG ;大于则跳转 同JNLE |
LOOPZ
与LOOPE
LOOPZ与LOOPE等价
执行逻辑:
ECX=ECX-1
if ECX>0 and ZF=1, jump to destination
LOOPNZ
与LOOPNE
等价
执行逻辑:
ECX=ECX-1
if ECX>0 and ZF=0, jump to destination
八、移位指令
1 | SHL/SHR ;逻辑左/右移 |
影响OF、CF
逻辑右移:最高位补0,最低位移入CF
算术右移:最高位保持,最低位移入CF
逻辑左移/算术左移:最高位移入CF,最低位补0
循环左移:最高位移入CF和最低位
循环右移:最低位移入CF和最高位
九、过程
用PROC
和ENDP
伪指令来声明
对程序进行逻辑划分为过程
1 | ; 启动过程 |
局部标号和全局标号
十、字符串和数组
基本指令
指令 | 描述 |
---|---|
MOVSB, MOVSW, MOVSD | 移动字符串:拷贝DS:(E)SI寻址的内存操作数至ES:(E)DI |
CMPSB, CMPSW, CMPSD | 比较字符串:比较内存中由DS:(E)SI寻址和ES:(E)DI寻址的字符串 |
SCASB, SCASW, SCASD | 扫描字符串:扫描ES:(E)DI指向的内存字符串查找与累加器匹配的值 |
STOSB, STOSW, STOSD | 存储字符串:将累加器内容存储到由ES:(E)DI寻址的内存中 |
LODSB, LODSW, LODSD | 将字符串数据装入累加器:将由DS:(E)SI寻址的内存单元装入累加其中 |
- SI是DS段中的偏移
- DI是ES段中的偏移
使用重复前缀
字符串操作指令每次只能处理一个内存值。
通过增加一个重复前缀,字符串指令就会使用ECX作为计数器进行重复,实现用一条指令处理整个数组。
前缀 | 描述 |
---|---|
REP | ECX>0时重复 |
REPZ, REPE | ZF=1&&ECX>0 |
REPNZ, REPNE | ZF=0&&ECX>0 |
1 | main PROC |
方向标志:简单字符串指令使用方向标志来决定ESI和EDI是自动增加还是自动减少:
方向标志位DF=0:ESI、EDI自动增加
DF=1:ESI、EDI自动减少
1
2CLD ;清除方向标志
STD ;设置方向标志
十一、结构
1 | ;结构的定义 |
十二、宏
命名的汇编语句块。调用时直接拷贝插入程序中。
1 | ;宏的定义 |
编程题举例
数组间接寻址
16位汇编:三个字相加
1 | .data |
P106 3.8
在DATA为首地址的主存区域中存放100个无符号8位数,试编写程序找出其中最大的数,并将其放在KVFF存储单元中。
1 | MOV BX, SEG DATA |
P107 3.14
试编写8086汇编程序,统计由主存40000H开始的16K个单元中所存放的字符“A”的个数,并将结果存放在DX中。
1 | START: MOV DX, 40000H |