美文网首页学习笔记
X86学习笔记二 字符串修改

X86学习笔记二 字符串修改

作者: 闭门造折 | 来源:发表于2019-04-16 20:30 被阅读0次

    今天的任务是对字符串实现增、删、改、查等等操作

    假设数据空间总长度为M,已经占去部分为N。
    增操作有两种:
    1、在数据末尾添加新的数据段
    2、在某个字符串中间添加新的数据段。
    前者很简单,不存在覆盖问题。后者需要先移动后续内容,再将新内容覆盖进去。

    删操作也有两种:
    1、删除末尾字符串
    2、删除中间字符串
    后者存在无用空白问题,需要将后续内容依次前移

    改操作分为三种:
    1、新的字符串长度<旧的字符串长度
    2、新的字符串长度=旧的字符串长度
    3、新的字符串长度>旧的字符串长度
    第一类需要将后续内容前移,第三类需要提前将后续内容后移

    查操作比较简单,从开始到末尾顺序筛查即可,可以设计为报多个坐标,也可以设计为只报出现总数或头一个的位置

    首先是改操作,由于笔者很懒,所以并没有将后续内容依次前移,而是留下了一些内容渣渣。也没有考虑提前将内容后移,通过在readme中写明输入要求,降低了自己的工作量。
    主体的main函数

    STACK   SEGMENT PARA    STACK
            DW  100H DUP(?)        ;不需要栈空间顶部地址
    STACK   ENDS
                
    DATA    SEGMENT PARA
    STRING1 DB  '15061125 ZHAOZE',00H        ;随意的两个字符串变量
    STRING2 DB  'STRING BEFORE STRCPY',00H
    DATA    ENDS
    
    CODE    SEGMENT PARA
            ASSUME  CS:CODE, DS:DATA, SS:STACK, ES:DATA
    
    MAIN    PROC    FAR
            MOV     AX,DATA
            MOV     DS,AX
            MOV     ES,AX           ;ES用于STOSB操作
    
            CALL    DISP_STR        ;无参数调用,所以不用参数压栈
    
            MOV     DX,OFFSET STRING2
            PUSH    DX              ;第二个参数,字符串2的地址偏移
            MOV     DX,OFFSET STRING1
            PUSH    DX              ;第一个参数,字符串1的地址偏移
            CALL    FAR PTR STRCPY  ;调用修改函数
            CALL    DISP_STR        ;调用输出函数
    
            MOV     AX,4C00H        ;结束
            INT     21H
    

    输出函数就不贴代码了,仅贴修改函数的代码。由于已经降低了很多难度,所以逻辑看起来非常的简单

    STRCPY  PROC    FAR
            PUSH    BP        ;把此时的BP值压栈
            MOV     BP,SP     ;将SP的值传给BP:由于后续有栈操作
                              ;   SP的值可能改变,但是参数位置又是固定的
                              ;   所以用BP过渡
            PUSH    DI        ;函数中要用到临时寄存器DI,SI,将初值保留
            PUSH    SI
    
            MOV     SI,[BP+6]   ;BP=初始时SP位置。BP+6是第一个参数
            MOV     DI,[BP+8]   ;BP+8是第二个参数
            CLD                 ;时钟置1
    STRC:
            LODSB
            STOSB
            CMP     AL,0
            JNZ     STRC
            POP     SI         ;还原现场
            POP     DI
            POP     BP
            RET     4          ;栈空间还原,返回2N,N为参数个数
    STRCPY  ENDP
    

    这次的代码与上次相比,涉及到了两个新的知识点
    第一个是LODSB和STOSB,
    对应的修改在main函数中也有体现,MOV ES,AX。即将额外段也指向DATA
    LODSB = 从DS:[SI]地址处取一个字节,存入到AL中,并且SI++
    STOSB = 将AL中的内容,存到ES:[DI]所指向的那个字节,且DI++
    需要注意的是,ES:[DI],指的是以ES为基地址,偏移量为DI的位置,所以需要设置ES的初始值
    CLD表示的是时钟为1,每次SI和DI自增的值为1而不是2

    第二个是参数压栈。了解过栈知识,并实现过编译器的同学应该知道,参数压栈的时候应该逆序压栈,如此才能正序调用。

    堆栈 SP的值
    ...
    BP 2K-10
    跳转前IP地址 2K-8
    跳转前CS值(段内调用不需要存入) 2K-6
    参数1 2K-4
    参数2 2K-2
    ... 2K

    当我们执行压栈操作的时候,此时SP指向的是2K
    压入参数2,SP指向2K-2
    压入参数1,SP指向2K-4
    执行CALL指令,压入CS和IP,SP指向2K-8
    进入函数内部,压入BP,SP指向2K-10
    将此时SP的值赋给BP,BP=2K-10
    则BP+6 = 2K-4,取出参数1
    BP+8 = 2K-2,取出参数2
    RET时,除了自动释放的4个栈空间,还需要释放参数所占空间2N

    相关文章

      网友评论

        本文标题:X86学习笔记二 字符串修改

        本文链接:https://www.haomeiwen.com/subject/ahyfvftx.html