博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

汇编中的String

Posted on 2011-03-29 17:04  天地玄黄  阅读(4974)  评论(0编辑  收藏  举报

这只是一个学习笔记,难免会有些杂乱,记录的都是一些汇编中有关String的要点。

 

1、在汇编语言看来,只要是在内存中连续的存储单元(byte)中存储的东西都叫做“String”,而不管这些东西是不是人可以识别的字符。

2、汇编语言的String是你通过在R额Register中设定相应的值来指定的。比如在EAX中指定String的首地址,在ECX中指定String的长度。

3、String分为Source String和Destination String。Source String就是你读入的String,Destination String就是你要写入的String。它们的区别仅是寄存器的不同

     · Source String使用ESIExtend Source Index作为地址寄存器,使用ECX表示它的长度。

     · Destination String使用EDIExtend Destination Index指向它的地址,同样使用ECX表示它的长度。

     · Data coming from a source string or going to a destination string must begin the trip from, end the trip at, or pass through register EAX.

 

4、STOSB

     这个指令是STOre String by Byte的助记法。它的功能是把某个byte书写到Destination String中多少次。

     它使用以下几个寄存器:

       · EDI 必须指向Destination String。

       · ECX 中存放需要写入的次数。需要写入的东西在AL中。

       · AL 中存放想要在String中存放的数值。

     这时候,如果执行STOSB指令,将会执行下面的两个操作:

       · AL 中存放的一个byte的值被放到EDI所指向的内存中;

       · EDI 加1,这样它就指向了下一个可以写入的单元(byte)。

     这时的ECX(其中存放着“次数”)不会自动减1,需要你自己来设定(使用DEC和LOOP),或者使用下面的命令:

rep stosb

     REP是一个指令前缀,表明CPU应该以什么样的态度对待它之后那个指令(这里是STOSB)

     在这个指令中,还有一个非常重要的地方,就是DF标记位(Direction Flag)。当DF为1时,对于内存的访问是从大到小的(地址),如果DF为0,那么就从小到大。一般都是从小到大。

     有两个指令可以设定DF的值,一个是CLD,一个是STD。前者把DF设为0,后者把DF设为1。即前者为从小到大查找(STOSB中的EDI每次增加1),后者从大到下查找(STOSB中的EDI每次减1)。POPF也会影响DF的值。

     还有几个与STOS相关的指令:

       · STOSB:STOre String by Byte,存储8-bits的数据(AL),EDI每次移动1个byte(根据DF确定方向)

       · STOSW:STOre String by Word,存储16-bits的数据(AX),EDI每次移动2个byte(根据DF确定方向)

       · STOSD:STOre String by Double,存储32-bits的数据(EAX),EDI每次移动4个byte(根据DF确定方向)

     在它们之前使用 REP,全都是对ECX减1。

 

5、LOOP

     如果仅仅使用STOSB指令,那么仅能进行一次写入操作。需要一个循环,同时减少ECX的值,才能不断写入。这可以用两个指令实现:

DoChar: stosb          ; Note that there’s no REP prefix!

        add al,'1'     ; Bump the character value in AL up by 1
        aaa            ; Adjust AX to make this a BCD addition
        add al,'0'     ; Basically, put binary 3 in AL’s high nybble

        dec ecx        ; Decrement the count by 1..
        jnz DoChar     ; ..and loop again if ECX > 0

     最后的这两个指令也可以用一个指令代替,即LOOP:它首先把ECX减1,然后检查ZF标记位,看是否跳转。当ECX不为0时,跳转,否则就不跳转

DoChar: stosb           ; Note that there’s no REP prefix!
        add al,'1'      ; Bump the character value in AL up by 1
        aaa             ; Adjust AX to make this a BCD addition
        add al,'0'      ; Make sure we have binary 3 in AL’s high nybble
        loop DoChar     ; Go back & do another char until ECX goes to 0


6、MOVSB

     MOVS也有三种形式,都是把数据从 ESI 所指向的内存拷贝到 EDI 所指向的内存,拷贝的次数为 ECX ,根据 DF(Direction Flas) 来确定方向:

       · MOVSB:MOVe String by Byte,每次操作8-bits(1个byte)的数据,每拷贝1个byte的数据ECX减一

       · MOVSW:MOVe String by Word,每次操作16-bits(2个byte)的数据,每拷贝2个byte的数据ECX减一

       · MOVSD:MOVe String by Double,每次操作32-bits(4个byte)的数据,每拷贝4个byte的数据ECX减一

     在这些指令之前使用 REP ,可以把它们变成全自动机关枪,一直执行到 ECX 变成0。

 

7、SCASB

     这个指令和上面两个指令的用法基本相似。它表示SCAn String by Byte,用来搜索字符串。

     它设定以下几个寄存器:

       · DF 设定为0或1,表明搜索的方向是uphill还是downhill。

       · EDI 中存放需要搜索的字符串的地址。我感觉这里有些诡异,为什么不放在ESI中呢?

       · AL 需要查找的东西放在AL中。

       · ECX 最大查找的次数放在ECX中。

     这里使用 REPNE SCASB 进行自动搜索。在搜索过程中,[EDI] 所指向的byte每次都和 AL 中的值进行比较,如果相等,则停止查找。如果不相等,那么 EDI 加1, ECX 减1,继续尝试下一个[EDI]。当搜索找到所要的值的时候,EDI 指向所要查找的 byte 的下一个 byte。它要停下来有两种情况,一是找到AL中的值,一是ECX为0。

     这里的 REPNE 的意思是:Repeat SCASB as long as [EDI] does not equal AL.

     如果使用 REPE 作为前缀:Repeat SCASB as long as [EDI] equals AL.

     SCASB 会设定ZF的值,如果[EDI] 和 AL中的值相同(为0),那么ZF为1,表明找到AL中的值;如果不同(不为0),那么ZF为0,表明没有找到AL中的值。

      · 这样,当使用REPNE时,ZF为1时停下。当使用REPE时,ZF为0时停下。

      · 判断是否是ECX用完时(即找不到和AL相同的值,或全是和AL相同的值),REPNE 用 JNZ,REPE 用 JZ。