首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >组件: REP MOVS机制

组件: REP MOVS机制
EN

Stack Overflow用户
提问于 2015-01-07 02:29:38
回答 2查看 35.6K关注 0票数 14

看看下面的汇编代码:

代码语言:javascript
复制
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指令是如何工作的?根据MSDN的说法,“指令的前缀可以是REP,以将操作重复ecx寄存器指定的次数。”这不就是一遍又一遍地重复相同的操作吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-07 02:35:02

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

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

PS:通常操作大小被编码为指令后缀,所以人们使用movsbmovsd来表示bytedword操作。但是,一些汇编程序允许通过byte ptrdword ptr指定示例中的大小。此外,操作数在指令中是隐式的,您不能修改它们。

票数 29
EN

Stack Overflow用户

发布于 2017-05-08 18:23:27

关于语法的简短解释

在汇编代码级别,允许两种形式的指令:“显式操作数”形式和“无操作数”形式。显式操作数形式允许使用符号显式指定存储器的源地址和目标地址。提供此显式操作数表单是为了提供文档;但是,请注意,此表单提供的文档可能具有误导性。也就是说,符号不必指定正确的源地址和目标地址。源地址始终由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-bit)
  • 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变得非常慢,没有理由在基于P5微体系结构的奔腾CPU中使用它(1993-1997)。

与P5微体系结构并行,英特尔开发了P6微体系结构,它决定重新访问REP MOVS,并自1996年起实现了使REP MOVS再次快速的“快速字符串”功能。

2013年,英特尔决定再次访问REP MOVS,并实现了CPUID ERMSB (增强的REP MOVSB)位,该位应该表示CPU以快速高效的方式实现了字节大小的移动和存储指令(movsb,stosb)。在实践中,它仅适用于256字节或更大的大块,并且仅当满足某些条件时才是快速的:

源地址和目标地址都必须与16字节的边界对齐(对于常春藤桥处理器,建议使用此边界大小,在较新的情况下,边界可能更大,最多64字节的Cannonlake);

  • the源区域不应与目标区域重叠;

  • 长度必须是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中最快的。这与旧处理器(2013年之前)形成对比,在旧处理器中,可用的最大MOVS大小(64位上的MOVSQ,32位上的MOVSD )可产生最快的结果。

因此,您所显示的代码对于具有ERMSB的处理器来说并不是最优的,因为只有MOVSB是快速的,而不是MOVSD,尽管差别不是那么大,而且单个REP MOVSB应该足够了-它只会产生一次启动成本,而不是第一个REP MOVSD和第二个REP MOVSB的启动成本。

但是,对于没有ERMBS的处理器,您的代码是可以的,除了1993年发布的基于P5的奔腾处理器,在该处理器中,简单的MOV复制(或在循环中使用更大的x87寄存器)会更快。您给出的代码在非常老的处理器上也会有最好的结果,比如1985年发布的80386。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27804852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档