第79回です。前回はこちら。
[第79回の様子]
2023/05/31に第79回を開催した。
内容としてはRust By Example 日本語版22. 安全でない操作の「22.1. Inline assembly」のInputs and outputsに取り組んだ。
参加者は自分を入れて6人。前回途中で終わってしまったので、今回もドライバを担当した。
[学んだこと]
- 22.1. Inline assembly: Basic usage
- 復習。基本的な使い方は以下の通り
use std::arch::asm;
unsafe {
asm!("nop"); //何もしないアセンブリ命令
}
- 22.1. Inline assembly: Inputs and outputs
- 実際に値を操作するアセンブリを書いてみる
use std::arch::asm;
let x: u64;
unsafe {
asm!("mov {}, 5", out(reg) x);
}
assert_eq!(x, 5);
println!("x={}", x);
// x=5が出力される
- アセンブリにRust側の引数を渡す際は、フォーマット文字列を利用する
- その際、引数がインラインアセンブリの入力なのか出力なのかを示す必要がある
- 上記の場合、出力になるので、
outを指定する - 加えて、レジスタの種類も指定する必要がある
- 今回は汎用レジスタを利用するので、
regを指定する
- 最終的にコンパイラがテンプレート文字列に適切なレジスタを挿入する
- インラインアセンブリの実行後、Rustの変数に変数を読み込む
- 入力を利用する例は以下のようになる
use std::arch::asm;
let i: u64 = 3;
let o: u64;
unsafe {
asm!(
"mov {0}, {1}",
"add {0}, 5",
out(reg) o,
in(reg) i,
);
}
assert_eq!(o, 8);
println!("o={}", o);
// o=8と出力される
- 上の処理では、まず
iの値をレジスタに書き込み、さらにそこに5を足している - このように、
asm!マクロは複数のテンプレート文字列を利用できる- 引数を
{0},{1}のようにして受け取ることができる
- 引数を
- Rustの変数を入力に利用する場合は、
inを指定する - 同じ変数をインラインアセンブリの入力と出力両方で利用したい場合には、
inoutキーワードを利用できる
use std::arch::asm;
let mut x: u64 = 3;
unsafe {
asm!("add {0}, 5", inout(reg) x);
}
assert_eq!(x, 8);
- 以下のように、
inoutを指定しつつ入力と出力で利用するRust変数を別にすることもできる
use std::arch::asm;
let x: u64 = 3;
let y: u64;
unsafe {
asm!("add {0}, 5", inout(reg) x => y);
}
assert_eq!(y, 8);
- インラインアセンブリで利用するテンプレート文字列の引数は、インデックス以外にも名前を利用することができる、と書かれていた
- 日本語版のサイトではよく分からなかったが、Rust Referenceのサイトを見て書き方がわかった
"mov {x}, {y}"のようにテンプレートを書き、引数でx=out(reg) oのように引数名を与える
use std::arch::asm;
fn main() {
let i: u64 = 3;
let o: u64;
unsafe {
asm!(
"mov {x}, {y}",
"add {x}, 5",
x=out(reg) o,
y=in(reg) i,
);
}
assert_eq!(o, 8);
println!("o={}", o);
// o=8
}
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
インラインアセンブリ編がなかなか終わらない...。
今週のプルリクエストはこちら。