汇编字符串操作指令【微软CL vs. GCC】

        最近在研究汇编的一些基本指令,在研究过程中通过二进制的反编译学习到了不少汇编的函数、堆栈和一些可以提高代码运行速度的机器指令等汇编语言语法。如字符串的复制可以使用MOV指令逐个字符赋值,也可以使用字符串操作指令减少指令数,提高运行速度。

1. 字符串操作指令 

1.1 字符串装载LODS

        转载指令用于将ESI寄存器所指向的字符串的字符装入到累加寄存器,同时调整ESI的值(加或者减所操作的字节数)。包括LODSB、LODSW、LODSD、LODSQ。

OpcodeInstructionOp/
En
64-Bit
Mode
Compat/
Leg Mode
Description
ACLODS m8ZOValidValidFor legacy mode, Load byte at address DS:(E)S
into AL. For 64-bit mode load byte at address
(R)SI into AL.
ADLODS m16ZOValidValidFor legacy mode, Load word at address
DS:(E)SI into AX. For 64-bit mode load word at
address (R)SI into AX.
ADLODS m32ZOValidValidFor legacy mode, Load dword at address
DS:(E)SI into EAX. For 64-bit mode load dword
at address (R)SI into EAX.
REX.W + ADLODS m64ZOValidN.E.Load qword at address (R)SI into RAX.
ACLODSBZOValidValidFor legacy mode, Load byte at address DS:(E)S
into AL. For 64-bit mode load byte at address
(R)SI into AL.
ADLODSWZOValidValidFor legacy mode, Load word at address
DS:(E)SI into AX. For 64-bit mode load word at
address (R)SI into AX.
ADLODSDZOValidValidFor legacy mode, Load dword at address
DS:(E)SI into EAX. For 64-bit mode load dword
at address (R)SI into EAX.
REX.W + ADLODSQZOValidN.E.Load qword at address (R)SI into RAX.

1.2 字符串存储STOS

        字符串存储指令用于将累加寄存器值存储到EDI所指向的地址,也就是替换字符,同时调整EDI的值(加或者减所操作的字节数)。包括STOSB、STOSW、STOSD、STOSQ。

OpcodeInstructionOp/
En
64-Bit
Mode
Compat/
Leg Mode
Description
AASTOS m8NAValidValidFor legacy mode, store AL at address ES:(E)DI;
For 64-bit mode store AL at address RDI or
EDI.
ABSTOS m16NAValidValidFor legacy mode, store AX at address ES:(E)DI;
For 64-bit mode store AX at address RDI or
EDI.
ABSTOS m32NAValidValidFor legacy mode, store EAX at address
ES:(E)DI; For 64-bit mode store EAX at address
RDI or EDI.
REX.W + ABSTOS m64NAValidN.E.Store RAX at address RDI or EDI.
AASTOSBNAValidValidFor legacy mode, store AL at address ES:(E)DI;
For 64-bit mode store AL at address RDI or
EDI.
ABSTOSWNAValidValidFor legacy mode, store AX at address ES:(E)DI;
For 64-bit mode store AX at address RDI or
EDI.
ABSTOSDNAValidValidFor legacy mode, store EAX at address
ES:(E)DI; For 64-bit mode store EAX at address
RDI or EDI.
REX.W + ABSTOSQNAValidN.E.Store RAX at address RDI or EDI.

1.3 字符串传送MOVS

        字符串传送指令用于将ESI所指向的字符串传送到EDI所指向的地址,同时调整ESI和EDI的值(加或者减所操作的字节数)。包括MOVSB、MOVSW、MOVSD、MOVSQ。

OpcodeInstructionOp/
En
64-Bit
Mode
Compat/
Leg Mode
Description
A4MOVS m8, m8ZOValidValidFor legacy mode, Move byte from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
byte from address (R|E)SI to (R|E)DI.
A5MOVS m16, m16ZOValidValidFor legacy mode, move word from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
word at address (R|E)SI to (R|E)DI.
A5MOVS m32, m32ZOValidValidFor legacy mode, move dword from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
dword from address (R|E)SI to (R|E)DI.
REX.W + A5MOVS m64, m64ZOValidN.E.Move qword from address (R|E)SI to (R|E)DI.
A4MOVSBZOValidValidFor legacy mode, Move byte from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
byte from address (R|E)SI to (R|E)DI.
A5MOVSWZOValidValidFor legacy mode, move word from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
word at address (R|E)SI to (R|E)DI.
A5MOVSDZOValidValidFor legacy mode, move dword from address
DS:(E)SI to ES:(E)DI. For 64-bit mode move
dword from address (R|E)SI to (R|E)DI.
REX.W + A5MOVSQZOValidN.E.Move qword from address (R|E)SI to (R|E)DI.

 1.4 字符串扫描SCAS

        字符串扫描指令用于将累加寄存器的内容与EDI所指向的字节、双字或四字进行比较,并调整EDI的值(加或者减所操作的字节数)。包括SCASB、SCASW、SCASD、SCASQ。

OpcodeInstructionOp/
En
64-Bit
Mode
Compat/
Leg Mode
Description
AESCAS m8ZOValidValidCompare AL with byte at ES:(E)DI or RDI, then
set status flags.*
AFSCAS m16ZOValidValidCompare AX with word at ES:(E)DI or RDI, then
set status flags.*
AFSCAS m32ZOValidValidCompare EAX with doubleword at ES(E)DI or
RDI then set status flags.*
REX.W + AFSCAS m64ZOValidN.E.Compare RAX with quadword at RDI or EDI
then set status flags.
AESCASBZOValidValidCompare AL with byte at ES:(E)DI or RDI then
set status flags.*
AFSCASWZOValidValidCompare AX with word at ES:(E)DI or RDI then
set status flags.*
AFSCASDZOValidValidCompare EAX with doubleword at ES:(E)DI or
RDI then set status flags.*
REX.W + AFSCASQZOValidN.E.Compare RAX with quadword at RDI or EDI
then set status flags.

 1.5 字符串比较CMPS

        字符串比较指令用于将ESI所指向的数据与EDI所指向的数据进行比较,同时调整ESI和EDI的值(加或者减所操作的字节数)。包括CMPSB、CMPSW、CMPSD、CMPSQ。

