【发布时间】:2021-07-16 04:52:37
【问题描述】:
我试图将 memmove 从 C 实现到 x86 程序集,所以我写道:
start:
movb source(%eax), %cl
movb %cl, destination(%eax)
inc %eax
cmp num, %eax
jne start
end:
但这是错误的,为什么?根据:http://www.cplusplus.com/reference/cstring/memmove/
将 num 个字节的值从 source 指向的位置复制到 目标指向的内存块。 复制就像 使用了中间缓冲区,允许目的地和 来源重叠。
我的代码不支持。
如何在不使用堆栈的情况下解决此问题? 注意:我们可以假设在源目标进入内存之后,num(要复制的字节数)很远,不能被错误触及。
【问题讨论】:
-
好吧,既然你特别说你可以假设目的地在源之后,你可以简单地向后复制。 PS:一开始还不清楚你的轮换是为了什么。
-
当它们重叠时,您可以向后(从末尾开始并递减)或向前复制,具体取决于它们重叠的方式。
-
stackoverflow.com/questions/19606399/… 有一个 C 中的示例实现,您可以尝试调整它。如果您的系统有enhanced
rep movsb,那么您可以使用它,使用direction flag 来控制前进与后退。 -
@NateEldredge:
rep movsb在 DF=1 时非常慢,包括在带有 ERMSB 的 CPU 上。当然,您仍然可以使用它来确保正确性,尽管它可能是这个天真的 byte-at-a-time 循环的一半速度(在 Skylake 上每个周期约 2 个字节),每次迭代都从内存中重新加载num并加载通过将一个新字节合并到 ECX 的底部(而不是使用 movzbl)。 (cmp num, %eax/jcc 至少在 Haswell/Skylake 上,IIRC 是否仍将微融合和宏融合到 1-uop cmp/jcc 中,因为它使用的是绝对寻址模式)。 -
@CraigEstey:对于某些硬件上的硬件预取器而言,复制转发可能会更有效,因此您通常希望在 C 规则允许时复制转发。在开始做有用的工作之前,您需要更少的条件分支。当然,如果有足够多的程序滥用
memcpy并依赖它像memmove一样工作,那么让memcpy 做他们实际上并不想要的事情,仅仅因为语言标准允许这样做并不是一个理想的情况。对“错误”更加宽容可能会降低性能。 (不过,如果没有单独的 memcpy,好处可能是代码占用空间更小。)
标签: c assembly x86 att memmove