汇编语言---字符串操作指令(之gcc内联汇编应用)

目录

一、加载字符串数据指令(Load String Instruction)

二、存储字符串数据指令(Store String Instruction)

三、字符串传送指令(Move String Instruction)

四、输入字符串指令(Input String Instruction)

五、字符串输出指令(Output String Instruction)

六、字符串比较指令(Compare String Instruction)

七、字符串扫描指令(Scan String Instruction)

八、重复字符串操作指令(Repeat String Instruction)

1.重复前缀指令REP

2.条件重复前缀指令(Repeat String Conditionally)


      

        字符串操作指令的实质是对一片连续的存储单元进行处理,这片连续的存储单元由隐含指针DS:SIES:DI来指定;字符串操作指令可对内存单元按照字节、字、双字进行处理,并能根据操作对象的字节数使变址寄存器SI/DI增加或减少1、2、4字节;
规定如下:

当DF=0时,变址寄存器SI/DI增加1、2、4字节;即:变址寄存器SI/DI递增的步长可以是1、2、4字节;
当DF=1时,变址寄存器SI/DI减少1、2、4字节;即:变址寄存器SI/DI递减的步长可以是1、2、4字节;

一、加载字符串数据指令(Load String Instruction)

        从指针DI:SI所指定的内存单元开始,取一个字节/字/双字,然后存入到AL/AX/EAX中,并根据标志位DF的值对寄存器SI做相应的增减;把存放字符串数据的连续存储区当做是数据源,使用寄存器SI;
        该指令的执行不会影响任何标志位;

指令格式: LODS  地址表达式
        LODSB/LODSW 地址表达式
        LODS        地址表达式 ;80386+    
  

       在指令LODS中,它会根据"地址表达式"的属性来决定读取一个字节、字或双字;即:当该地址表达式的属性为字节、字或双字时,将从指针DI:SI处读取一个字节到AL中,或读取一个字到AX中,或读取一个双字到EAX中,与此同时,SI还将分别增减1、2、4字节;

二、存储字符串数据指令(Store String Instruction)

        该指令把寄存器AL/AX/EAX中的值存入指针ES:DI所指向内存单元开始的一片存储单元中,并根据标志位DF的值对寄存器DI做相应的增减;把存放字符串的连续存储区当做是数据的目的地,使用寄存器DI;
        该指令的执行并不会影响任何标志位;

指令格式: STOS 地址表达式
        STOSB/STOSW 地址表达式
        STOSD       地址表达式;80386+

例:gcc内联实现memset,在ubuntu16.04 gcc 5.4.0验证通过

void *memset_asm(void *dst, char c, size_t size)
{
        asm volatile(
                "cld\n\t"        /*清除DF标志*/
                "rep\n\t"
                "stosb\n\t"   /*al/ax/eax->ES:DI*/
                ::"a"(c),"D"(dst),"c"(size) /*"D":约束DI*/
                :"memory","cc");
        return dst;
}

三、字符串传送指令(Move String Instruction)

        该指令把指针DS:SI所指向的字节、字或双字传送给指针ES:DI所指向的内存单元,并根据标志位DF的值对寄存器DI和SI分别作相应的增减;
        该指令的执行并不会影响任何标志位;

指令格式: MOVS  地址表达式1,地址表达式2
        MOVSB/MOVSW 地址表达式1,地址表达式2
        MOVSD       地址表达式1,地址表达式2  ;80386+

例:gcc内联实现memcpy,在ubuntu16.04 gcc 5.4.0验证通过

void *memcpy_asm(void *dst, const void *src, size_t size)
{
        /*movs:把指针DS:SI所指向的数据传送给指针ES:DI所指向的内存单元*/
        asm volatile(
                "shr $2, %2\n\t"
                "cld\n\t"
                "rep  movsl\n\t"
                "mov %3, %%ecx\n\t"
                "and $3, %%ecx\n\t"
                "rep  movsb\n\t"
                /*输出参数*/
                :
                /*输入参数:DS段(S:ESI) ES段(D:EDI) c:ecx m:内存变量*/
                :"D"(dst),"S"(src),"c"(size), "m"(size)
                /*cc:使用的指令会改变CPU的条件寄存器*/
                :"memory","cc");
        return dst;
}


