汇编语言学习笔记--串操作篇(c++的string???)

一、基本

1.两个寄存器

其实感觉和之前学的差不多,只是把之前的目的操作数源操作数给具体化到了两个寄存器之上,之后的所有的指令操作都是对这两个寄存器进行。当然,因此,串也有自己的独特指令操作。

ESI:源索引寄存器,访问源串中的元素
EDI:目的索引寄存器,访问目的串的元素

movs:串传送
cmps:串比较
scas:串扫描
stos:存入串
lods:从串取

ptr
在这里插入图片描述

2.问题来了什么是串??

这里和C++的string类来进行类比,在C++中,对string的操作实际上也是把其当作数组操作,对每一个最小元素进行一系列操作。既然如此,我们前面学了那么多汇编的基础,是不是也是这样的?答案肯定是Yes,不然我也不会进行类比。汇编中的串,实际上只是表面上和数组不同,实际上它们是相同的。而在之前的学习中,我们都明白了数组的寻值找数,这些在串中也同样适用,不过它是由自己独特的命令而已。

3.串指令

和数组一样,如果要找到串,则首先必须要找到它的地址(不然连人家的家在哪儿都不知道,你怎么开始下一步?)在数组中,使用的是lea,来将数组的首地址拿到,而在串中,也一样,不过重新分配了两个寄存器特地用来寻址。
因此,在这里有了

第一个不同点:串指令是没有操作数的孤家寡人(默认调用:ESIEDI),但是这也导致一个问题:操作数都没有,我怎么知道你是字节,字,还是双字?
解决

  • 第一种方法:通过目的操作数和源操作数明确(使用上面的ptr)
  • 第二种方法:使用特殊的助记符号来定义长度:字节操作串使用‘b’后缀,字长指令使用’w’,双字使用‘d’
movsb:字节长度
movsw:字串长度
movsd:双子长度

第二个不同点:数字是通过mov ebx,4对地址直接操作来进行选择数值。而在串之中,则是通过ESI和EDI自动选择:

串指令是每次只处理一个串元素,但是此时的两个寄存器其实已经对下一个元素的操作做好了准备(它们指向下一个元素的地址)!!

这也就是说明:串指令先是从当前的寄存器里面取出值,在这之后,两个寄存器分别写入各自的下一个元素的地址。

如果是字节长,则加(减)1,字长则操作2个单位,双字长则是4个单位。

同时,其进行的方向(向前选择还是向后)也是和数组不同。在串中,是通过一个方向标志DF进行决定。

DF为0,使递增,从左到右处理串
DF为1,使递减,从右向左处理串

修改DF的两条指令:

  • cld:清0
  • std:设1

(1)movs

movs将一个串的元素从源串传送到目的串,复制完成后,两个索引的寄存器的值根据每个元素的长度而改变,同时由DF决定移动方向。

  • movsb:移动字节长
  • movsw:移动字长
  • movsd:移动双字长
例题

在这里插入图片描述
在这里插入图片描述
流程解释

  1. **[esi]**表明是寄存器间接寻址,也就是通过其获取源串的当前字符。
  2. MASM需要操作符BYTE PTR来去顶目的地址是字节,而不是其他的类型。
  3. movsb实现复制源串的字节,并且两个索引寄存器的值递增
  4. mov BYTE PTR [edi],0在目的串的末尾加上一个空字节,因为在源串的最后一个字节复制到目的串后,EDI的值已经递增了。

(2)重复前缀(rep)

如果按照以上说的,每次执行一个字符,那么想要复制100个字节长的串,还必须写一个循环过程,这就将问题复杂了。因此,80x86的体系结构中还有三种重复前缀。这样,串指令就可以按照给定的字数自动重复执行,或者知道满足某种条件为止。
注意:重复前缀实际上等同于两种不同的单字节编码,它们本身不是指令,而是扩展原有字符串指令的机器代码,生成的新指令。

rep:循环ecx次
repe(repz):相同就循环(为0就循环)
repne(repnz):不相同就循环(不为0就循环)

在这里插入图片描述

在这里插入图片描述在这里插入图片描述
根据上面两个做个比较:按照老办法使用loop实际上比下面的rep movsb多了几条语句。

rep系列的使用
  • movs系列联动
    连续循环移动

在这里插入图片描述

  • cmps系列联动
    连续循环比较
    在这里插入图片描述

(3)scas

scas用来在串中扫描某个特定的传元素是否在串中存在。被扫描的串元素地址放在目的索引寄存器EDI中。

  • 用scasb,需要查找的串元素以字节存放在AL
  • 用scasw,需要查找的串元素以存放在AX
  • 用scasd,需要查找的传元素以双字存放在EAX

在这里插入图片描述
例题
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
要点: 在查找之后,无论标志位是否为1,串指令总是会增加索引寄存器的值,所以,目的索引寄存器EDI的值会比预期的值大。如果查找成功,EDI则会包含与AL相匹配的字符后的下一个字符的地址,如果没找到,则指向串结束后的字符的地址。所以,使用dec edi则可以进行修正,使edi回退到正确的位置。

(4) stos

保存串指令stos将AL,AX,EAX中的一个字符复制为目的串的某个元素。(可以与rep联动,将同样的值复制到目的串中)
在这里插入图片描述

(5)lods

从串中取指令。按照指令给的串元素长度,复制源串中的元素到对应的寄存器中。

例题

source BYTE "brown"
dest BYTE "brine"
1.
lea esi,source
lea edi,dest
cld
mov ecx,5
repne cmpsb

