第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すると壊れるやつが多くて怖い...。
今週もプルリクエストはおやすみ。