16位汇编第八讲指令第四讲

 

        16位汇编第八讲指令第四讲

一丶串操作类指令

1.什么是串操作?

  1.串操作指令是8086指令系统中比较独特的一类指令,采用比较特殊的数据串寻址方式,在操作主存连续区域 的数据是,特别好用.因而比较常用 简而言之,就是内存中的一段数据,拷贝/读取/修改... 到另一块另内存 重点掌握  MOVS  STOS  LODS CMPS SCAS REP

2.串操作的简介

  1.串操作指令的操作数,是驻村中连续存放的数据串(String 注意string表示串的意思)--也就是一段数据在内存中 是连续的,以字或者字节排列   2.串操作指令的操作对象是以字(Word)为单位的字串,或者字节(Byte)为单位的字节串--简单理解就是我要操作 1个字节大小,还是两个字节大小

3.串的操作

  串的操作一般使用 SI(源寄存器)和 DI(目的寄存器),可以使用端超越DS:[SI]   或者目的寄存器 DI  ES:[DI] 每次执行一次串操作,那么SI和DI则会自动修改,地址自增 当然地址自增是看方向标志的  DF  我们要想复制的时候,让其内存自增复制,那么就用CLD让方向初始为自增 否则 反向复制的话就用STD指令让地址自减

4.串操作指令中的串传送指令(MOVS)

作用:   把字节或者字操作数从内存的源地址,传送到目的地址 分别有两个指令,一个是字节串传送,一个是字传送 MOVSB (后缀b代表byte的意思)  MOVSW(后缀w代表字的意思) 指令:   MOVSB    ES:[DI] <- DS:[SI]  从si内存中取出一个字节的数据,复制到DI中     SI<-SI±1,DI<-DI±1  地址随着方向标志自增1或者自减1   MOVSW    ES:[DI] <- DS:[SI]  从si内存中取出一个字的数据,复制到DI中     SI<-SI±2,DI<-DI±2  地址随着方向标志自增2或者自减2  使用例子:    主要是两个花红框的地方,意思是什么,第一个画红框的内容 1.定义一个源地址,里面的内容是HELLO  也就是内存的内容是Hello 2.定义一个目标地址,里面的内容是申请了100个字节,然后初始化为零 第二个画红框的内容 1.首先给si设置偏移这里使用lea设置的, 我们也可以写成   mov si,offset g_szSrc,下面的目的也是一样 2.给目的设置偏移 3.使用movsb,从si内从中取出一个字节,设置到目的内存中 可以看出,方向标志位默认是往下自增的,我并没有使用CLD设置,所以SI 和DI复制完成后,内存就会自增  会C语言的请看这条注释 : 在C语言中,这个命令就相当于 memcpy(内存拷贝)每次拷贝几个字节,不懂汇编的滤过 当然我们可以使用 MOVSW 只不过一次拷贝两个字节了.具体的自己手工尝试.

 5.串操作指令中的串存储指令STOS(store string)

作用: 把AL或者AX数据传送到目的地址 C语言的请看: 在C语言中,这条命令相当于 memset,清空的作用 这个就简单了,把寄存器的数据,传送到目的寄存器中,也就是 ES:[DI]中 ES:[DI]<-AL/AX 对于这里我说一下ES 和DS 上面我们使用的时候,并没有使用段超越指令,为什么,因为我们的DI 和SI都是数据区了, 也就是说不用使用段超越了,否则你需要自己加,一般来说,ES和DS两个段都是合并到一起的 STOSB,STOSW 分别对应两条指令     STOSB 字节串存储  ES[DI]<-AL,把AL的数据,放到DI中         按照方向标志,DI<-DI±1  自增或者自减1     STOSW 字串存储: ES:[DI]<-Ax ,把AX中的数据,放到DI中       按照方向标志,DI<-DI±2  自增或者自减2 使用例子,字节串存储      第一框,代码是给al一个3,然后通过段存储的命令,把3给DI存储 反汇编单步调试,已经完成一个字节保存了,现在看下DI 06的偏移处是不是3 是3,完成了操作 STOSW 则是把AX中的数据,放到DI中,放两个字节,也就是一个字,因为AX是16位寄存器. 具体自己测试即可.

