3
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」は何に使われますか? すべてのコードを完全に説明していただけますか?ありがとう!

4

2 に答える 2

3

gcc拡張インラインasm形式を理解する必要があります。

  • 最初の部分は実際のアセンブリです。この場合、2つの命令しかありません
  • 2番目の部分は出力制約を指定し、3番目の部分は入力制約を指定します。4番目の部分は、アセンブリがメモリを破壊することを指定します

出力

  • "=&c"d0をecxレジスタに関連付け、書き込み専用としてマークします。&コードが終了する前に変更できることを意味します
  • "=&D"ediレジスタについても同じことを意味します

入力

  • "0" (n)nを最初に言及されたレジスタに関連付けます。あなたの場合、ecxで
  • "a" (c)cをeaxに関連付ける
  • "1" (s)sをediに関連付けます

組み立て

だからあなたはそれを持っています。このecx回(n回)を繰り返します。eax(c)をedi(s)に格納してから、インクリメントします。


では、なぜ未使用なd0d1か?わからない。私もこの場合は役に立たないと思いますし、出力セクション全体を空のままにしておくこともできますが、入力制約で「書き込み可能」と「早期クローバー」を指定することはできないと思います。だから私は考えd0て、それを可能d1にするためにそこにい&ます。

私はそれをこのように書いてみます:

asm volatile (
    "rep\n"
    "stosb\n"
    :
    : "c" (n), "a" (c), "D" (s)
    : "%ecx", "%edi", "memory"
);
于 2012-03-20T13:53:22.453 に答える
1

「d0」と「d1」は何に使われますか?

事実上、%ecx( %edi32 ビットと仮定して)の最終値が ,d0d1それぞれ格納されることを意味します。これにはいくつかの目的があります。

出力として、これらのレジスターが実質的に上書きされていることをコンパイラーに知らせます。それらを一時変数に割り当てることにより、最適化コンパイラは、「ストア」操作を実際に実行する必要がないことも認識します。

"=&" は、これらを早期破壊オペランドとして指定します。すべての入力が消費される前に、それらに書き込むことができます。したがって、コンパイラが入力レジスタを自由に選択できる場合、これら 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 マニュアルとは異なり、前のセクションに基づいており、構造化された学習にはまったく適していません。

于 2012-03-20T15:58:38.827 に答える