第八章 数据处理的两个基本问题
# 第八章 数据处理的两个基本问题
本章旨在进一步加强对不同寻址方式的理解及运用。
计算机是进行数据处理、运算的机器,这其中包含两个基本的问题:
(1)处理的数据在什么地方?
(2)要处理的数据有多长?
携带着这两个问题,我们开启第八章的学习之路。
# 8.1 bx、si、di 和 bp
首先看下这四个寄存器的含义:
bx, Base,Pointer to base addresss (data)。一般用于存储数据段的基址(首地址)。
si,Source Index,Source string/index pointer。一般用于存储源数组数据索引(下标)。
di,Destination Index,estination string/index pointer。一般用于存储目标数组数据索引(下标)。
bp,Base Pointer,Pointer to base address (stack)。一般用于存储栈的基址。
然后在使用过程中有几处需要注意的地方:
(1)在 8086CPU 中,只有这 4 个寄存器可以用在 “[....]” 中来进行内存单元的寻址。其他寄存器是不可以的,例如 “mov bx, [ax]” 就是错误的用法。
(2)在 [...] 中,这四个寄存器可以单个出现,或只能以 4 种组合出现:bx 和 si、bx 和 di、bp 和 si、bp 和 di。为了方便记忆可以将 si 和 di 看做一组,将 bx 和 bp 看做一组。组间可以自由组合,组内不能组合。(脑补为人类不可以近亲繁殖。)
(3)只要在 [...] 中使用寄存器 bp,而指令中没有显性的给出段地址,则段地址就默认在 ss 中。
# 8.2 机器指令处理的数据在什么地方
这是我们在开头抛出的两个问题中的第一个。
在指令执行前,所要处理的数据可以在 3 个地方:CPU 内部、内存、端口(端口暂时不用知道是什么东西)。
我们知道了存储数据的部件,但如果具体找到这些部件存储的数据位置?下一节将解答我们的疑问。
# 8.3 汇编语言中数据位置的表达
在汇编语言中如何表达数据的位置?
汇编语言中用 3 个概念来表达数据的位置。
(1)立即数
对于直接包含在机器指令中的数据(执行前在 CPU 的指令缓冲器中),汇编语言中称为立即数(idata), 在汇编指令中直接给出。 例如:
mov ax, 1
or bx, 00100000B
2
2
(2)寄存器
指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。例如:
mov ax, bx
push bx
2
2
(3)段地址(SA)和偏移地址(EA)
指令要处理的数据在内存中,在汇编语言中可以用 [X] 的格式给出 EA,SA 在某个段寄存器中。
存放段地址的寄存器可以是默认的,也可以显性给出。例如:
;段寄存器默认存储在DS中
mov ax, [0]
mov ax, [bx]
mov ax, [di]
...
;段寄存器默认存储在SS中
mov ax, [bp]
mov ax, [bp+si]
mov ax, [bp+di]
...
;段寄存器显性给出
mov ax, ds:[bp]
mov ax, es:[3]
mov ax, ss:[bx+si]
mov ax, cs:[bx+si+8]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 8.4 寻址方式
这一节我们总结一下所学到过的寻址方式。列表如下:
寻址方式 | 含义 | 名称 | 常用格式举例 | 备注 |
---|---|---|---|---|
[idata] | EA=idata; SA=(ds) | 直接寻址 | [idata] | 偏移地址 = 立即数 |
[bx] | EA=(bx); SA=(ds) | 寄存器间接寻址 | [bx] | 偏移地址 = 变量 |
[bx+idata] | EA=(bx)+idata; SA=(ds) | 寄存器相对寻址 | 用于结构体: [bx].idata ; 用于数组: idata[si] , idata[di] ; 用于二维数组: [bx][idata] | 偏移地址 = 变量 + 立即数 |
[bx+si] | EA=(bx)+(si); SA=(ds) | 基址变址寻址 | 用于二维数组: [bx][si] | 偏移地址 = 变量 + 变量 |
[bx+si+idata] | EA=(bx)+(si)+idata; SA=(ds) | 相对基址变址寻址 | 用于表格(结构)中的数组项: [bx].idata[si] ; 用于二维数组: idata[bx][si] | 偏移地址 = 变量 + 变量 + 立即数 |
注意在 8.1 节指出的特殊情况,只要在 [...] 中使用寄存器 bp,而指令中没有显性的给出段地址,段地址就默认在 ss 中。
# 8.5 指令要处理的数据有多长
这是我们在开头抛出的两个问题中的第二个。
8086CPU 的指令,可以处理两种尺寸的数据,byte 和 word。所以在机器指令中要指明,指令进行的是字操作还是字节操作。对于这个问题,汇编语言中用以下方法处理。
(1)通过寄存器名指定要处理的数据的尺寸。如果寄存器名是字型寄存器(如 ax、bx 等),则说明指令进行的是字操作。如果寄存器名是字节型寄存器(如 al、ah、bl 等),则说明指令进行的是字节操作。
(2)在没有寄存器名存在的情况下,用操作符 X ptr 指明内存单元的长度,X 在汇编指令中可以为 word 或 byte。这种情形适用于没有寄存器参与的内存单元访问指令中。例如:
;下面的指令,用word ptr指明了指令中访问的内存单元是一个字单元
mov word ptr ds:[0], 1
inc word ptr [bx]
;下面的指令,用byte ptr指明了指令访问的内存单元是一个字节单元
mov byte ptr ds:[0], 1
inc byte ptr [bx]
2
3
4
5
6
7
2
3
4
5
6
7
(3)其他方法。有些指令默认了访问的是字单元还是字节单元,比如,push [1000H] 就不用指明访问的是字单元还是字节单元,因为 push 指令只会进行字操作。
# 8.6 寻址方式的综合应用
8086CPU 提供的如 [bx+si+idata] 的寻址方式为结构化数据的处理提供了方便。使得我们可以在编程的时候,从结构化的角度去看待所要处理的数据。正常情况下,一个结构化的数据包含了多个数据项,而数据项的类型又不相同,有的是字型数据,有的是字节型数据,有的是数组(字符串)。一般来说,我们可以用 [bx+idata+si] 的方式来访问结构体中的数据。用 bx 定位整个结构体,用 idata 定位结构体中的某一个数据项,用 si 定位数组项中的元素。为此,汇编语言提供了更为贴切的书写方式,如 [bx].idata、[bx].idata [si]。
# 8.7 div 指令
div 是除法指令。在使用的过程中应注意以下问题:
(1)除数:有 8 位和 16 位两种,在一个 reg (寄存器) 或内存单元中。
(2)被除数:默认放在 AX 或 DX 和 AX 中,如果除数为 8 位,被除数则为 16 位,默认在 AX 中存放;如果除数为 16 位,被除数则为 32 位,在 DX 和 AX 中存放,DX 存放高 16 位,AX 存放低 16 位。
(3)结果:如果除数为 8 位,则 AL 存储除法操作的商,AH 存储除法操作的余数;如果除数为 16 位,则 AX 存储除法操作的商,DX 存储除法操作的余数。
div 使用格式如下:
div reg
div 内存单元
# 8.8 伪指令 dd
dd 用来定义 dword(双字)型数据。
# 8.9 dup
dup (duplication 的缩写) 用来重复开辟内存空间。
dup 指令要和 db、dw、dd 等数据定义伪指令配合使用,使用格式如下:
db 重复次数 dup (重复的字节型数据) dw 重复次数 dup (重复的字型数据) dd 重复次数 dup (重复的双字型数据)
例如,如下代码表示定义了 9 个字节:
db 3 dup (0,1,2)