void *memcpy_asm(void *dst, const void *src, size_t n)
{
        int d0=0, d1=0, d2=0;
        asm volatile(
                "shr $2, %0        \n\t"
                "rep ; movsl    \n\t"
                "movl %4,%%ecx    \n\t"
                "andl $3,%%ecx    \n\t"
                "jz 1f            \n\t"
                "rep ; movsb    \n\t"
                "1:"
                /*分别表示第零个操作数(%0)–到第二个(%2)操作数*/
                : "=&c"(d0),"=&D"(d1),"=&S"(d2)
                /*分别表示第三个操作数(%3)到第六个操作数(%6);其中%3个=第%0个;%5==%1;%6==%2*/
                : "0"(n),"g"(n),"1"((long)dst),"2"((long)src)
                :"memory");
        return dst;
}

四、输入字符串指令(Input String Instruction)

        该指令是从某一指定端口接受一个字符串,并存入到一片连续的存储单元中;输入端口由寄存器DX指定,存储单元的首地址由指针ES:DI来确定,读入的数据个数由寄存器CX来确定;在指令的执行过程中,还要根据标志位DF的值来对寄存器DI做相应的增减;把存放字符串的连续存储区当做是数据的目的地;
        该指令不会影响任何标志位;
与指令有关的操作数ES、DI、DX和CX等都是隐含操作数;

指令格式: INS  地址表达式
        INSB/INSW  地址表达式
        INSD             地址表达式 ;80386+

五、字符串输出指令(Output String Instruction)

        该指令是把一个给定的字符串输出到一个指定的端口中;输出端口由通用寄存器DX指定,输出数据的首地址由指针DS:SI确定,输出数据的个数由计数寄存器CX来确定;在指令执行的过程中,还要根据方向标志DF的值来对变址寄存器SI做相应的增减;
        该指令的执行并不会影响任何标志位;
与指令有关的操作数DS、SI、DX和CX等都是隐含操作数;

指令格式: OUTS        地址表达式
        OUTSB/OUTSW  地址表达式
        OUTSD       地址表达式 ;80386+

六、字符串比较指令(Compare String Instruction)

        该指令是把指针DS:SI所指向的字节、字、双字的值与指针ES:DI所指向的字节、字、双字的值相减,并用所得到的差来设置相关标志位;与此同时,变址寄存器SI和DI也将根据方向标志位DF的值做相应的增减;

指令格式: CMPS        地址表达式1,地址表达式2
        CMPSB/CMPSW 地址表达式1,地址表达式2
        CMPSD       地址表达式1,地址表达式2 ;80386+
        受影响的标志位: AF,CF,OF,PF,SF,ZF

例:gcc内联实现memcmp,在ubuntu16.04 gcc 5.4.0验证通过

