把内存的某部分内容复制到另一个地址,怎么做呢?
设想将DS:SI处的连续512字节内容复制到ES:DI(先不考虑可能的重叠)。也许会有人写出这样的代码:
NextByte: mov cx,512
mov al,ds:[si]
mov es:[di],al
inc si
inc di
loop NextByte ; 循环次数
我不喜欢上面的代码。
它的确能达到作用,但是,效率不好。如果你是在做优化,那么写出这样的代码意味着赔了夫人又折兵。
Intel的CPU的强项是串操作。所谓串操作就是由CPU去完成某一数量的、重复的内存操作。
需要说明的是,我们常用的KMP算法(用于匹配字符串中的模式)的改进——Boyer算法,由于没有利用串操作,因此在Intel的CPU上的效率并非最优。 好的编译器往往可以利用Intel CPU的这一特性优化代码,然而,并非所有的时候它都能产生最好的代码。
某些指令可以加上REP前缀(repeat, 反复之意),这些指令通常被叫做串操作指令。
举例来说,STOSD指令将EAX的内容保存到ES:DI,同时在DI上加或减四。 类似的,STOSB和STOSW分别作1字节或1字的上述操作,在DI上加或减的数是1或2。
计算机语言通常是不允许二义性的。为什么我要说“加或减”呢?没错,孤立地看STOS?指令,并不能知道到底是加还是减,因为这取决于“方向”标志(DF, Direction Flag)。 如果DF被复位,则加;反之则减。
置位、复位的指令分别是STD和CLD。
当然,REP只是几种可用前缀之一。常用的还包括REPNE,这个前缀通常被用来比较两个串,或搜索某个特定字符(字、双字)。REPZ、REPE、REPNZ也是非常常用的指令前缀,分别代表ZF(Zero Flag)在不同状态时重复执行。