组装:REP MOV机制

时间:2015-01-06 18:29:38

标签: assembly x86

查看以下汇编代码:

MOV ESI, DWORD PTR [EBP + C]
MOV ECX, EDI
MOV EAX, EAX
SHR ECX, 2
LEA EDI, DWORD PTR[EBX + 18]
REP MOVS DWORD PTR ES:[EDI], DWORD PTR [ESI]
MOV ECX, EAX
AND ECX, 3
REP MOVS BYTE PTR ES:[EDI], BYTE PTR[ESI]

我从代码摘录中得到的书解释了第一个REP MOVS复制4字节块,第二个REP MOVS复制剩余的2字节块(如果存在)。

REP MOVS说明如何运作?根据{{​​3}},"该指令可以用REP作为前缀,以重复操作ecx寄存器指定的次数。"不会一遍又一遍地重复同样的操作吗?

2 个答案:

答案 0 :(得分:15)

有关特定指令的问题,请参阅指令集参考。

在这种情况下,您需要查找repmovs(不是mov)。 简而言之,rep重复以下字符串操作ecx次。 movs将数据从ds:esi移动到es:edi,并根据方向标志的设置递增或递减指针。因此,重复它会将一系列内存移动到其他地方。

PS:通常将操作大小编码为指令后缀,因此人们使用movsbmovsd来指示bytedword操作。但是,某些汇编程序允许通过byte ptrdword ptr指定示例中的大小。此外,操作数隐含在指令中,您无法修改它们。

答案 1 :(得分:5)

简短说明

在汇编代码级别,允许两种形式的指令:“显式操作数”形式和“nooperand”形式。显式操作数形式允许使用符号显式指定存储器的源地址和目标地址。提供此显式操作数表单以允许文档;但请注意,此表单提供的文档可能会产生误导。也就是说,符号不必指定正确的源和目标地址。源地址始终由DS指定:(RSI / ESI / SI),目标地址始终由ES:(RDI / EDI / DI)寄存器指定,必须在执行movsb指令之前正确加载。这就是我理解英特尔在这个问题上的官方立场。

长篇解释

REP MOVS DWORD PTR ES:[EDI], DWORD PTR [ESI]REP MOVSD的同义词; REP MOVS BYTE PTR ES:[EDI], BYTE PTR[ESI]REP MOVSB的同义词。

根据数据大小,有以下MOVS命令:

  • MOVSB(字节,8位)
  • MOVSW(字,16位)
  • MOVSD(双字,32位)
  • MOVSQ(qword,64位) - 仅在64位模式下可用

MOVS命令将数据从DS:(SI / ESI / RSI)复制到ES:(DI / EDI / RDI) - SI / DI寄存器的大小基于您当前的模式 - 16位,32-位或64位。 它还增加(减少)SI和DI寄存器(基于D标志,设置CLD以增加寄存器)。

MOVS命令不能使用除SI / DI之外的其他寄存器,因此无需指定它们。

如果MOVS命令以REP为前缀,则重复执行CX(ECX / RCX)字节数,减少CX,因此最后CX变为零。

自1993年生产第一台奔腾CPU以来,英特尔开始使更简单的命令执行得更快,复杂的命令(如REP MOVS) - 更慢。

因此,REP MOVS变得非常缓慢,没有理由使用它。

2013年,英特尔决定重新访问REP MOVS。如果CPU(2013年之后生产)具有CPUID ERMSB(Encanced REP MOVSB)位,则rep movsb和rep stosb命令的执行方式与旧处理器不同,并且应该是快速的。在实践中,它只对大块,256字节和更大的块快速,并且只有在满足某些条件时才会快速:

  • 源地址和目标地址都必须与16字节边界对齐(对于Ivy Bridge处理器,建议使用此边界大小,较新的边界可能更大,Cannonlake最多可达64字节);
  • 源区域不应与目标区域重叠;
  • 长度必须是64字节的倍数才能产生更高的性能;
  • 方向必须向前(CLD)。

请参阅“英特尔优化手册”第3.7.6节“增强REP MOVSB和STOSB操作(ERMSB)http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf

REP MOVS指令在小块上非常慢,因为启动成本约为35个周期。如果你在一个循环中做简单的MOV EAX,没有启动成本,你可以在这35个循环中复制大量数据。

请注意,ERMSB为REP MOVSB产生最佳结果,而不是REP MOVSD(MOVSQ)。所有REP MOVS指令都变得更快,但REP MOVSB是最快的。

因此,您所显示的代码在没有ERMSB的处理器上不是最佳的(因为普通的简单MOV EAX副本会更快),或者使用ERMSB(因为只有MOVSB很快,而不是MOVSD,尽管区别不大)

您提供的代码可能只会在1985年发布的80386这样的旧处理器上获得最佳效果。