---
title: インラインアセンブリ
url: https://doc.liz6.com/ja/rust/07-unsafe-rust/03-inline-assembly
locale: ja
area: rust
tags:
- rust
- unsafe-rust
date: 2026-06-30
modified: 2026-07-16
description: asm! マクロにより、Rust でターゲットマシンのアセンブリ命令を直接埋め込めます。制約（constraints）はレジスタの入出力関係を記述し、clobbers はどのレジスタが破壊されるかを宣言します。各アセンブリテンプレートはアーキテクチャ固有（x86_64 と ARM64 では書き方が全く異なります）であり、本質的には「この行を越えて最適化しないでください」という、コンパイラ最適化に対する壁です。
---

# インラインアセンブリ

> `asm!` マクロにより、Rust でターゲットマシンのアセンブリ命令を直接埋め込めます。制約（constraints）はレジスタの入出力関係を記述し、clobbers はどのレジスタが破壊されるかを宣言します。各アセンブリテンプレートはアーキテクチャ固有（x86_64 と ARM64 では書き方が全く異なります）であり、本質的には「この行を越えて最適化しないでください」という、コンパイラ最適化に対する壁です。

## asm! の基礎

```rust
use std::arch::asm;
let x: u64;
unsafe { asm!("rdtsc", out("rax") _, out("rdx") _, lateout("rax") x); }
// TSC (Time Stamp Counter) = EDX:EAX
// out("rax") _  — 上位32ビット、値は破棄 (_)
// out("rdx") _  — rdx の下位32ビット、破棄
// lateout("rax") x — x に結合された値
```

`asm!` は Rust 1.59+ で導入された新しいマクロです（古い `llvm_asm!` に取って代わります）。制約の妥当性をコンパイル時にチェックし、レジスタの競合、無効なオペランド、型の不一致はすべてコンパイル時に報告されます。

## 制約（Constraints）: 入出力仕様

```rust
let mut a: u64 = 4;
let b: u64 = 4;
unsafe {
    asm!(
        "add {0}, {1}",              // {0} = a, {1} = b
        inlateout(reg) a,            // a: 入力＋出力、入力とレジスタを共有しない
        in(reg) b,                   // b: 純粋な入力
    );
}
```

- `in(reg)`: 入力。コンパイラがレジスタを割り当て、値を読み込みます。
- `out(reg)`: 出力。最終値を読み取ります。
- `inout(reg)`: 入力＋出力。
- `lateout(reg)`: 出力。入力とレジスタを共有しません（入力レジスタが clobber されるシナリオ用）。
- `inlateout(reg)`: 入力＋出力。入力とレジスタを共有しません。

## Clobbers: どのレジスタが変更されるか

`out` と `lateout` は対応するレジスタを自動的に clobbered としてマークします。しかし、他の関数を呼び出す場合、ABI 全体の clobber セットをマークする必要があります。

```rust
unsafe {
    asm!(
        "call my_function",
        clobber_abi("C"),            // C 呼び出し規約の caller-saved レジスタすべてが clobbered としてマークされる
    );
}
```

## アーキテクチャ固有の条件コンパイル

```rust
#[cfg(target_arch = "x86_64")]
unsafe { asm!("rdtsc", ...); }

#[cfg(target_arch = "aarch64")]
unsafe { asm!("mrs {}, cntvct_el0", out(reg) x); }  // ARM64 のサイクルカウンター
```

## オプション

```rust
asm!("nop", options(nomem, nostack, preserves_flags));
// nomem:    メモリへの読み書きを行わない（コンパイラはキャッシュを更新しなくてもよい）
// nostack:  スタックの push/pop を行わない
// preserves_flags: EFLAGS/RFLAGS を変更しない
// pure:     副作用がない（最適化によって削除可能）
// readonly: メモリのみ読み取り
```

## 参考

- **Rust Reference**: inline assembly
- **Rust By Example**: asm

*Keywords: asm!, inline assembly, constraints, clobbers, lateout, clobber_abi, per-arch asm*
