x86.h static inline void stosl(void *addr, int data, int cnt)

トップページ
jupiteroak.hatenablog.com


x86.h
https://github.com/mit-pdos/xv6-public/blob/master/x86.h#L51

static inline void stosl(void *addr, int data, int cnt)
{
  asm volatile("cld
                 rep stosl"
                 : "=D" (addr), "=c" (cnt)
                 : "0" (addr), "1" (cnt), "a" (data)
                 : "memory", "cc");
}

stosl関数は、先頭アドレスが引数addr・サイズが引数cnt×4のメモリ領域を、引数dataで指定された4バイトの値を使って初期化します(特定のメモリ領域を指定された値で埋めます)。
 
引数 void *addr
初期化の対象となるメモリ領域の先頭アドレスです。

引数 int data
初期化で使用される4バイトの値です。

引数 int cnt
初期化の対象となるメモリ領域のサイズ(バイト単位)÷4の値です。


処理の内容

インラインアセンブラ

asm volatile("cld;
              rep stosl"
              : "=D" (addr), "=c" (cnt)
              : "0" (addr), "1" (cnt), "a" (data)
              : "memory", "cc");

関数内のインラインアセンブラを解釈すると以下のようになります。

アセンブリ言語命令

cld
rep stosl

インラインアセンブラの命令を実行する前の状態

・ediレジスタ(入力レジスタのリストに0、出力レジスタのリストにDで表記されている)
引数addrの値が設定されています。
・ecxレジスタ(入力レジスタのリストに1、出力レジスタのリストにcで表記されている)
引数cntの値が設定されています。
・eaxレジスタ(入力レジスタのリストにaで表記されている)
引数dataの値が設定されています。

cld

cld命令は、EFLGSレジスタのDFフラグ(bit10)をクリアします。DFフラグが0の時にストリング命令(movs、lods、cmps、stosなど)を実行すると、ediレジスタの値がインクリメントするようになります。

rep stosl

repプレフィックス(リピートプレフィックス)を付けられた命令は、ecxレジスタに設定された値の回数分繰り返すように実行されます。
stosl命令は、eaxレジスタに設定された4バイトの値をediレジスタで指定されたメモリに格納します。
DFフラグが0の時(前のcld命令によってDFフラグが0の値になっている)、stosl命令を実行するとediレジスタの値が4インクリメントされます。
repプレフィックスの効果により、この操作をecxレジスタに設定された値の回数分繰り返します。


参考
http://exlight.net/devel/8086/string.html
https://stackoverflow.com/questions/38410829/why-cant-find-the-insl-instruction-in-x86-document