インラインアセンブリ拡張構文
Linuxのコードでしばしば登場するこれ。
アセンブリなんだけど独特のルールがめんどくせぇ。
しっかり理解しておこう。
オペランド
__asm__()とやってカッコの中に命令を書き込んでいきます。
c言語では直接扱えないレジスタへの入出力が行えます。
以下のルールがあります。
__asm__ ( アセンブリテンプレート : 出力オペランド : 入力オペランド : 破壊するレジスタ );
アセンブラテンプレート
アセンブリ言語を記述しますが、少しだけ書き方が違います。
命令と始まりと終わりを””で囲み、一行の最後毎に;を置きます。
レジスタを使用する場合は先頭に%%を付けます。
int main() { int zero=0,one=1,out; asm volatile ( "movl %1,%%eax" /* zero(ebx)の値をeaxへ */ "movl %2,%%eax" /* one(ecx)の値をeaxへ */ "movl %%eax,%0" /* eaxの値をout(ジェネラルレジスタ)へ */ : "=g"(out) /* 出力オペランドoutは%0 */ : "b"(zero),"c"(one) /* 入力オペランドzeroは%1でoneは%2 */ ); return 0; }
全く意味のないコードですが例として挙げておきます。
インラインアセンブリの外にc言語で書かれた変数も利用することができます。
その際は後述する出力オペランドと入力オペランドで指定しますが、指定された順に%0、%1…と番号で割り当てられます。
出力オペランド
:";=制約文字"(変数名)
で指定されます。
インライアセンブリの外に書いたc言語の変数にレジスタの値を保存したい時などに使用します。
=の後の制約文字には沢山の種類があり使用したいものに合わせて=を修飾します。
a | eax |
---|---|
b | ebx |
c | ecx |
d | edx |
r | レジスタが自動で割り当てられます |
m | メモリに割り当てられます |
g | 汎用レジスタが割り当てられます。 |
他にもたくさんありますが基本的なものです。
頭文字で表されているので分かりやすいはずです。
変数名にはインライアセンブリの外側にc言語で書かれた変数を指定します。
:";=a"(var1)
のように設定すれば
入力オペランド
:™制約文字"(変数名)
出力オペランドの=が抜けたものです。
破壊オペランド
インラインアセンブリでは自由にレジスタを指定できますが、その過程で無関係の変数が割り当てられたレジスタを上書きしてしまう可能性があります。
それを防ぐために最後の行にインラインアセンブリで使用するレジスタを列挙します。
コンパイラーはそのレジスタのデータを破壊しないようなコードを出力します。
コメント