27

标准 C 函数“memcpy”如何工作?它必须将(大)块 RAM 复制到 RAM 中的另一个区域。因为我知道你不能在汇编中直接从 RAM 移动到 RAM(使用 mov 指令)所以我猜它在复制时使用 CPU 寄存器作为中间存储器?

但它是如何复制的?按块(如何按块复制?),按单个字节(char)或它们拥有的最大数据类型(以 long long double 复制 - 在我的系统上是 12 个字节)。

编辑:好吧,显然你可以直接将数据从 RAM 移动到 RAM,我不是装配专家,我所学到的关于装配的所有知识都是从这个文档(X86 装配指南)中提到的,它在关于你不能移动的 mov 指令的部分中提到RAM 到 RAM。显然这不是真的。

4

3 回答 3

24

要看。通常,您无法在单个周期中物理复制大于最大可用寄存器的任何内容,但这并不是当今机器的真正工作方式。在实践中,您真正关心的不是 CPU 在做什么,而是更关心 DRAM 的特性。机器的内存层次结构将在以尽可能快的方式执行此复制方面发挥至关重要的决定性作用(例如,您是否加载了整个高速缓存行?相对于复制操作而言,DRAM 行的大小是多少?)。一个实现可能会选择使用某种向量指令来实现memcpy。在不参考特定实现的情况下,它实际上是具有一个位置缓冲区的逐字节复制。

这是一篇有趣的文章,描述了一个人对优化的冒险memcpy。主要的要点是,它总是会根据您可以廉价执行的指令针对特定的架构和环境。

于 2013-07-06T01:39:46.773 回答
12

的实施memcpy高度特定于实施它的系统。实现通常是硬件辅助的。

内存到内存的 mov 指令并不少见——它们至少PDP-11在你可以写这样的东西时就已经存在了:

    MOV FROM, R2
    MOV TO,   R3
    MOV R2,   R4
    ADD LEN,  R4
CP: MOV (R2+), (R3+) ; "(Rx+)" means "*Rx++" in C
    CMP R2, R4
    BNE CP

注释行大致相当于 C 的

*to++ = *from++;

现代 CPU 具有memcpy直接实现的指令:您使用源地址和目标地址加载特殊寄存器,调用内存复制命令,然后让 CPU 完成其余工作。

于 2013-07-06T01:41:05.150 回答
7

一个简单的实现memcpy是:

 while (n--) *s2++ = *s1++;

glibc通常在汇编代码中使用一些巧妙的实现。memcpy调用通常是内联的。

在 x86 上,代码检查 size 参数是否是文字的倍数 2或倍数4(使用gcc内置函数)并使用带有movl指令的循环(复制4字节),否则它会调用一般情况。

一般情况下使用快速块复制程序集使用repmovsl指令。

于 2013-07-06T01:40:16.790 回答