int memcmp_asm(void *dest, const void *src, size_t size)
{
        register int result = 0;
        asm volatile(
                 "cld               \n\t"
                "repe cmpsb \n\t"   ;
不停地比较直到ecx寄存器为0或不相等
                "je  1f             \n\t"   ;两块内存相等,跳出,返回0.
                "sbb %0,%0   \n\t"  ;sbb是x86的减法指令,会额外地减去CF(借位)的值,这样%0就会是0或者-1
                "or $1,%0       \n\t"  ;把立即数1或到%0上,这样%0就会是1或者-1.
                "1:"
                :"=&a"(result)         ;
传入变量result 放入寄存器ax,且这个变量是输出值(=),不要与其它输入输出共用寄存器(&)
                :"0"(result),"S"(dest),"D"(src), "c"(size), "m"(size)
                :"cc");      //clobber list 告诉gcc在这段内联汇编中哪些寄存器被显式/隐式修改
        return result;

七、字符串扫描指令(Scan String Instruction)

        该指令是用指针ES:DI所指向字节/字/双字的值与相应的AL/AX/EAX的值相减,并依据所得到的差值来设置相关标志位;与此同时,变址寄存器DI还将根据方向标志DF的值来做相应的增减;

指令格式: SCAS        地址表达式
        SCASB/SCASW 地址表达式
        SCASD       地址表达式 ;80386+
        受影响的标志位: AF,CF,OF,PF,SF,ZF

八、重复字符串操作指令(Repeat String Instruction)

1.重复前缀指令REP

重复前缀指令是重复其后指定的字符串操作指令,重复的次数由计数寄存器CX来决定;
指令格式:

REP LODS/LODSB/LODSW/LODSD
REP STOS/STOSB/STOSW/STOSD
REP MOVS/MOVSB/MOVSW/MOVSD
REP INS/INSB/INSW/INSD
REP OUTS/OUTSB/OUTSW/OUTSD

重复前缀指令的执行步骤如下:
STEP1:判断: CX=0
STEP2:如果CX=0,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响相关标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行完后,再转到步骤STEP1;
从上面的重复前缀指令格式来看,虽然我们可以使用重复前缀指令来重复取字符串数据指令(LODS),但是可能会因为指令的执行结果而在程序中几乎不会使用;

2.条件重复前缀指令(Repeat String Conditionally)

        条件重复前缀指令与重复前缀指令的功能相似,所不同的是:条件重复前缀指令中的重复次数不仅由CX来决定,而且还会由标志位ZF的值来决定;根据ZF所起的作用又可分为两种:相等重复前缀指令和不等重复前缀指令;
        相等重复前缀指令:

指令格式:
REPE/REPZ SCAS/SCASB/SCASW/SCASD
REPE/REPZ CMPS/CMPSB/CMPSW/CMPSD

该重复前缀指令的执行步骤如下:
STEP1:判断条件: CX!=0 且 ZF=1
STEP2:如果条件不成立,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响任何标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行后,再转到步骤STEP1;

        不等重复前缀指令:

指令格式:
REPNE/REPNZ SCAS/SCASB/SCASW/SCASD
REPNE/REPNZ CMPS/CMPSB/CMPSW/CMPSD

该重复前缀指令的执行步骤如下:
STEP1:判断条件:CX!=0 且 ZF=0
STEP2:如果条件不成立,则结束重复操作,执行程序中的下一条指令;
STEP3:否则,CX=CX-1(不影响任何标志位),并执行重复前缀指令后面指定的字符串操作指令,在该指令执行完后,再转到步骤STEP1;

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MSL 即 Microsoft Library 是 DOS 版的 "WinHelp",也就是现代版 Help Viewer 的始祖。 安装目录下有个 ini 文件,用来指定图书的路径,它即是目录。 文件来源自 http://wdl2.winworldpc.com/Abandonware%20SDKs/Microsoft Programmer's Library 1.3.7z Microsoft Programmer's Library 1.3.iso 这就是 DOS 版的 MSDN!使用 DOSBOX 就可以运行此库。此库含一大古董级MS官方编程参考材料,主要针对 Windows 3.0 平台,真可谓之应用尽有: MS Windows 3.0 SDK Guide to Programming MS Windows 3.0 SDK Install. & Update Guide MS Windows 3.0 SDK Programmer's Reference Vol. 1 MS Windows 3.0 SDK Programmer's Reference Vol. 2 MS Windows 3.0 SDK Tools MS Windows 3.0 SDK Articles All MS Windows 3.0 SDK Manuals MS Windows 3.0 DDK Install. & Update Guide MS Windows 3.0 DDK Adaptation Guide MS Windows 3.0 DDK Virtual Device Adapt. Guide MS Windows 3.0 DDK Printer & Font Kit All MS Windows 3.0 DDK Manuals MS Online User's Guide Programming MS Windows MS Windows Sample Code MS KnowledgeBase - MS Windows 以及 Options => Library 菜单下提供的 9 个重要的参考资料,其就有 C 和 MASM 这些重要的参考资料。这些是已安装的目录部分,鉴于 MASM 的重要性,特将其添加到压缩包内,免CD运行: Windows References OS/S References Network References MS-DOS References MS Systems Journal Hardware References C References MASM References BASIC References Pascal References FORTUAN References 其 C References 和 MASM References 包含: Installing and Using MS MASM 6.0 MS MASM 6.0 Reference MS MASM 6.0 Programmer's Guide MS MASM 6.0 White Paper QuickAssembler 2.01 Programmer's Guide MS Mixed-Language Programming Guide CodeView & Utilities User's Guide MS Editor User's Guide MS OnLine User's Guide MASM Sample Code MS KnowledgeBase - MASM MS C 6.0 Advanced Programming Techniques MS C 6.0 Installing and Using the P.D.S. MS C 6.0 Reference MS C 6.0 Run-Time Library Reference MS C 6.0 Developer's Toolkit Reference QuickC 2.5 Tool Kit QuickC 2.5 C for Yourself QuickC 2.5 Up and Running QuickC 2.5 Update MS Professional
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值