web-dev-qa-db-ja.com

memcpyの内部実装はどのように機能しますか?

標準のC関数「memcpy」はどのように機能しますか? RAM)の(大きな)チャンクをRAMの別の領域にコピーする必要があります。私が知っているので、RAMからRAMアセンブリ(mov命令を使用)ので、コピー時にCPUレジスタを中間メモリとして使用していると思いますか?

しかし、それはどのようにコピーしますか?ブロックごと(どのようにブロックごとにコピーしますか?)、個々のバイト(char)、またはそれらが持つ最大のデータ型ごと(長いlong doubleでコピー-私のシステムでは12バイト)。

編集:OK RAM to RAM directlyから私はアセンブリの専門家ではありません。アセンブリについて学んだことは、このドキュメント( X86アセンブリガイド )からです。これは、mov命令に関するセクションで、RAM RAMへ。これは正しくないようです。

21
hddh

依存します。一般的に、1つのサイクルで使用可能な最大のレジスタよりも大きなものを物理的にコピーすることはできませんでしたが、最近のマシンの動作はそうではありません。実際には、CPUの動作についてはあまり気にせず、DRAMの特性についてもっと気にします。マシンのメモリ階層は、このコピーを可能な限り高速に実行する上で重要な決定的な役割を果たすでしょう(たとえば、キャッシュライン全体をロードしていますか?コピー操作に関してDRAM行のサイズはどれくらいですか?)。代わりに、実装は、ある種のベクトル命令を使用してmemcpyを実装することを選択する場合があります。特定の実装を参照しなければ、それは事実上、1桁のバッファーを持つバイト単位のコピーです。

これは楽しい記事です は、memcpyを最適化するための1人の冒険について説明しています。主なポイントは、安価に実行できる命令に基づいて、特定のアーキテクチャと環境を常に対象とすることです。

19
Gian

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に任せます。

9
dasblinkenlight

memcpyの簡単な実装は次のとおりです。

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

しかし、glibcは通常、アセンブリコードで巧妙な実装を使用します。 memcpy呼び出しは通常インライン化されます。

X86では、コードはサイズパラメーターが2のリテラル倍数か4の倍数(gcc組み込み関数を使用)かどうかをチェックし、movl命令(4バイトのコピー)でループを使用します。それ以外の場合は、一般的なケースを呼び出します。

一般的なケースでは、repおよびmovsl命令を使用した高速ブロックコピーアセンブリを使用します。

5
ouah