6.串操作指令,串读取LODS(load string)

作用:    把指定的主存单元的数据传送给AL,或者AX 看到这里已经明白了吧,上面的是吧AL,或者AX中的内容存储到DI中,这个则是读取到DI中,唯一不同的则是从源寄存器中读取(也就是SI) LODSB  字节串读取  AL<-DS:[SI]  按照方向标志,自增或者自减1  SI<-SI±1 LODSW 字读取         AX<-DS:[SI]  按照方向标志,自增或者自减2  SI<-SI±2 使用例子:    现在可以看到AX中的值是0b46,而SI中的偏移加上段地址所在的物理地址是hello 我们使用了 字读取,也就是读取两个字节,也就是说AX中的值会变为  he 这两个字符的ASCII码 具体的字节读取,自己测试便知道了

 7.串操作命令,串比较CMPS(compare string)

作用:   讲主存中的源操作数减去目的操作数,然后设置标志位,进位比较两个操作数之间的关系 简而言之:   意思就是  源内存中的数(可以理解为数,也可能是字符串的ASCII码) 减去 目的内存中的数,根据结果设置标志位 比如  源内存 的数字是  1  目的内存中  也是1  那么 1 -1 就为0,0是结果,根据结果设置一下标志位  则ZF = 1,也就是源和目的相等 C语言的请看:  相当于memcmp(内存比较) 不懂C语言的滤过 也有两个比较,分别是字比较,还有字节比较 字节比较:  CMPSB  DS:[SI]-ES:[DI]     根据方向的标志自增或者自减1  SI<-SI±1,DI<-DI±1 字比较:      CMPSB  DS:[SI]-ES:[DI]     根据方向的标志自增或者自减2 SI<-SI±2,DI<-DI±2 使用例子,字节比较    看下反汇编代码,然后看下标志位 结果相当,则ZF位为1,如果hello 五个字节都要比较,则来五次即可. (下面还有重复前缀指令,暂时是来五次) 具体的字比较,自己测试便知道  

8.串操作指令,串扫描SCAS(Scan String)

作用:   将AL/AX减去目的操作数,以便设置标志,进位比较AL/AX与操作数的关系 简而言之:   就是你要搜索的字节,放到AL,或者AX中,然后会和DI去比较,然后根据结果设置标志 C语言的请看: 在C语言中,这个相当于 memchr命令 SCASB       AL-ES:[DI]  根据方向标志自增或者自减1  DI<-±1 SCASW      AX-ES:[DI]  根据方向标志自增或者自减2  DI<-±2 使用例子: 现在是68 - 去内存中DI中的值,也是68   设置标志位,AL中寄存器的值减去DI中的值,根据结果设置标志位,因为68-68结果就是0,所以对应的零标志位置位了 有可能68-69,就是负数了,所以CF位会置位  

 二丶重复前缀指令(repeat)

1.什么是重复前缀指令?   简单理解为就是为串操作单独提供的循环指令,比如我们上面要用MOVS串操作指令的时候,把源寄存器中的值,拷贝到目的寄存器中,假设我们有个HELLO 我们要使用五次 MOVSB命令才能拷贝过去 现在提供了一个为串操作的循环 重复前缀分为两类,3条指令 1.配合使用,MOVS,STOS,LODS的时候,使用指令REP前缀,不影响标志 2.配合使用 CMPS,SCAS,指令,使用REPZ和REPNZ前缀 然后重复次数放到cx寄存器中 例如   
mov cx,3 rep movsb
代表我要重复三次,movsb的指令,注意,根据方向标志,每次自增或者自减1,因为你使用的movsb REP指令的作用就是 当CX ≠ 0的时候,继续传送

REPZ,和REPNZ解析

