[第81回の様子]
2023/06/14に第81回を開催した。
内容としてはRust By Example 日本語版22. 安全でない操作の「22.1. Inline assembly」のExplicit register operandsに取り組んだ。
参加者は自分を入れて多分6~7人。今回は低レイヤに詳しい別のくわしい人がドライバやってくれたので助かった!
[学んだこと]
- 22.1. Inline assembly: Explicit register operands
- 明示的なレジスタのオペランドの話。
- asmの命令の中には、特定のレジスタにオペランドが存在しないといけないものがある
- なので、Rustのインラインアセンブリでは、レジスタを指定することができる
- 以下の例ではeaxレジスタのみを受けいてるout命令を使っている
use std::arch::asm; let cmd = 0xd1; unsafe {
// 0x64ポートに0xd1を出力する asm!("out 0x64, eax", in("eax") cmd); }
- 明示的にレジスタを指定する場合、インラインアセンブリの中でテンプレート文字列として変数を利用できないので、上のようにレジスタ名を直接書く必要がある
- また、レジスタを明示的に指定した場合は、オペランドのリスト(引数のリスト)の末尾に来る必要がある
- x86のmul命令を利用した例は以下のようになる
use std::arch::asm; fn mul(a: u64, b: u64) -> u128 { println!("a={:X}", a); println!("b={:X}", b); let lo: u64; let hi: u64; unsafe { asm!( // x86のmul命令はraxレジスタを暗黙の入力に利用する // raxとrdxレジスタに128ビットの計算結果を出力する "mul {}", in(reg) a, // raxレジスタにbを入力し、出力はlo変数に戻す inlateout("rax") b => lo, // raxの上位64ビットはrdxレジスタにあり、hi変数に戻される lateout("rdx") hi ); } ((hi as u128) << 64) + lo as u128 } fn main() { let res = mul(u64::MAX, u64::MAX); // a=FFFFFFFFFFFFFFFF // b=FFFFFFFFFFFFFFFF println!("res={:X}", res); // res=FFFFFFFFFFFFFFFE0000000000000001 }
- テキストには載っていなかったが、ドライバの人が詳しかったのでxor命令も説明してくれた
- xorの結果を返すので、どんな値が与えられても0になる
use std::arch::asm; fn main() { let mut cmd = 1; println!("cmd={}", cmd); // cmd=1 unsafe { asm!("xor eax, eax", inout("eax") cmd); } println!("cmd={}", cmd); // cmd=0 }
- この例は最近読んでいるRust Atomics and Locksでも登場していた
- mov eax, 0とやるよりも必要なレジスタの数が少なくてすむので好まれるとのこと
Rust Atomics and Locks — Chapter 7. Understanding the Processor
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
レジスタむずい...低レイヤーほんとに何もわからない。
今週のプルリクエストはおやすみ。