OpcodeInstructionOp/
En
64-Bit
Mode
Compat/
Leg Mode
Description
A6CMPS m8, m8ZOValidValidFor legacy mode, compare byte at address DS:(E)SI with
byte at address ES:(E)DI; For 64-bit mode compare byte
at address (R|E)SI to byte at address (R|E)DI. The status
flags are set accordingly.
A7CMPS m16, m16ZOValidValidFor legacy mode, compare word at address DS:(E)SI
with word at address ES:(E)DI; For 64-bit mode
compare word at address (R|E)SI with word at address
(R|E)DI. The status flags are set accordingly.
A7CMPS m32, m32ZOValidValidFor legacy mode, compare dword at address DS:(E)SI at
dword at address ES:(E)DI; For 64-bit mode compare
dword at address (R|E)SI at dword at address (R|E)DI.
The status flags are set accordingly.
REX.W + A7CMPS m64, m64ZOValidN.E.Compares quadword at address (R|E)SI with quadword
at address (R|E)DI and sets the status flags accordingly.
A6CMPSBZOValidValidFor legacy mode, compare byte at address DS:(E)SI with
byte at address ES:(E)DI; For 64-bit mode compare byte
at address (R|E)SI with byte at address (R|E)DI. The
status flags are set accordingly.
A7CMPSWZOValidValidFor legacy mode, compare word at address DS:(E)SI
with word at address ES:(E)DI; For 64-bit mode
compare word at address (R|E)SI with word at address
(R|E)DI. The status flags are set accordingly.
A7CMPSDZOValidValidFor legacy mode, compare dword at address DS:(E)SI
with dword at address ES:(E)DI; For 64-bit mode
compare dword at address (R|E)SI with dword at
address (R|E)DI. The status flags are set accordingly.
REX.W + A7CMPSQZOValidN.E.Compares quadword at address (R|E)SI with quadword
at address (R|E)DI and sets the status flags accordingly.

2. 示例

        如下的字符串复制函数C代码在经过编译器编译后,不同的编译器编译参数将产生不同的机器码,代码中的dst[n] = src[n]语句经过编译后可能会使用到字符串操作指令。以下是casm.c源文件中的copy_str函数:

void copy_str(void)
{
	char src[32] = "this is a string";
	char dst[32] = "";
	
	for(int n = 0; n < 32; n++)
	{
		dst[n] = src[n];
	}
	
	printf("copy_str called: %s\n", dst);
}

        本文编译示例代码使用的CL编译器的版本是用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.29.30133 版,GCC版本是4.7.2。 

2.1 微软CL编译

2.1.1 不使用优化

        在命令行运行如下命令编译并链接生成可执行程序:

CL /c casm.c
LINK /SUBSYSTEM:CONSOLE /RELEASE casm.obj

         不使用优化生成的机器码如下图所示,CL编译器使用多条MOV指令来复制字符串:

2.1.2 使用O1优化(优选空间)

        在命令行运行如下命令编译并链接生成可执行程序:

CL /c /O1 /GA /w /TC /nologo /Fo casm.c
LINK /SUBSYSTEM:CONSOLE /RELEASE casm.obj

        示例copy_str函数编译后对应的机器码如下图所示,可以看到地址为0x00AC1048等地址使用5次MOVS指令复制了17字符“this is a string",0x00AC1050、0x00AC1054等地址使用了5次STOS指令来将后面的15个字节置为0。如下图所示:

2.1.3 使用O2优化(优选速度)

        在命令行运行如下命令编译并链接生成可执行程序:

CL /c /O2 /GA /w /TC /nologo /Fo casm.c
LINK /SUBSYSTEM:CONSOLE /RELEASE casm.obj

         CL编译器采用O2选项编译后的机器码如下图所示,代码非常精简,使用MOVAPS(Move Aligned Packed Single-Precision Floating-Point Values)指令复制字符串,如下图所示:

2.2 GCC编译

2.2.1 不使用优化

        在命令行运行如下命令编译并链接生成可执行程序:

gcc -std=c99 .\casm.c -o .\casmgcc.exe

         使用gcc编译后的机器码如下图所示,使用了REP指令和MOVS指令逐个复制字符串,MOVS共计执行17次,如下图所示:

2.2.2 使用O1优化

        在命令行运行如下命令编译并链接生成可执行程序:

gcc -std=c99 -O1 .\casm.c -o .\casmgcc.exe

         使用gcc编译后的机器码如下图所示,使用了REP指令和MOVS指令逐个复制字符串,MOVS共计执行17次,为了调用printf函数,gcc还重新分配了stack空间并调用了43次STOS指令,如下图所示:

2.2.3 使用O2优化

         在命令行运行如下命令编译并链接生成可执行程序:

gcc -std=c99 -O2 .\casm.c -o .\casmgcc.exe

         生成的机器码如下图所示,可以看到和使用O1优化所生成的机器码基本一样,也是使用了17次MOVS指令复制字符串,如下图所示:

3. 总结 

        字符串操作指令可以简化字符串的拷贝等操作,CL和GCC编译器各具特色,CL编译器的O2优化可以生成非常精简的机器码。另外,GCC编译器在处理字符串复制操作时,其使用的指令数多于CL编译器。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

「已注销」

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

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

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

打赏作者

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

抵扣说明:

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

余额充值