REPZ:   1.每次执行串指令,则CX-1   2.判断零标志位(ZF)是否为零 (也就是不想等)   3.如果CX == 0,或者 ZF == 0 (不想等)则重复执行结束 注意可以简单理解为,    cx !=0 并且  zf == 1 的时候继续循环 REPNZ:        1.每次执行串指令,则CX-1   2.判断零标志位(ZF)是否为1 (也就是想等)   3.如果CX == 0,或者 ZF ==1 (想等)则重复执行结束  REPNZ/REPNE的前缀,可以简单理解为   cx != 0  && zf ==0 的时候继续 使用就很简单了,上次我们要拷贝的时候必须给五次,这次直接给CX一个值,然后利用前缀指令即可.  

 三丶控制转移指令

控制转移指令,用于实现分支,循环,过程等程序的接口,是仅次于传送指令的常用指令 一般来说控制转移指令都是修改IP的偏移或者CS段寄存器的值,让代码跳转(坏处: 断CPU的流水线)实现 程序的执行顺序的改变

①丶无条件转移指令

  无条件转移指令,就是说你给一个偏移,可以无条件的跳转到其地放执行 JMP指令(无条件转移指令) JMP指令有2个种类,4个类型 1.段内转移 2.段间转移   段内转移:     段内转移,就是在一个段中的跳转 又分为短转移,和近转移 短转移(short): 短转移就是一次只能跳一个字节的大小,也就是 ±127 近转移(near): 近转移则是能跳转 -32767 -> 327678大小 例子:   
JMP SHORT 地址/标号
跳转到地址或者标号的地方 近转移 对于近转移来说,机器码是一个字节,E9是操作码,而0100则是偏移,就是说你跳转的偏移的大小是多少 段间转移    段间转移,则是去另一个段去跳转
JMP FAR PTR 地址,标号
例子:    对于段间转移,则是 段地址:偏移 的形式去转移的,CS的值会修改为段地址,IP会修改为偏移 注意二进制机器码,也是这样的,这个可以自己修改的,因为让代码JMP到自己的代码,然后在JMP回去,就实现了HOOK指令 JMP有两种寻址指令 直接寻址方式  
JMP AX
地址放在寄存器当中 间接寻址方式   
JMP word ptr [BX] ;需要指明一下
总结 短转移:  使用 short 关键字 例如  jmp short 标号/地址偏移 近转移: 使用  near ptr  例如 jmp near ptr 标号/地址偏移 远转移:  使用 far ptr    例如 jmp  far ptr 标号/地址偏移 然后近转移和短转移,可以直接使用jmp,在编译器中,会自动选择相应的方式去转移

四丶条件转移

 上面说的都是强制转移,现在我们需要使用条件转移指令,比如根据标志位去转移 JCC  (JCC是一个比喻,并没有这条命令,可以吧CC看做任何条件) JCC  标号 CC条件成立则跳转到标号,否则程序继续顺序执行下一条指令 操作数标号,使用短转移,成为相对寻址方式 其中CC是一张表组成 看到这张表很难记,有个小窍门 1.  z  zero(零的意思)/E  (equal)   如果为z则是位零的意思,为e则是相等的意思 比如   jz/je  等于零,或者相等,其中判断的是ZF位 N表示取反的意思 比如   JS  SF = 1 表示符号为负   JNS 不看也知道SF = 0 符号位正 其中每个标志位都有一个  判断是否相等或者不想等 比如 CF位   jC  那么代表CF =1 jNC 那么表示CF = 0 对于上面还不够,因为我们还要判断是否 大于,小于 高于,低于 (高于,低于 是用于无符号的判断,大于小于则是用于符号的判断) G  有符号的 大于判断 L   有符号的小于判断 A  无符号的高于判断 B 无符号的低于判断 比如,我要判断CF位小于0   JB 如果是CF大于零,则  JNB (不低于) JAE (A是高于  高于等于)  作业以及资料下载链接: 链接:http://pan.baidu.com/s/1boQijU3 密码:nr3a
posted @ 2017-09-05 23:23 iBinary 阅读(...) 评论(...) 编辑 收藏