本文为汇编语言考试复习整理 →_→
寄存器
通用寄存器(General Purpose Registers)均可以拆成2个8位寄存器使用,如AX寄存器可以拆成AL(低位)、AH(高位)使用。
| Types | Registers | Full Name | Function |
|---|---|---|---|
| General Purpose Registers | AX | Accumulator Register | 存储数据;乘除法;中断指令;不能用作偏移地址索引 |
| BX | Base Register | 偏移地址索引(默认段地址为DS) | |
| CX | Counter Register | 循环计数;不能用作偏移地址索引 | |
| DX | Data Register | 存储数据;乘除法;不能用作偏移地址索引 | |
| Segment Registers | CS | Code Segment | 代码段的段地址 |
| DS | Data Segment | 数据段的段地址 | |
| SS | Stack Segment | 栈段的段地址 | |
| ES | Extra Segment | 额外段的段地址 | |
| Special Purpose Registers | SP | Stack Pointer | 栈段的偏移地址;不能用作偏移地址索引 |
| BP | Base Pointer | 偏移地址索引(默认段地址为SS) | |
| IP | Instruction Pointer | 代码段的偏移地址 | |
| SI | Source Index | 串传送指令源地址;源偏移地址索引 | |
| DI | Destination Index | 串传送指令目的地址;目的偏移地址索引 | |
| Flag Register | PSW | Program Status Word | 存储相关指令的执行结果 |
更多内容可参考
https://www.geeksforgeeks.org/types-of-registers-in-8086-microprocessor/
标志寄存器
| PSW | Full Name | 1 |
|---|---|---|
| ZF | Zero Flag | 计算结果为0 |
| PF | Parity Flag | 计算结果二进制有偶数个1 |
| SF | Sign Flag | 计算结果为负 |
| CF | Carry Flag | 当作无符号数计算,结果存在进位溢出 |
| OF | Overflow Flag | 当作有符号数计算,结果存在溢出 |
| AF | Auxiliary Carry Flag | 计算过程是否存在进位 |
| DF | Directional Flag | 串传送方向从高到低 |
| IF | Interrupt Flag | 接受中断 |
| TF | Trap Flag | 单步执行 |
更多内容可参考
https://www.geeksforgeeks.org/flag-register-8086-microprocessor/
寻址
16位的寄存器,20位的地址总线。CPU 向地址总线发送物理地址前需先计算出来,计算方式如下:
物理地址(20位) = 段地址 x 10H + 偏移地址
所以,可能存在不同段地址和偏移地址指向一个物理地址的情况。
内存单元
在 DEBUG.EXE 中,内存单元按照低地址到高地址的方式显示,每两个紧邻的数表示一个字节(Byte),每行显示16个字节。
上图中,如果DS寄存器(Data Segment)为076C,则指令 mov ax,[0] 将使AX寄存器被赋值为十六进制的C88C。(C8在高地址,所以在高位;8C在低地址,所以在低位)
此外,内存单元存储地址时,段地址存储于高地址,偏移地址存储于低地址。
指令语法
1. mov ax,0f500h
解释:将十六进制的f500(最后的 h 表示十六进制;数值的第一位是字母 f 所以需要加上 0 )赋值给AX寄存器
段寄存器(CS、DS、SS、ES)不能直接赋值数据,需要通过寄存器(段寄存器和IP除外)赋值
内存单元可以通过寄存器或者数据赋值,不能使用 mov 内存单元地址,内存单元地址 赋值,下面两种均是可以的。
mov ds:[0],ax ; ax已经指明是word类型,无需加上word ptr
mov word ptr ds:[0],33h ; 需要指定word ptr或者byte ptr
2. add ax,2
解释:将十进制的2加给AX寄存器,也可以对内存单元使用,如 add word ptr es:[0],33h ;相关的指令有 sub ax,2 ,使AX寄存器减去十进制的2
3. inc ax
解释:AX寄存器加1,也可以对内存单元使用,如 inc word ptr es:[0] ;相关的指令有 dec ax ,使AX寄存器减1
4. push ax
解释:将AX寄存器(或者内存单元)的值入栈
栈顶为SS:SP,满足先入后出原则,入栈SP变小,出栈SP变大;使用时需要先声明栈段(stack segment),栈段完全由程序员控制,没有保护机制。此外, push 和 pop 时,SP只能加2或者减2。
| 指令 | 解释 |
|---|---|
push ax |
1. sub sp,22. mov ss:[sp],ax
|
pop ax |
1. mov ax,ss:[sp]2. add sp,2
|
5. loop s
解释:同一个代码段(段内短转移)往前跳转到s标记处循环
- CX减1,并判断是否为0
- 如果CX为0,则不跳转继续往下执行代码;如果CX大于0,则跳转到s标记循环
6. and al,11011111b
解释:将AL值的二进制与 11011111b 做与运算,功能上将AL转为大写字符
| and | 0 | 1 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
相关的指令有 or al,00100000b ,它是将AL值的二进制与 00100000b 做或运算,功能上将AL转为小写字符
| or | 0 | 1 |
| 0 | 0 | 1 |
| 1 | 1 | 1 |
7. db 'unIX'
解释:在内存中定义字节型(byte)数据,等效于 db 75H,6EH,49H,58H , 75H,6EH,49H,58H 为 unIX 的16进制ASCII码
相类似的还有dw(define word)、dd(define double word),均是编译器识别的伪指令
8. div bx
解释:BX为除数,被除数为AX(低位)和DX(高位)构成的数,商存放于AX中,余数存放于DX中
| 除数 | 被除数 | 商 | 余数 |
|---|---|---|---|
| 8位 | AX | AL | AH |
| 16位 | AX(低位)、DX(高位) | AX | DX |
相关的指令有 mul bx ,这里BX为乘数,被乘数为AX,积为AX(低位)和DX(高位)构成的数
| 乘数 | 被乘数 | 积 |
|---|---|---|
| 8位 | AL | AX |
| 16位 | AX | AX(低位)、DX(高位) |
; 应用举例
div reg ; 8位或者16位reg
div 内存单元地址 ; 需要加上 byte ptr / word ptr
div word ptr es:[0]
div byte ptr [bx + si + 8] ; ds:[bx + si + 8]
mul reg ; 8位或者16位reg
mul 内存单元地址 ; 需要加上 byte ptr / word ptr
mul word ptr es:[0]
mul byte ptr [bx + si + 8] ; ds:[bx + si + 8]
9. db 200 dup (0)
解释:定义200个字节的 0 , dup (duplication)同样也是编译器识别的伪指令
10. mov si,offset s
解释:操作符 offset 由编译器识别,值为标记 s 处相对代码起始位置的偏移量,通常用于串传送
11. jmp short s
解释:CS和IP由于其特殊性,不能直接通过赋值改变,jmp指令登场! jmp short s 跳转到标号s处执行代码,是段内短转移,转移范围为 -128~127 (段内转移只改变IP)
| 指令 | 解释 | 类别 |
|---|---|---|
jmp short s |
跳转到标号s处 | 段内短转移( -128~127 ) |
jmp near ptr s |
跳转到标号s处 | 段内近转移( -32768~32767 ) |
jmp ax |
将AX的值赋给IP | 段内近转移( -32768~32767 ) |
jmp far ptr s |
跳转到标号s处 | 段间远转移(改变CS和IP) |
jmp word ptr 内存单元地址 |
内存单元的值赋给IP | 段内近转移( -32768~32767 ) |
jmp dword ptr 内存单元地址 |
内存单元低地址赋给IP,高地址赋给CS | 段间远转移(改变CS和IP) |
12. jcxz s
解释:当CX为0时,跳转到标号s处,否则往下执行;属于有条件转移指令,短转移,对IP的修改范围为 -128~127
13. call s
解释:将call下一条指令1的地址压入栈中,然后跳转到标号s处
| 搭档 | 解释 | 指令 | 解释 |
|---|---|---|---|
ret |
1. pop ip
|
call s |
1. push ip2. jmp near ptr s
|
call 16位reg |
1. push ip2. jmp 16位reg
|
||
call word ptr 内存单元地址 |
1. push ip2. jmp word ptr 内存单元地址
|
||
retf |
1. pop ip2. pop cs
|
call far ptr s |
1. push cs2. push ip3. jmp far ptr s
|
call dword ptr 内存单元地址 |
1. push cs2. push ip3. jmp dword ptr 内存单元地址
|
14. adc ax,bx
解释:带进位加法,前面指令对标志寄存器中CF的影响会加到这里,等效于 (ax)+(bx)+CF
相关的指令还有 sbb ax,bx ,带进位减法
add al,bl
adc ah,bh
; 等效于 add ax,bx
sub al,bl
sbb ah,bh
; 等效于 sub ax,bx
15. cmp ax,bx
解释:用AX减BX,但不保存结果,只影响标志寄存器,一般和je等条件转移搭配使用
无符号条件转移有:je、jne、jb、jnb、ja、jna;有符号条件转移有:jg、jng、jl、jnl;更多内容可参考:http://marin.jb.free.fr/jumps/
; 应用示例
cmp bl,11
jb s
inc ax
s: inc si
loop k
...
16. pushf
解释:标志寄存器压栈
相关指令 popf 从栈中取值赋给标志寄存器
17. rep movsb
解释:串传送指令, movsb 是按照byte传送; movsw 是按照word传送
| 指令 | 解释 |
|---|---|
movsb |
1. ((es)*16+(di))=((ds)*16+(si)) 2. 如果df=0( cld ),则 inc si,inc di ;如果df=1( std ),则 dec si , dec di
|
rep movsb |
s:movsbloop s(重复次数由CX决定) |
串传送步骤:
- 设置DS:SI和ES:DI
- 设置传送方向,cld(低到高)、std(高到低)
- 设置传送长度CX
-
rep movsb或者rep movsw
18. int 21h
解释:21h号中断,对应中断向量表 0:21h*4 位置(这里存储了21h中断例程的段地址 0:21h*4+2 和偏移地址 0:21h*4 ),再执行中断例程,一般中断程序中会有 iret 返回
| 指令 | 解释 |
|---|---|
int 21h |
1. 取得中断类型码N(如21h) 2. pushf3. TF=0,IF=0 4. push cs , push ip5. (IP)=(4\*N),(CS)=(4\*N+2) |
iret |
1. pop ip2. pop cs3. popf
|
报错指南
-
[idata]单独表示编译器会报错,可以使用ds:[idata],或者先mov bx,idata再用[bx]表示(idata即普通数据,如33H) - 不能对两个内存单元地址直接操作,如
mov 内存单元地址,内存单元地址 - 包含多段(code segment、data segment、stack segment等)的程序必需加入代码开始标号,最后
end 标号,否则编译器默认第一段开始为代码段 - 地址如果用16进制表示,结尾需要加上H
- 内存单元与数据的操作(
mov、add、and等),需要指明word ptr或者byte ptr
-
CPU执行指令的步骤是:1. 从CS:IP指向的内存单元读取指令进入指令缓冲器;2. IP指向下一条指令;3. 执行缓冲器中的指令 ↩
Leave a comment