static inline void *__memset(void *s, char c, size_t n) {
int d0, d1;
asm volatile (
"rep; stosb;"
: "=&c" (d0), "=&D" (d1)
: "0" (n), "a" (c), "1" (s)
: "memory");
return s;
}
「d0」と「d1」は何に使われますか? すべてのコードを完全に説明していただけますか?ありがとう!
static inline void *__memset(void *s, char c, size_t n) {
int d0, d1;
asm volatile (
"rep; stosb;"
: "=&c" (d0), "=&D" (d1)
: "0" (n), "a" (c), "1" (s)
: "memory");
return s;
}
「d0」と「d1」は何に使われますか? すべてのコードを完全に説明していただけますか?ありがとう!
gcc拡張インラインasm形式を理解する必要があります。
"=&c"
d0をecxレジスタに関連付け、書き込み専用としてマークします。&
コードが終了する前に変更できることを意味します"=&D"
ediレジスタについても同じことを意味します"0" (n)
nを最初に言及されたレジスタに関連付けます。あなたの場合、ecxで"a" (c)
cをeaxに関連付ける"1" (s)
sをediに関連付けますだからあなたはそれを持っています。このecx回(n回)を繰り返します。eax(c)をedi(s)に格納してから、インクリメントします。
では、なぜ未使用なd0
のd1
か?わからない。私もこの場合は役に立たないと思いますし、出力セクション全体を空のままにしておくこともできますが、入力制約で「書き込み可能」と「早期クローバー」を指定することはできないと思います。だから私は考えd0
て、それを可能d1
にするためにそこにい&
ます。
私はそれをこのように書いてみます:
asm volatile (
"rep\n"
"stosb\n"
:
: "c" (n), "a" (c), "D" (s)
: "%ecx", "%edi", "memory"
);
「d0」と「d1」は何に使われますか?
事実上、%ecx
( %edi
32 ビットと仮定して)の最終値が ,d0
にd1
それぞれ格納されることを意味します。これにはいくつかの目的があります。
出力として、これらのレジスターが実質的に上書きされていることをコンパイラーに知らせます。それらを一時変数に割り当てることにより、最適化コンパイラは、「ストア」操作を実際に実行する必要がないことも認識します。
"=&" は、これらを早期破壊オペランドとして指定します。すべての入力が消費される前に、それらに書き込むことができます。したがって、コンパイラが入力レジスタを自由に選択できる場合、これら 2 つのエイリアスを作成するべきではありません。
これは、入力として明示的に%ecx
名前が付けられているため、技術的には必要ありません: - この場合の「rep」カウント。入力が消費されて命令が実行される前に更新できないため、どちらにも必要かどうかはわかりません。繰り返しになりますが、入力として明示的に名前が付けられているため、コンパイラーは自由に別のレジスターを選択できません。要するに、「=&」はここでは問題ありませんが、何もしません。"0" (n)
%edi
"1" (s)
に設定された入力専用レジスタを"a" (c)
指定すると、コンパイラはが 'asm' の後もこの値を保持していると想定する場合があります。これは実際に の場合です。%eax
(c)
%eax
"rep; stosb;"
"memory"
コンパイラに知られていない方法でメモリを変更できることを指定します。この場合は真であり、値(n)
から始まるバイトを設定しています。方向フラグがクリアされている必要があります。これには、値のリロードを強制する効果があります。コンパイラは、レジスタが想定されているメモリ値を反映していると想定できないためです。害はなく、一般的なケースでは安全にする必要があるかもしれませんが、多くの場合、やり過ぎです。(r)
(c)
memset
編集:入力オペランドは clobber オペランドとオーバーラップできません。何かをinput-only および clobberedとして指定しても意味がありません。コンパイラがこれを許可しているとは思いませんし、あいまいな仕様を使用するのは賢明ではありません。マニュアルから:
入力オペランドまたは出力オペランドと重複する方法でクロバー記述を記述してはなりません。たとえば、1 つのメンバーを持つレジスター クラスを記述しているオペランドが、そのレジスターを clobber リストで言及している場合、存在しない可能性があります。
いくつかの古い回答を見直して、優れたLockless GCC インライン ASM チュートリアルへのリンクを追加すると思いました。この記事は、「リファレンス」として最もよく説明されている gcc マニュアルとは異なり、前のセクションに基づいており、構造化された学習にはまったく適していません。