【微机原理与接口 7】—— 常用指令分析4 (串操作指令剖析)

一、关于串操作的一些说明:

虽然我们知道,在高级语言里面,串 和 一般的数据的标识符会有一些不一样(比如C++ 里面整形的 int 以及字符串的 string )但是,在底层语言里面,他们类型其实都是一样的二进制数。只不过串是一个数据块。我们用下图说明一下:

那么, 在执行串操作之前,我们需要确定以下的几件事情:

  1. 串所在的区域,串的首地址(这里的串包括源串和目标串)
  2. 串的长度
  3. 串操作的方向,这个我们用一张图来理解:

如果横向的蓝色箭头表示的是源串首,假如串操作的方向是 由低地址向高地址,那么实际上要操作的串就是下方的一块区域;但是如果方向是 由高地址向低地址,那么要操作的串就应该是上方的一块区域。二者的串本身完全不一样!

  1. 串操作的指令之前可以加上一个重复前缀。

下面,我们一一来解释以下:
【1】首先是串的位置:我们的操作对象是 源串和目标串。其中,源串默认的段首地址存放在 D S DS (数据段里面),串首地址存放在 S I SI ,即: D S : S I DS:SI 。(其中 D S DS 可以使用段超越变成其他段)
目标串它的段地址默认是在附加段 E S ES ,串首地址在 D I DI 里面(注意 E S ES 不允许被段超越!)

【2】关于串的长度,我们会将串的长度值存放在 C X CX 里面。在使用串操作指令之前,我们需要给 C X CX 赋初值

【3】关于串操作的方向,我们使用状态标识里面的 D F DF 来表示:如果 D F = 0 DF = 0 表示的是串操作从低地址向高地址执行如果 D F = 1 DF = 1 ,那么表示从高地址向低地址执行。同样地,我们也要在使用串操作指令之前,给 D F DF 赋初值: C L D CLD 表示将 D F DF 清零; S T D STD 表示将 D F DF 置1

【4】关于串操作指令前面的循环前缀(这是串操作指令所特有的),重复前缀可以分为无条件前缀和条件前缀。其中,无条件前缀我们用 R E P REP 表示,它的意思是:只要当 C X 0 CX ≠0 的情况下,我们就一直执行 R E P REP 后面跟着的语句 我们可以看到,因为是无条件地反复执行,因此,后面常常跟串传输类指令

而对于条件前缀,我们分两种:
(1)REPZ,或者说 REPE(都行):它的意思是"相等则重复“当 C X 0 CX ≠0 ,且 Z F = 1 ZF = 1 时,重复执行
(2)REPNZ,或者说 REPNE:它的意思是“不相等则重复”,即当 C X 0 CX ≠0 ,且 Z F = 0 ZF = 0 时重复执行
我们可以看到,对于条件前缀,后面常常跟串运算类指令

1.1 串操作指令执行的一般流程

我们用下图说明:

其中,我们可以看到流程图主要分成了两块:左边的四个步骤,我们称之为初始化。这里需要特别说明:串操作指令中,每操作完一个字节或者一个字之后,串首指针是指令自动更改的。不需要我们手动设置。而上图几乎是所有串操作指令执行都需要经过的流程图,我们发现:在每操作完一个字节或者一个字之后,并不是立刻就去判断是不是已经完成了所有操作,而是在修改完地址指针之和,还需要经过修改串长度(这需要我们自己写程序控制)的这个操作之后,才到判断。

下面,我再把这个图分模块画一下:

那么,试想一下:假如我们的串操作方向是 DF = 0,而且是一个串传输指令;那么在所有数据传输完毕之后,串首指针应该是在串尾的后一位!

二、正题——串操作指令

2.1 串传送指令 MOVS

首先是串传送: M O V S MOVS ,更具体地说,应该分成两种: M O V S B MOVSB M O V S W MOVSW
M O V S B MOVSB 顾名思义就是传送1个字节(也就是8位)的串;而 M O V S W MOVSW 则是传送 1个字的串。

我们看一个例子学习它的用法:

使用 M O V S MOVS 指令,将200个字节数据从内存数据段 MEM1 为首地址的区域送到一个逻辑段 MEM2
为首地址的区域:(我们下面给出程序的分析):

LEA SI, MEM1     //这句话的意思是给源串的串首赋初值(要赋值给SI寄存器)
LEA DI MEM2      //这句话也是给目标串的串首地址赋初值(要赋值给 DI 寄存器)
MOV CX 200       //给 串的长度赋初值(要赋值给 CX)
CLD              //令 DF = 0,说明是从低地址向高地址执行
REP MOVSB        //无条件重复:只要 CX ≠0 就一直执行串的传输
HLT              //当REP跳出来了,就结束

当然也是可以用 M O V S W MOVSW 的,这样的话,我们的 CX 就要赋初值为 100 了,因此 M O V S W MOVSW 一次操作16位

