第六部分 数据处理

Download Report

Transcript 第六部分 数据处理

第六部分 数据处理
Assembly Language
Programming
1 串数据的处理
串?
内存中的一系列的字节或者字
支持串的操作
– 复制
– 存储
– 比较
– 查找
串操作的特点
操作的数据单位
– 字节DB, 字DW, 双字DD
– 对奇数字节串,选用字节操作
– 对偶数字节串,选用字操作,加快速度
寄存器的使用
– 源寄存器:DS:SI 目标寄存器:ES:DI
– 通常需要定义扩展段ES,不过也可以如下:
MOV AX, @data
MOV DS, AX
MOV ES, AX
操作指令
操作
基本指令
隐含操作数
字节操作
字操作
双字操作
MOVE
MOVS
ES:DI, DS:SI
MOVSB
MOVSW
MOVSD
LOAD
LODS
AX, DS:SI
LODSB
LODSW
LODSD
STORE
STOS
ES:DI, AX
STOSB
STOSW
STOSD
COMPARE CMPS
DS:SI, ES:DI
CMPSB
CMPSW
CMPSD
SCAN
ES:DI,AX
SCASB
SCASW
SCASD
SCAS
两种方式:基本指令和标准指令
基本格式指令
格式;
MOVS BYTE1, BYTE2
传送从BYTE2开始的字节到开始于BYTE1
的字节。其中
– 操作数源和目标都采用上表中的寄存器
– BYTE1, BYTE2操作数指明传送的长度
注:我们侧重于标准格式
重复前缀指令REP
REP指令重复执行相应指令,例如
REP MOVSB
– 重复的次数由CX定
– 每执行一次,CX - - , 直到CX减为0为止
串操作的重复方向:决定了对SI和DI的操作
– 左右:CLD 将DF清0
字节:SI = SI + 1 , DI = DI + 1
字: SI = SI + 2, DI = DI + 2
– 右左:STD 将DF置1
字节:SI = SI - 1 , DI = DI - 1
字: SI = SI - 2, DI = DI - 2
串传送Moving
MOVSB, MOVSW
– 字节或者字在内存间的拷贝
– 执行效果:
源寄存器 DS:SI 和 目标寄存器 ES:DI
SI 和 DI 加/减 1或2
– 若CX中含有重复操作的次数,REP前缀重复执
行串数据的传送操作
例:串拷贝
;Copy array a to b, assume ES=DS, and 10 bytes are to be copied
;字节复制
MOV
MOV
MOV
CLD
REP
CX, 10
DI, OFFSET B
SI, OFFSET A
;10 bytes to copy
;destination
;source
;left to right
MOVSB
;字复制
MOV CX, 5
MOV DI, OFFSET B
MOV SI, OFFSET A
CLD
REP MOVSW
;10 bytes to copy
;destination
;source
;left to right
例:数据迁移
;shift bytes of a 3 bytes to right
MOV CX, 7
;bytes to copy
MOV DI, OFFSET A+9 ;destination
MOV SI, OFFSET A+9-3 ;source
STD
;copy from right to left
REP MOVSB
SI
A
DI
例:复制
PATTERN DB "!@#*"
;duplicate data
DB
(100-4) DUP (?) ;space
MOV CX, 100-4
;96 bytes to copy
MOV SI, OFFSET PATTERN
MOV DI, OFFSET PATTERN+4
CLD
;destructive overlap
REP MOVSB
DI
SI
! @ # *
a
串存入Storing
STOSB, STOSW
将 AL 或 AX 数据拷贝到串相应的字节或字中
– 拷贝的目标地址由 ES:DI指定
– 每完成拷贝,ES:DI指向下一个拷贝的地址上
可以结合REP重复进行操作
例:存储的初始化
ARR DW 200 DUP (?) ;empty words
;to be initialized to A050A050...
MOV AX, 50A0H
MOV DI, OFFSET ARR
MOV CX, 200
;array size
CLD
AH AL
REP STOSW
DI
AX 50 A0
A0 50 A0 50
ARR
读取串 Loading
LODSB, LODSW
– 将 DS:SI 地址的数据拷贝到 AL 或 AX
– 每完成一次读取,DS:SI指向下一读取的单位
例:串处理
;array B = toUpper(array A)
MOV DI, OFFSET B
;dest
MOV SI, OFFSET A
;source
MOV CX, 30
;array size
CLD
;left to right processing
LP:
LODSB ;get next byte
AND AL,0DFh
;to upper case
STOSB ;store at next location
LOOP LP
串扫描Scanning
SCASB, SCASW
将AL 或 AX 数据和 ES:DI地址中的数据比较,DI
自动加减
该指令设置标志寄存器
– 依据比较的结果设定标志位
– 在循环中使用,或者使用带条件的REP
REPZ / REPE: 当CX不为0,并且ZF为0时,重复操作。当
ZF不为0或不相等 或 CX减到0时,停止重复。
REPNZ / REPNE:当CX不为0,并且ZF不为0时,重复操作。
当ZF为0或相等 或 CX减到0时,停止重复。
SCASx 和 CMPSx 条件重复语义
while (CX != 0 ) {
do string primitive;
--CX;
if (REPNE and ZF == 1)
exit loop;
if (REPE and ZF == 0)
exit loop;
}
重复首先检测CX是否
为0
检测0标记被设置放在
最后——这就决定了,
不管一次操作是否退
出,SI / DI都要进行加
减
只有 CMPS 和 SCAS
指令影响 ZF 置位
例1:串查找
ARR DB 'abcdefghijklmnopqrstuvwxyz'
MOV
DI, OFFSET ARR
MOV
CX, 26
; 26 bytes
CLD
;left to right processing
MOV
AL,TARGET
;ch to find
REPNE SCASB
;search for match
;make at most cx comparisons
JNE
NOMATCH ;ZF never set
;match occurred at ES:[di-1]
;di is incremented even if match
例2:查找与替换
在串中查找*,并用空格替换
LEN EQU 13 ;data length
TESTDATA DB ‘extra*innings’
……
CLD
MOV AL, ‘*’
MOV CX, LEN
LEA DI, TESTDATA
REPNE SCASB
JNE exit
MOV BYTE PTR[DI-1], 20H
串比较Comparing
CMPSB, CMPSW
将 DS:SI  ES:DI比较,设置标记位,并
且将SI和DI加减
通常使用条件的REP指令
注意:CMP op1, op2是将操作数1减去操作
2,仅限于代数比较;而CMPS是ASCII码
比较
例:串比较
MOV
SI, OFFSET STR1
MOV
DI, OFFSET STR2
CLD
;left to right processing
MOV
CX, 12
;shorter string
REPE
CMPSB ;cmp til <> or cx=0
JL
str1smaller
JG
str2smaller
;the strings are equal - so far
;if sizes different, shorter string
is less
注意:串以字为单位比较时
当以字为单位比较时,
例如:SAMUEL和ARNOLD时,
A
S
<
R
A
SI
DI
SAMUEL
ARNOLD
字节定义DB
高
S
A
SI
SAUMLE
字定义DW
>
A
R
DI
RAONDL
高
2 算术运算(I)
——处理二进制数据
预备1:有符号数和无符号数
格式
字节
Max无符号数 255 / 28-1
Max有符号数
127 / 27-1
字
双字
216-1
232-1
215-1
231-1
无符号数:所有位均为数据位
有符号数:最左边的位为符号位
– 例如:1111 1101 无符号数252,而有符号数为-7
预备2:算术进位
算术进位
无符号数
1111 1101
有符号数
252
- 4
CF = 1, OF = 0
+ 0000 0101
+
5
+
5
1 0000 0001
无效
1
有效
1
进位CF的设置,由符号位的运算进位0或1产生的。
对于无符号数,产生了数据位的进位而无效。
预备2:算术溢出
溢出的两情形:
无符号数
0111 1001
有符号数
121
+121
CF = 0, OF = 1
+ 0000 1011
1000 0100
+ 11
有效 132
+
11
无效 -124
情形1:当符号位有进位输入,而没有进位输出时
无符号数
1111 0110
CF = 1, OF = 1
+ 1000 1001
1
0111 1111
有符号数
+246
-10
+ 137
+ -119
无效 127
无效 127
情形2:当进位输出不是由进位输入产生时
预备3:扩展
字节字
– 无符号数
– 有符号数
字双字
– 无符号数
– 有符号数
Preparing Dividend
To divide a word in AX by a word, AX must
be converted to a doubleword in DX:AX
– If signed: CWD (called sign-extension)
– If unsigned: MOV DX,0
For byte (in AL) to word (AX) conversion
– If signed: CBW (these do not affect Flags)
– If unsigned: MOV AH,0
加减运算
溢出对有符号数的加减运算有影响,应注
意。
加法
减法
ADD
通常加法
SUB
通常减法
ADC
带进位的加法
SBB
带借位的减法
双字值的算术运算
WORD1A
WORD1B
WORD2A
WORD2B
WORD3A
WORD3B
DW
DW
DW
DW
DW
DW
0BC62H
0123H
553AH
0012H
?
?
例1:请运算
WORD1B : WORD1A
+ WORD2B : WORD2A
WORD3B : WORD3A
程序:
MOV AX, WORD1A
ADD AX, WORD2A
MOV WORD3A, AX
MOV AX, WORD1B
ADC AX, WORD2B
MOV WORD3B, AX
思考:将上述例子扩展,任意长
度的字数据运算
程序
CLC
MOV CX, 02
LEA SI, WORD1A
LEA DI, WORD2A
LEA BX, WORD3A
INC SI
INC SI
INC DI
INC DI
INC BX
L20:
MOV AX, [SI]
ADC AX, [DI]
MOV [BX], AX
INC BX
LOOP L20
乘法指令
有符号数乘法
IMUL source
无符号数乘法
MUL source
source :寄存器或内存地址 (但不能为常数)
格式
字节×字节
– AX=AL*source
AH(不管)
AL被乘数
AX乘积
字×字
– DX:AX=AX*source
CF=OF
– 1 若乘积的长度 > 操作数的
长度
– 0 反之
SF, ZF, AF, 和 PF
– 无定义
DX(不管)
AX被乘数
乘积
例1 IMUL
MOV BL,0FEh
MOV AL,0E5h
IMUL BL
BL  -2, AL -27
IMUL运算后
– AX  0036h (54d)
– CF=OF=0 (result still fits in byte)
– SF, AF, PF, ZF 无定义
例2 MUL
MOV BL,0FEh
MOV AL,0E5h
IMUL BL
BL  254, AL  229
MUL运算后
– AX  0E336h (58166d)
– CF=OF=1 (result requires a word)
– SF, AF, PF, 和 ZF 无定义
例3 IMUL
MOV AWORD,-136
MOV AX,6784
IMUL AWORD
AWORD  0FF78h, AX  1A80h
IMUL运算后
– DX:AX  0FFF1EC00h (-922624d)
– CF=OF=1 (result requires a doubleword)
例4 MUL
MOV AWORD,-136
MOV AX,6784
MUL AWORD
AWORD  0FF78h (65400d), AX 
1A80h
MUL运算后
– DX:AX  1A71EC00h (443673600d)
– CF=OF=1 (result requires a doubleword)
例5 IMUL
MOV AX,-1
MOV DX,2
IMUL DX
AX  0FFFFh, BX  0002h
IMUL运算后
– DX:AX  0FFFFFFFEh (-2d)
– CF=OF=0 (result still fits in a word)
双字乘法——双字×字
1365
×
×
12
16380
×
12
156 00
3206 2521H
×
65
13
类似上述的算法
6400H
?
+
12
780
3206
2521
× 6400
× 6400
0E80 E400
0E80 E400
+ 138A 5800
138A 5800
= 16380
字×字节
MULTCAN DW 2521H
DW 3206H
MULTPLR DW 6400H
PRODUCT DW 0, 0, 0
;lower byte * multplr
MOV AX, MULTCAN
MUL MULTPLR
MOV PRODUCT, AX
MOV PRODUCT +2, DX
;higher byte * multplr
MOV AX, MULTCAN+2
MUL MULTPLR
;add two part
ADD PRODUCT+2, AX
ADC PRODUCT+4, DX
双字乘法——双字×双字
利用上述的思想,拆分为四次字乘法,将
各个乘积加到相应的位置上,即可。
被乘数 AB
B
×
B
×
A
×
B
×
乘数CD
C
D
C
D
依
次
错
一 (进位加法)
个
字
节
相
加
乘积占用4个字
左移运算做乘法
SHL左移一次,相当于×2运算
左移代替乘法,好处:加快运算速度
例如;
– SHL AX, 01
– SHL WORDVAL, 3
除法指令
有符号除法
IDIV divisor
无符号除法
DIV divisor
divisor 为寄存器或者内存地址 (非常
数)
格式
字 除以 字节
– AL = AX / divisor
– AH = AX % divisor
除前
AX 被除数
AH余数
AL商
除后
双字 除以 字
– AX=DX:AX / divisor
– DX=DX:AX % divisor
DX
被除数
余数
所有的标记位没有定义
思考:若出现 字节 除以 字节,字 除以 字 怎么办?
AX
商
除前
除后
例 DIV
数据:
BYTE1 DB 80H
BYTE2 DB 16H
WORD1 DW 2000H
WORD2 DW 0010H
WORD3 DW 1000H
例1:
MOV AX, WORD1
DIV BYTE1
例2:
MOVZX BYTE1
DIV
BYTE2
例3:
MOV
MOV
DIV
例4:
MOV
SUB
DIV
DX, WORD2
AX, WORD3
WORD1
AX, WORD1
DX, DX
WORD3
例 IDIV
数据:
BYTE1 DB 80H
BYTE2 DB 16H
WORD1 DW 2000H
WORD2 DW 0010H
WORD3 DW 1000H
例1:
MOV AX, WORD1
IDIV BYTE1
例2:
MOVZX BYTE1
IDIV
BYTE2
例3:
MOV
MOV
IDIV
例4:
MOV
CWD
DIV
DX, WORD2
AX, WORD3
WORD1
AX, WORD1
WORD3
除法溢出
溢出发生在
– 当字除以字节时:商超过一个字节
– 当双字除以字时:商超过一个字
除法溢出,非法错误终止程序运行
简单的判断溢出发生的方法:
– 字除以字节时: AH>=divisor
– 双字除以字时: DX>=divisor
防止除法溢出
CMP AH, DIVBYTE
JNB L20
DIV DIVBYTE
简单的判断溢出发
生的方法:
–字除以字节时:
AH>=divisor
–双字除以字时:
DX>=divisor
L20:
……
; 溢出处理
3 算术运算(II)
——处理ASCII和BCD数据
提要
ASCII和BCD格式
数据格式的运算
格式间的转换
BCD和ASCII
某数采用ASCII十进制数表示,每个字节存储一个
ASCII数字
Binary-coded decimal (BCD) 数字采用4位二进制
数表示各个十进制数
– 一个十进制数采用非压缩的BCD表示,低4位为相应的
十进制数字符号,高4位为0
– 一个十进制数采用压缩的BCD表示,只用4位为相应的
十进制数字符号
例:5678
ASCII:
4字节
35 36 37 38
非压缩的BCD:
4字节
05 06 07 08
压缩的BCD:
2字节
56 78
AAA 指令
AAA (ASCII adjust after addition)
– 该指令对 ADD 或 ADC 指令的二进制结果进行
调整
– 使得在AL中的结果和 ASCII数字表示相一致。
The Carry value, if any ends up in AH
例:Add '8' and '2'
MOV
MOV
ADD
AAA
OR
AH,0
AL,'8'
; AX = 0038h
AL,'2'
; AX = 006Ah
; AX = 0100h (adjust result)
AX, 3030h
; AX = 3130h = '10'
AAS 指令
AAS (ASCII adjust after subtraction)
– 该指令对SUB 或 SBB 指令二进制结果调整
– 使得AL中的结果和ASCII数字表示相一致
It places the Carry value, if any, in AH
例:Subtract '9' from '8'
MOV AH,0
MOV AL, '8' ; AX = 0038h
SUB AL,'9'
; AX = 00FFh
AAS
; AX = FF09h (adjust result)
PUSHF
; save Carry flag
OR AL,30h
; AX = FF39h (AL = '9')
POPF
; restore Carry flag
AAM 指令
AAM (ASCII adjust after multiplication)
– 该指令对MUL指令的二进制结果调整
该乘法须以非压缩的十进制数字执行
MOV BL,05h
; first operand
MOV AL,06h
; second operand
MUL
; AX = 001Eh
AAM
BL
; AX = 0300h
AAD 指令
AAD (ASCII adjust before division) 该指令
在除法之前,对AX中非压缩的十进制数进
行调整
.code
.data
quotient BYTE ?
remainder BYTE ?
MOV AX,0307h ; dividend
AAD
; AX = 0025h
MOV BL,5
; divisor
DIV BL
; AX = 0207h
MOV quotient,AL
MOV remainder,AH
Packed Decimal Integers
Packed BCD stores two decimal digits
per byte
– For example, 12,345,678 can be stored as
the following sequence of hexadecimal
bytes:
12 34 56 78
There is no limit on the number of bytes you can use to store a
BCD number. Financial values are frequently stored in BCD
format, to permit high precision when performing calculations.
DAA Instruction
The DAA (decimal adjust after addition)
instruction converts the binary result of an ADD
or ADC operation to packed decimal format.
The value to be adjusted must be in AL
Example: calculate BCD 35 + 48
mov al,35h
add al,48h
daa
; AL = 7Dh
; AL = 83h (adjusted)
DAS Instruction
The DAS (decimal adjust after subtraction)
instruction converts the binary result of a SUB or
SBB operation to packed decimal format.
The value must be in AL
Example: subtract BCD 48 from 85
mov al,85h
sub al,48h
das
; AL = 3Dh
; AL = 37h (adjusted)