kdnakt blog

hello there.

Rust dojo第84回を開催した

第84回です。諸事情あって1週スキップしてました。前回はこちら。

kdnakt.hatenablog.com

[第84回の様子]

2023/07/12に第84回を開催した。

内容としてはRust By Example 日本語版22. 安全でない操作の「22.1. Inline assembly」のClobbered registersをなんとか終わらせた。1ヶ月以上かかってしまった...。
参加者は自分を入れて6人。

[学んだこと]

  • 22.1. Inline assembly: Clobbered registers
  • サンプルコードは前回までである程度理解できたので、改めて解説の英文を読んでいくことに
use std::arch::asm;

fn main() {
    // 4バイト×3つ分
let mut name_buf = [0_u8; 12]; // 文字列はASCIIコードとしてebx, edx, ecxに保管される
// ebxは予約されているので、その値を保存するためにpush/popが必要 unsafe { asm!( "push rbx", "cpuid", "mov [rdi], ebx", "mov [rdi + 4], edx", "mov [rdi + 8], ecx", "pop rbx", // Rustコードをシンプルにするために、アセンブリのコードを増やして // 配列へのポインタを用いて値を保存する // `out("ecx") val`のように明示的な出力レジスタを利用するのと対照的に、
// アセンブリの動きはより明示的になる // ポインタそのものはあくまで入力として扱われる in("rdi") name_buf.as_mut_ptr(), // cpuid 0を選択し、eaxをclobberedに指定する inout("eax") 0 => _, // cpuidは以下のレジスタもclobberする out("ecx") _, out("edx") _, ); } // バイト列を文字列に変換 let name = core::str::from_utf8(&name_buf).unwrap(); println!("CPU Manufacturer ID: {}", name);
// CPU Manufacturer ID: AuthenticAMD
}
use std::arch::asm;

fn main() {
    let mut name_buf = [0_u8; 12];

    unsafe {
        asm!(
            "cpuid",
            "mov [rdi], ebx",
            "mov [rdi + 4], edx",
            "mov [rdi + 8], ecx",
            in("rdi") name_buf.as_mut_ptr(),
            inout("eax") 0 => _,
            // ebxレジスタを出力に利用
            out("ebx") _,
            out("ecx") _,
            out("edx") _,
        );
    }

    let name = core::str::from_utf8(&name_buf).unwrap();
    println!("CPU Manufacturer ID: {}", name);
}

// 以下のコンパイルエラー
error: cannot use register `bx`: rbx is used internally by LLVM and cannot be used as an operand for inline asm
  --> src/main.rs:15:13
   |
15 |             out("ebx") _,
   |             ^^^^^^^^^^^^

error: could not compile `playground` (bin "playground") due to previous error
  • 上記エラーを回避するために、64ビットマシンではrbxを、32ビットマシンではebxをpush/popしてレジスタの状態を戻す必要がある
  • 汎用レジスタを利用しても同じことができる
use std::arch::asm;

// シフト演算と加算を利用してxに6をかける
let mut x: u64 = 4;
unsafe {
    asm!(
        "mov {tmp}, {x}",
        "shl {tmp}, 1",
        "shl {x}, 2",
        "add {x}, {tmp}",
        x = inout(reg) x,
        tmp = out(reg) _,
    );
}
assert_eq!(x, 4 * 6);

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。

ようやくClobbered registersの森を抜けた...インラインアセンブリの道のりは遠い。

今週もプルリクエストはおやすみ。