ESI初始值为00010000
EDI初始值为00010005
则执行以上指令之后,ESI,EDI,ECX分别为多少?(00010001,00010006,4)

2.
lea esi,source
lea edi,dest
cld
mov ecx,5
repe cmpsb

ESI初始值为00010000
EDI初始值为00010005
则执行以上指令之后,ESI,EDI,ECX分别为多少?(00010003,00010008,2)

3.
mov al,'w'
lea edi,dest
cld
mov ecx,5
repe scasb

EDI初始值为00010005
则执行以上指令之后,EDI,ECX分别为多少?(0001000A,0)

4.
mov al,'n'
lea edi,dest
cld
mov ecx,5
repne scasb

EDI初始值为00010005
则执行以上指令之后,EDI,ECX分别为多少?(00010009,1)

5.
mov al,'*'
lea edi,dest
cld
mov ecx,5
rep stosb

EDI初始值为00010005
则执行以上指令之后,EDI,ECX分别为多少?(0001000A(*****),0)

6.
lea esi,source
lea edi,dest
cld
mov ecx,5 

for6:
lodsb
inc al
stosb
loop for6
endFor6:

ESI初始值为00010000
EDI初始值为00010005
则执行以上指令之后,ESI,EDI,ECX分别为多少?(00010005,0001000A,0,‘cspxo’)

7.
lea esi,source
lea edi,dest
cld
mov ecx,3 
rep movsb

ESI初始值为00010000
EDI初始值为00010005
则执行以上指令之后,ESI,EDI,ECX分别为多少?(00010003,0001000A,0,‘brone’)

8.
lea esi,source+4
lea edi,dest+4
std
mov ecx,3 
rep movsb

ESI初始值为00010000
EDI初始值为00010005
则执行以上指令之后,ESI,EDI,ECX分别为多少?(00010004,0001000A,0,‘browe’)

作业

题目:
有长度为字的串shuzu,现在要把其中的正数存入名为zheng的串中,负数存入名为fu的串中。

;Program: 正负分类
;Author: 龙文汉
;Date: 2020.12.9

.386
.MODEL FLAT

ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

INCLUDE io.h            ; header file for input/output

cr      EQU     0dh     ; carriage return character
Lf      EQU     0ah     ; line feed

.STACK  4096            ; reserve 4096-byte stack

.DATA                   ; reserve storage for data
prompt1 BYTE "Please input the string:",cr,Lf,0;
prompt2 BYTE "The count of even number:",cr,Lf,0;
str1 BYTE "The length of str:",cr,Lf,0;
str5 BYTE "The String:",cr,Lf,0;
str2 BYTE "Zhenshu :",cr,Lf,0;
str3 BYTE "Fushu :",cr,Lf,0;
HH BYTE cr,Lf,0;


string WORD 100 DUP(?);
fu WORD 100 DUP(?);
zh WORD 100 DUP(?);
temp WORD 100 DUP(?);

.CODE                           ; start of main program code
strlen PROC NEAR32
    push ebp;
    mov ebp,esp;
    pushf;
    push eax;
    push ebx;
    sub eax,eax
    mov ebx,[ebp+8];
WhileChar:
    cmp BYTE PTR [ebx],0;
    je endWhileChar;
    inc eax;length + 1
    inc ebx;next char
    jmp WhileChar
endWhileChar:
    mov edx,eax;
    pop ebx;
    pop eax;
    popf;
    pop ebp;
    ret 4;release old eax
strlen ENDP;

PrintStr PROC NEAR32
    push ebp;
    mov ebp,esp;
    push ebx;
    mov ebx,[ebp+8]
WhileChar:
    cmp WORD PTR [ebx],0;
    je endWhileChar;
    itoa temp,[ebx];
    output temp;
    add ebx,2;
    jmp WhileChar;
endWhileChar:
    output HH;
    pop ebx;
    pop ebp;
    ret
PrintStr ENDP;

CreateStr PROC NEAR32
    push eax;
    push ebx;
    push ecx;
;输入字符串长度
    output str1;
    input temp,100;
    atod temp;
    mov ecx,eax;
    output str5;
    lea ebx,string;
;创建字符串
    Dowhile:
        input temp,100;
        atoi temp;
        mov [ebx],ax;
        add ebx,2;
        loop Dowhile;
    pop ecx;
    pop ebx;
    pop eax;
    ret
CreateStr ENDP;

JuageZF PROC NEAR32
    lea eax,string;
    lea ebx,zh;
    lea ecx,fu;

WhileBegin:
    cmp WORD PTR [eax],0;

    je Endwhile;

    mov dx,[eax];
    jl Less
    mov [ebx],dx;

    add ebx,2;



    add eax,2;
    jmp WhileBegin

    Less:
        mov [ecx],dx;
        add ecx,2;
        add eax,2;
        jmp WhileBegin;
Endwhile:
    ret;
JuageZF ENDP;

_start:
    call CreateStr

    lea eax,string
    push eax;
    call strlen;
    pop eax;

    lea eax,string
    push eax;
    call PrintStr;
    pop eax;

    call JuageZF;

    output str2;
    lea eax,zh
    push eax;
    call PrintStr;

    output str3;
    lea eax,fu
    push eax;
    call PrintStr;




        INVOKE  ExitProcess, 0  ; exit with return code 0
PUBLIC _start                   ; make entry point public

END                             ; end of source code


  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hanzoe_lwh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值