前言
参考书籍:
王爽。汇编语言。北京:清华大学出版社, 2013:161-172
本人菜狗一枚,不敢咬文嚼字,只能站在巨人的肩膀上窥探一下未曾了解的世界。
计算机进行数据处理和运算的两个基本问题
- 处理的数据在什么地方?
- 要处理的数据有多长?
描述性符号:reg 表示寄存器,sreg 表示段寄存器
机器指令处理的数据在什么地方
数据处理指令:读取、写入、运算
指令执行前数据可能存储的位置:CPU 内部、内存、端口
机器码 | 汇编指令 | 指令执行前数据的位置 |
---|---|---|
8E1E0000 | mov bx, [0] | 内存,ds:0 单元 |
89C3 | mov bx, ax | CPU 内部,ax 寄存器 |
BB0100 | mov bx, 1 | CPU 内部,指令缓冲器 |
汇编语言中数据位置的表达
-
立即数(idata)
直接包含在机器指令中的数据(执行前在 CPU 指令缓冲器中)mov ax, 1 or bx, 00010000b ;立即数(idata)在汇编指令中直接给出 mov al, 'a'
-
寄存器
指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。
mov ax, bx mov ds, ax push bx mov ds:[0], bx push ds mov ss, ax mov sp, ax
-
段地址(SA)和偏移地址(EA)
指令要处理的数据在内存中,在汇编指令中可用 [X] 的格式给出 EA, SA 在某个段寄存器中
存放段地址的寄存器是默认的,也可以显性给出; 段地址默认在 ds 中 mov ax, [0] mov ax, [di] mov ax, [bx+8] mov ax, [bx+si] mov ax, [bx+si+8] ; 段地址默认在 ss 中 mov ax, [bp] mov ax, [bp+8] mov ax, [bp+si] mov ax, [bp+si+8] ; 显性给出段地址 mov ax, ds:[bp] mov ax, es:[bx]
寻址方式
寄存器 bx 段地址默认在 ds
寄存器 bp 段地址默认在 ss
寻址地址 | 偏移地址 | 段地址 | 名称 | 常用格式举例 |
---|---|---|---|---|
idata | idata | (ds) | 直接寻址 | [idata] |
[bx] | bx | (ds) | 寄存器间接寻址 | [bx] |
[si] | (si) | (ds) | ||
[di] | (di) | (ds) | ||
[bp] | (bp) | (ss) | ||
[bx+idata] | (bx)+idata | (ds) | 寄存器相对寻址 | 用于结构体:[bx].idata 用于二维数组:[bx][idata] 用于数组:idata[si],idata[di] |
[si+idata] | (si)+idata | (ds) | ||
[di+idata] | (di)+idata | (ds) | ||
[bp+idata] | (bp)+idata | (ss) | ||
[bx+si] | (bx)+(si) | (ds) | 基址变址寻址 | 用于二维数组:[bx][si] |
[bx+di] | (bx)+(di) | (ds) | ||
[bp+si] | (bp)+(si) | (ss) | ||
[bp+di] | (bp)+(di) | (ss) | ||
[bx+si+idata] | (bx)+(si)+idata | (ds) | 相对基址变址寻址 | 用于二维数组:idata[bx][si] 用于表格(结构)中的数组项:[bx].idata[si] |
[bx+di+idata] | (bx)+(di)+idata | (ds) | ||
[bp+si+idata] | (bp)+(si)+idata | (ss) | ||
[bp+di+idata] | (bp)+(di)+idata | (ss) |
指令要处理的数据有多长
-
通过寄存器名指明要处理的数据的尺寸:byte 或 word
-
寄存器指明进行字操作
mov ax, 1 mov bx, ds:[0] mov ds, ax mov ds:[0], ax inc ax add ax, 1000
-
寄存器指明进行字节操作
mov al, 1 mov al, bl mov al, ds:[0] mov ds:[0], al inc al add al, 100
-
-
在没有寄存器名存在的情况下,用操作符 byte / word ptr 指明内存单元的长度
- 用 word ptr 指明指令访问的内存单元是一个字单元
mov word ptr ds:[0], 1 inc word ptr [bx] inc word ptr ds:[0] add word ptr [bx], 2
- 用 byte ptr 指明指令访问的内存单元是一个字节单元
mov byte ptr ds:[0], 1 inc byte ptr [bx] inc byte ptr ds:[0] add byte ptr [bx], 2
- 用 word ptr 指明指令访问的内存单元是一个字单元
-
其他方法
有些指明默认了访问的单元尺寸,如 push 指令只进行字操作
div 指令
div 是除法指令,div 内存单元
- 除数:8/16 位,在一个 reg 或 内存单元中
- 被除数:默认放在 AX 或 DX和AX中
- 除数为 8 位, 被除数则为 16 位,默认存放在 AX 中
- 除数为 16 位, 被除数则为 32 位,在 DX和AX 中存放,DX存放高 16 位, AX 存放低 16 位
- 结果:
- 除数为 8 位,则 AL 存储除法操作的商,AH 存储除法操作的余数
- 除数为 16 位, 则 AX 存储除法操作的商,DX 存储除法操作的余数
汇编指令 | 商 | 余数 | 含义 |
---|---|---|---|
div type ptr ds:[0] | al | ah | (al) = (ax) / ((ds) * 16 + 0) 的商 (ah) = (ax) / ((ds) * 16 + 0) 的余数 |
div word ptr es:[0] | ax | dx | (ax) = [(ds) * 10000H + (ax)] / ((es) * 16 + 0) 的商 (dx) = [(ds) * 10000H + (ax)] / ((es) * 16 + 0) 的余数 |
div byte ptr [bx+si+8] | al | ah | (al) = (ax) / ((ds) * 16 + (bx) + (si) + 8) 的商 (ah) = (ax) / ((ds) * 16 + (bx) + (si) + 8) 的余数 |
div word ptr [bx+si+8] | ax | dx | (ax) = [(dx) * 10000H + (ax)] / ((ds) * 16 + (bx) + (si) + 8) 的商 (dx) = [(dx) * 10000H + (ax)] / ((ds) * 16 + (bx) + (si) + 8) 的余数 |
; 计算100001 / 100
; 被除数 100001 大于 65535, 进行 16 位除法
mov dx, 1
mov ax, 86AH ;(dx) * 10000H + (ax) = 100001
mov bx, 100
div bx
; 计算 1001 / 100
; 被除数 1001 可用 ax 寄存器存放, 进行 8 位除法
mov ax, 1001
mov bl, 100
div bl
伪指令 dd
dd 是用来定义 dword(double word,双字)型数据的
data segment
db 1 ; 在 data:0 处定义字节型数据 01H
dw 1 ; 在 data:1 处定义字型数据 0001H
dd 1 ; 在 data:3 处定义双字型数据 00000001H
data ends
dup
dup 是一个操作符,同 db、dw、dd 等一样,也是由编译器处理识别的符号。它是和 db、dw、dd 等数据定义伪指令配合使用的,用来进行数据的重复
dup 的使用格式:
- db 重复的次数 dup (重复的字节型数据)
- dw 重复的次数 dup (重复的字型数据)
- dd 重复的次数 dup (重复的双字型数据)
; 定义了 3 个字节, 它们的值都是 0
; 相当于 db 0, 0, 0
db 3 dup (0)
; 定义了 9 个字节, 它们是 0, 1, 2, 0, 1, 2, 0, 1, 2
; 相当于 db 0, 1, 2, 0, 1, 2, 0, 1, 2
db 3 dup (0, 1, 2)
; 定义了 18 个字符, 它们是 'abcABCabcABCabcABC'
; 相当于 db 'abcABCabcABCabcABC'
db 3 dup ('abc', 'ABC')