第85回です。前回はこちら。
[第85回の様子]
2023/07/19に第85回を開催した。
内容としてはRust By Example 日本語版22. 安全でない操作の「22.1. Inline assembly」のSymbol operands and ABI clobbersに取り組んだ。
参加者は自分を入れて6人。
[学んだこと]
- 22.1. Inline assembly: Symbol operands and ABI clobbers
- asm!マクロは、出力に指定されていないレジスタはアセンブリコードによって中身が変わらないと想定している
- clobber_abi()引数を利用すると、コンパイラが自動的に呼び出し規約を補完してくれる
- ABIで保管されないレジスタはclobbered(壊れた)扱いになる
- サンプルコードは次のようになる
use std::arch::asm;
extern "C" fn foo(arg: i32) -> i32 {
println!("arg = {}", arg);
arg * 2
}
fn call_foo(arg: i32) -> i32 {
unsafe {
let result;
asm!(
"call {}",
// 呼び出す関数のポインタ
in(reg) foo,
// RDIレジスタに最初の引数
in("rdi") arg,
// 戻り値はRAXレジスタ
out("rax") result,
// C言語の呼び出し規約で保護されないレジスタをclobberedとしてマーク
clobber_abi("C"),
);
result
}
}
fn main() {
let result = call_foo(10);
println!("result = {}", result);
}
// 出力は以下の通り
arg = 10
result = 20
- 他のレジスタの値が変更されているはずなので、unsafeブロックの前後で確認してみることに
- 以下のようなコードを書いて実行してみた
fn call_foo(arg: i32) -> i32 {
unsafe {
let reg: u64;
asm!(
"mov rbx, rcx",
out("rcx") reg,
);
println!("rbx before asm! = {}", reg);
}
let result
unsafe {;
asm!(
"call {}",
in(reg) foo,
in("rdi") arg,
out("rax") result,
clobber_abi("C"),
);
}
unsafe {
let reg: u64;
asm!(
"mov rbx, rcx",
out("rcx") reg,
);
println!("rbx after asm! = {}", reg);
}
result
}
// 出力は以下の通り
rbx before asm! = 140722307190784
arg = 10
rbx after asm! = 20
result = 20
- 上記はデバッグビルドでの実行結果だった。
- clobber_abi("C")の行をコメントアウトしても結果は変わらなかった。この例ではあまり意味がないのかも?
- リリースビルドにしたら実行結果が変わるかな?と言うことで実験してみたら、以下のような出力になった
rbx before asm! = 140736894476288 arg = 10 rbx after asm! = 0 result = 0
- 結果が変わっているのは、リリースビルドの最適化によって何かが変わっているっぽい
- 動作確認のために、最後のリターンの直前で以下のようにprintln!を挟んだらパニックが発生した。
unsafe {
let reg: u64;
asm!(
"mov rbx, rcx",
out("rcx") reg,
);
println!("rbx after asm! = {}", reg);
}
// この行を追加
println!("result={}", result);
result
// 出力は以下の通り
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
Running `target/debug/playground`
thread 'main' panicked at 'invalid args', /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/core/src/fmt/mod.rs:309:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
rbx before asm! = 140728984006656
arg = 10
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
アセンブリ周り触るコードでprintlnすると壊れるやつが多くて怖い...。
今週もプルリクエストはおやすみ。