第8章 数据处理的两个基本问题
定义了两个描述符号:reg 和 sreg
- reg 包含了:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
- sreg 包含了:ds,ss,cs,es
8.1 bx、si、di 和 bp
只有 bx,si,di 和 bp 这4个寄存器可以用 […] 中进行内存单元寻址
比如:下面的指令都是正确的:
mov ax,[bx]
mov ax,[bx+si]
mov ax,[bx+di]
mov ax,[bp]
mov ax,[bp+si]
mov ax,[bp+di]
而下面的指令都是错误的:
mov ax,[cx]
mov ax,[ax]
mov ax,[dx]
mov ax,[ds]
在[…]中,这4个寄存器可以单个出现,或者只能以4中组合出现:bx 和 si,bx 和 di,bp 和si,bp和di,比如下面指令是正确的:
只要在[…]中使用寄存器bp,而指令中没有显性的给出段地址,段地址就默认在 ss 中,比如下面的指令
8.2 机器指令处理的数据在什么地方
在机器指令层面,不关心数据的值,只关心指令执行前一刻,将要处理的数据所在的位置。
要处理的数据可以在三个地方:CPU内部、内存、端口。
表 8.2 指令举例
机器码 | 汇编指令 | 指令执行前数据的位置 |
---|---|---|
8E1E0000 | mov bx,[0] | 内存,ds:0单元 |
89C3 | mov bx,ax | CPU内部,ax寄存器 |
BB0100 | mov bx,1 | CPU内部,指令缓冲器 |
8.3 汇编语言中数据位置的表达
8.3.1 立即数
立即数:对于直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编语言中称之为立即数,在汇编指令中直接给出
mov ax,1
add bx,2000h
or bx,00010000b
mov al,'a'
8.3.2 寄存器
寄存器:要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名
mov ax,bx
mov ds,ax
push bx
mov ds:[0],bx
push ds
mov ss,ax
mov sp,ax
8.3.3 段地址(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] 含义:(ax) = ((ds)*16+(bp))
mov ax,es:[bx] 含义:(ax) = ((es)*16+(bx))
mov ax,ss:[bx+si] 含义:(ax) = ((ss)*16+(bx)+(si))
mov ax,cs:[bx+si+8] 含义:(ax) = ((cs)*16+(bx)+(si)+8)
8.4 寻址方式
8.5 指令要处理的数据有多长
在机器指令中要指明指令进行的是字操作还是字节操作
通过寄存器名指明要处理的数据的尺寸
指明指令进行的是字操作
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
使用操作符 X ptr 指明内存单元的长度,X 在汇编中可以指定为 word 或者 byte
用 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 或 byte ptr 显性的指明所要访问的内存单元的长度是很有必要的!
假设我们用 Debug 查看内存的结果如下:
这是因为 mov byte ptr [1000H],1
访问的地址是 ds:1000H
的字节单元,修改的是 ds:1000H 单元的内容;
而 mov word ptr [1000H],1
访问的地址是 ds:1000H
的字单元,修改的是 ds:1000H 和 ds:1001H 两个单元的内容。
有些指令默认了访问的是字单元还是字节单元。
比如:push [1000H] 默认字单元,因为 push 指令只进行字操作。
8.6 div 指令
div 是除法指令,使用 div 做除法的时候注意以下问题:
要求被除数默认存放在 ax,或者 dx 和 ax 中,而且要求被除数的位数,必须是除数的2倍,比如说,除数位8位,被除数就为16位。为什么被除数的位数一定要为除数的2倍呢?
因为 CPU 只会做加法运算,把其它一切的算法都转换成加法,比如说,除数 就先转换加法,例如36/6 当 CPU 看到这个运算时,就会这样想,需要多少个 6 相加才能得到 36 呢,然后CPU就从1个6 ,2个6…这样一种算下去,终于最后发现原来是6个6啊,从这我们可以看出,CPU 是不断的用除数相加,知道找到结果为止,这就出现问题了,如果被除数不是除数位数的2倍,再相加的过程中,就可能超出除数的位数所能表达的最大数值,从而越界,如果能保证 被除数是除数的2倍 ,这问题就能解决了,例如:8 /5 5+ 5 =10 超出所能表达的位数,08 /5 就可以解决这个问题
- 除数:有8位和16位两种,在一个 reg 或者内存单元中
- 被除数:默认放在 AX 或者 DX 和 AX 中,如果除数为8位,被除数为16位,默认在 AX 中存放;如果除数为16位,被除数为32位,在 DX 和 AX 中存放,DX 存高 16 位,AX 存低 16 位
- 商:如果除数为8位,AL 存储除法操作的商,AH 存储除法操作的余数;如果除数为16位,AX 存储除法操作的商,DX 村存储除法操作的余数
8.7 伪指令 dd
db 和 dw 定义字节型数据和字型数据,dd 用来定义 dword(double world,双字)型数据
data segment
db 1
dw 1
dd 1
data ends
在 data 段中定义了 3 个数据
第一个数据为 01H,在 data:0 处,占1个字节;
第二个数据为 0001H,在 data:1 处,占1个字;
第三个数据为 00000001H,在 data:3 处,占2个字。
8.8 dup
dup 是一个操作符,和 db、dw、dd 等数据定义伪指令配合使用,用来进行数据的重复。