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寄存器中
例如
代码语言:javascript复制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大小
例子:
代码语言:javascript复制JMP SHORT 地址/标号
跳转到地址或者标号的地方
近转移
对于近转移来说,机器码是一个字节,E9是操作码,而0100则是偏移,就是说你跳转的偏移的大小是多少
段间转移
段间转移,则是去另一个段去跳转
代码语言:javascript复制JMP FAR PTR 地址,标号
例子:
对于段间转移,则是 段地址:偏移 的形式去转移的,CS的值会修改为段地址,IP会修改为偏移
注意二进制机器码,也是这样的,这个可以自己修改的,因为让代码JMP到自己的代码,然后在JMP回去,就实现了HOOK指令
JMP有两种寻址指令
直接寻址方式
代码语言:javascript复制JMP AX
地址放在寄存器当中
间接寻址方式
代码语言:javascript复制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