那么,假如我们想要验证我们传输的串对不对,那么就需要将这两个串进行比较。因此就引出了串比较指令:

2.2 串比较指令 CMPS

同样地,CMPS 也分为:CMPSB, CMPSW。它执行的是啥呢?—— 目标串 - 源串,但是结果并不返回目标串。也即是实现两串的比较。

对于串比较指令,我们一般在它前面加条件前缀。

那么,依旧是刚刚的例子,我们在传输完了 200 个字节的串之后,想要检测一下是否正确传输,我们就需要比较两个串了:下面是程序分析:

	LEA SI, MEM1
	LEA DI MEM2
	MOV CX, 200
	CLD             //上面四条语句全都是初始化
	REPE CMPSB
	JZ STOP         //JZ 表示当 ZF = 1 时执行跳转,执行到这里如果ZF仍然为1说明两串一样
	DEC SI          //完成SI的自减,回顾上面的流程图,SI现在是在串低的后一位
	MOV AL, [SI]
	MOV BX, SI
STOP: HLT

首先,我们明确一件事情:REPE 的意思是相同即重复( C X 0 CX≠0 ,且 Z F = 1 ZF = 1 ),也就是说当比较的串一样时,就继续比。那么 REPE 退出的情况有什么呢?

  1. CX = 0(说明比完了,那么就是两个串完全一样)
  2. C X 0 CX≠0 ,但是 Z F = 0 ZF = 0 (说明在中间有两个串不一样的地方了)

JZ 表示当 Z F = 1 ZF = 1 时执行跳转,跳转到 STOP

2.3 串扫描指令

我们常常使用的是 S C A S B SCASB S C A S W SCASW 。当我们使用 S C A S B , S C A S W SCASB, SCASW 时,源操作数是不用写出来的,但是要在程序的前面声明。(注意:使用 S C A S B , S C A S W SCASB, SCASW 时,源操作数是 A L AL 或者 A X AX 。当使用 S C A S B SCASB 时,一次操作一个字节单元,源操作数就是 A L AL )

另外,说一下 S C A S B , S C A S W SCASB, SCASW 都干了什么:

我们以 S C A S B SCASB 为例,它执行的是将 A L AL 里面存放的字节依次 和串内的每一个字节单元相减,但是结果不返回,影响标志位 Z F ZF ,用于搜索串里面有没有哪个字节单元的内容和 A L AL 的一样。

举一个例子:在 ES段中从 2000H 单元开始存放了 10 个字符,寻找其中有没有字符 ‘A’,若有则记录搜索次数,将搜索次数写入 DATA1 单元,并将 ‘A’ 写入 DATA2 单元。

首先,我们要明确一件事情:目标串地址在 ES:DI 里面。

		MOV DI, 2000H     //先给DI 赋值
		MOV BX, DI        //地址备份,用于后面计算搜索次数
		MOV CX, 10        //因为如果采用SCASB,那么就是一个字节一个字节搜索,10次
		CLD
		REPNZ SCASB       //“若不相等则重复”,如果不相等,即ZF = 0 ,那么就一直搜索
		JZ FOUND          //若 ZF = 1 就跳转到 FOUND(ZF=1 说明找到一样的了)
		MOV DI, 0
		JMP DONE
FOUND:  DEC DI  //因为 DI 是先自增之后才进入判断的,所以在跳出之后DI 会在 'A' 的后一个单元
		MOV DATA1, DI
		INC DC
		SUB DI, BX        //计算搜索次数
DONE: 	MOV DATA2,DI
		HLT 

2.4 串加载与串存储

【1】首先是串加载,我们用 L O D S B LODSB L O D S W LODSW ,既然是 加载,那么就是将串中的数据装载到某个地方,因此,在 L O D S B LODSB L O D S W LODSW 中,串是作为源操作数的,地址在 [ D S : S I ] [DS:SI]

如果使用的是 L O D S B LODSB ,那么它执行的操作是将数据段中地址为 S I SI 的单元装入 A L AL
如果使用的是 L O D S W LODSW ,那么它执行的操作是将数据段中地址为 S I SI 的单元装入 A X AX

【2】下面是串存储,我们用 S T O S B STOSB S T O S W STOSW ,既然是存储,就是把某个内容存储进串里。因此,此时串就作为目标串,地址为: [ E I : D I ] [EI:DI]

如果使用的是 S T O S B STOSB ,那么它执行的是将 A L AL 里面的内容存储进 [ E S : D I ] [ES:DI]
如果使用的是 S T O S W STOSW ,那么它执行的是将 A X AX 里面的内容存储进 [ E S : D I ] [ES:DI]

注意:在串加载与串存储中,是已经限定了 A X , A L AX,AL 的!

发布了140 篇原创文章 · 获赞 411 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_44586473/article/details/105064768