注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
極めて低レベルな技巧やパフォーマンス上の理由から、CPUを直接コントロールしたいと思う人もいるでしょう。
Rustはそのような処理を行うために、インラインアセンブリを asm!
マクロによってサポートしています。
asm!(アセンブリのテンプレート : 出力オペランド : 入力オペランド : 破壊されるデータ : オプション );
asm
のいかなる利用もフィーチャーゲートの対象です(利用するには #![feature(asm)]
がクレートに必要になります)。
そしてもちろん unsafe
ブロックも必要です。
メモ: ここでの例はx86/x86-64のアセンブリで示されますが、すべてのプラットフォームがサポートされています。
アセンブリテンプレート
のみが要求されるパラメータであり、文字列リテラル (例: ""
) である必要があります。
#![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn foo() { unsafe { asm!("NOP"); } } // その他のプラットフォーム #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn foo() { /* ... */ } fn main() { // ... foo(); // ... }
以後は、 feature(asm)
と #[cfg]
は省略して示します。
出力オペランド、入力オペランド、破壊されるデータ、オプションはすべて省略可能ですが、省略する場合でも正しい数の :
を書く必要があります。
asm!("xor %eax, %eax" : : : "{eax}" );
空白も必要ではありません:
#![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn main() { unsafe { asm!("xor %eax, %eax" ::: "{eax}"); } }asm!("xor %eax, %eax" ::: "{eax}");
入力と出力のオペランドは、 : "制約1"(式1), "制約2"(式2), ...
というフォーマットに従います。
出力オペランドの式は変更可能な左辺値か、アサインされていない状態でなければなりません。
fn add(a: i32, b: i32) -> i32 { let c: i32; unsafe { asm!("add $2, $0" : "=r"(c) : "0"(a), "r"(b) ); } c } fn main() { assert_eq!(add(3, 14159), 14162) }
もし本当のオペランドをここで利用したい場合、波括弧 {}
で利用したいレジスタの周りを囲む必要があり、また、オペランドの特有のサイズを書く必要があります。
これは、どのレジスタを利用するかが重要となる、ごく低レベルのプログラミングで有用です。
let result: u8; asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port)); result
いくつかのインストラクションは異なる値を持っている可能性のあるレジスタを変更する事があります。 そのため、コンパイラがそれらのレジスタに格納された値が処理後にも有効であると思わないように、破壊されるデータのリストを利用します。
#![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn main() { unsafe { // Put the value 0x200 in eax // eaxに0x200を格納します // asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "{eax}"); asm!("mov $$0x200, %eax" : /* 出力なし */ : /* 入力無し */ : "{eax}"); } }// eaxに0x200を格納します asm!("mov $$0x200, %eax" : /* 出力なし */ : /* 入力無し */ : "{eax}");
入力と出力のレジスタは変更される可能性があることが制約によってすでに伝わっているために、リストに載せる必要はありません。 それ以外では、その他の暗黙的、明示的に利用されるレジスタをリストに載せる必要があります。
もしアセンブリが条件コードを変更する場合、レジスタ cc
も破壊されるデータのリストに指定する必要があります。
同様に、もしアセンブリがメモリを変更する場合 memory
もリストに指定する必要があります。
最後のセクション、 options
はRust特有のものです。
options
の形式は、コンマで区切られた文字列リテラルのリスト(例: :"foo", "bar", "baz"
)です。
これはインラインアセンブリについての追加の情報を指定するために利用されます:
現在有効なオプションは以下の通りです:
__asm__ __volatile__ (...)
を指定することと類似しています。let result: i32; unsafe { asm!("mov eax, 2" : "={eax}"(result) : : : "intel") } println!("eax is currently {}", result);
現在の asm!
マクロの実装は LLVMのインラインアセンブリ表現 への直接的なバインディングです。
そのため破壊されるデータのリストや、制約、その他の情報について LLVMのドキュメント を確認してください。