kdnakt blog

hello there.

Rust dojo第86回を開催した

第86回です。前回はこちら。

kdnakt.hatenablog.com

[第86回の様子]

2023/07/26に第86回を開催した。

内容としてはRust By Example 日本語版22. 安全でない操作の「22.1. Inline assembly」のRegister template modifiersに取り組んだ。
参加者は自分を入れて7人。久しぶりにドライバを担当した!

[学んだこと]

  • 22.1. Inline assembly: Register template modifiers
  • レジスタの名前をテンプレート文字列に入れる際に、うまくコントロールしたい場合がある
    • 同じレジスタがいくつかの名前を持っている場合がそう。
    • 64ビットレジスタの下位32ビットのようなサブセットになっているケースがそれ。
  • コンパイラはフルレジスタの名前をデフォルトで利用する
    • x86-64ならrax、x86ならeaxといった感じ
  • テンプレート文字列中の修飾子を利用することで変更できる
  • 以下の例では、reg_abcdクラスを使い、x86のax 、bx、cx、dxに限定している
use std::arch::asm;

fn main() {
    let mut x: u16 = 0xab;
    unsafe {
        // レジスタ・アロケータがaxレジスタを選んだ場合、
        // mov ah, alに変換され、下位ビットを上位ビットにコピーする
        asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
    }
    assert_eq!(x, 0xabab);
}
  • 試しに、mov ah, alと直接書いてみると、ちゃんと動いた
  • hやlなどのテンプレート修飾子を使わないと、以下のような警告が出る
warning: formatting may not be suitable for sub-register argument
 --> src/main.rs:8:19
  |
8 |         asm!("mov {0}, {0}", inout(reg_abcd) x);
  |                   ^^^  ^^^                   - for this argument
  |
  = help: use `{0:x}` to have the register formatted as `ax`
  = help: or use `{0:r}` to keep the default formatting of `rax`
  = note: `#[warn(asm_sub_register)]` on by default
  • ナビゲータの方に教えてもらい、u16の上位ビットと下位ビットを分けて出力するコードを書いてみた
    • トルエンディアンなので、下位ビットの値が配列axの先頭に入っている
use std::arch::asm;

fn main() {
    let mut x: u16 = 0xab;
    let ax: [u8; 2] = unsafe { std::mem::transmute::<u16, [u8; 2]>(x) };
    println!("{:?}", &ax); // [171, 0]
    unsafe {
        asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
    }
    let ax: [u8; 2] = unsafe { std::mem::transmute::<u16, [u8; 2]>(x) };
    println!("{:?}", &ax); // [171, 171]
    assert_eq!(x, 0xabab);
}

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。
エンディアンとかアセンブリインテル記法/AT&T記法とか、むずい...。

今週のプルリクエストはこちら。

github.com