assembly-arm について
ARMおよびAArch64アセンブリを扱うエージェント向けのリファレンススキルです。レジスター、呼び出し規約、インラインアセンブリ、SIMDに加え、Apple Siliconの注意点やNEONからSVE2への移行も扱います。
主な機能
- 01AArch64とARM Thumbの基礎
- 02レジスターと呼び出し規約の参照
- 03GCC/Clangインラインアセンブリの解説
- 04NEON SIMD組み込み関数の例
- 05Apple SiliconとABIの注意点
- 06NEONからSVE2への移行案内
活用シーン
- 01ARM64アセンブリ出力の読解
- 02ARMインラインアセンブリの作成
- 03NEONコードのSVE2移行計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill assembly-armインストール後、Claude Code で/assembly-armを入力して読み込まれたか確認します。
同梱ファイルreferences/reference.md
詳細
ARM / AArch64 アセンブリ
目的
AArch64(64 ビット)および ARM(32 ビット Thumb)アセンブリについて、レジスター、呼び出し規約、インラインアセンブリ、NEON/SVE SIMD のパターンをエージェントに解説します。
トリガー
- 「ARM64 アセンブリの出力を読むにはどうすればよいですか?」
- 「AArch64 のレジスターと呼び出し規約は何ですか?」
- 「ARM 用のインラインアセンブリを書くにはどうすればよいですか?」
- 「AArch64 と ARM Thumb の違いは何ですか?」
- 「NEON intrinsic を使うにはどうすればよいですか?」
ワークフロー
1. ARM アセンブリを生成する
# AArch64 (native or cross-compile)
aarch64-linux-gnu-gcc -S -O2 foo.c -o foo.s
# 32-bit ARM Thumb
arm-linux-gnueabihf-gcc -S -O2 -mthumb foo.c -o foo.s
# From objdump
aarch64-linux-gnu-objdump -d -S prog
# From GDB on target
(gdb) disassemble /s main
2. AArch64 レジスター(AAPCS64)
| レジスター | 別名 | 役割 |
|---|---|---|
x0–x7 | — | 引数 1~8 と戻り値 |
x8 | xr | 間接結果の格納場所(構造体の戻り値) |
x9–x15 | — | 呼び出し元保存の一時レジスター |
x16–x17 | ip0、ip1 | プロシージャー呼び出し間の一時レジスター(リンカーが使用) |
x18 | pr | プラットフォームレジスター(一部の OS では予約済み) |
x19–x28 | — | 呼び出し先保存 |
x29 | fp | フレームポインター(呼び出し先保存) |
x30 | lr | リンクレジスター(戻りアドレス) |
sp | — | スタックポインター(呼び出し時に 16 バイト境界に整列する必要あり) |
pc | — | プログラムカウンター(直接アクセス不可) |
xzr | wzr | ゼロレジスター(読み出し値は 0、書き込みは破棄) |
v0–v7 | q0–q7 | FP/SIMD の引数と戻り値 |
v8–v15 | — | 呼び出し先保存の SIMD レジスター(下位 64 ビットのみ) |
v16–v31 | — | 呼び出し元保存の一時レジスター |
幅のバリエーション:x0(64 ビット)、w0(32 ビット、64 ビットにゼロ拡張)、h0(16 ビット)、b0(8 ビット)。
3. AAPCS64 呼び出し規約
整数/ポインター引数: x0–x7
浮動小数点/SIMD 引数: v0–v7
戻り値: x0(整数)、x0+x1(128 ビット)、v0(浮動小数点/SIMD)
呼び出し先保存: x19–x28、x29(fp)、x30(lr)、v8–v15(下位 64 ビット)
呼び出し元保存: その他すべて
bl または blr 命令の実行時、スタックは 16 バイト境界に整列している必要があります。
4. よく使われる AArch64 命令
| 命令 | 効果 |
|---|---|
mov x0, x1 | レジスターをコピー |
mov x0, #42 | 即値をロード |
movz x0, #0x1234, lsl #16 | ゼロ拡張してシフトしながら移動 |
movk x0, #0xabcd | 値を保持しながら移動(一部を更新) |
ldr x0, [x1] | x1 のアドレスから 64 ビット値をロード |
ldr x0, [x1, #8] | x1+8 からロード |
str x0, [x1, #8] | x0 を x1+8 に格納 |
ldp x0, x1, [sp, #16] | ペアをロード(2 つのレジスターを同時に) |
stp x29, x30, [sp, #-16]! | ペアを格納し、sp を事前に減算 |
add x0, x1, x2 | x0 = x1 + x2 |
add x0, x1, #8 | x0 = x1 + 8 |
sub x0, x1, x2 | x0 = x1 - x2 |
mul x0, x1, x2 | x0 = x1 * x2 |
sdiv x0, x1, x2 | 符号付き除算 |
udiv x0, x1, x2 | 符号なし除算 |
cmp x0, x1 | x0 - x1 のフラグを設定 |
cbz x0, label | x0 == 0 の場合に分岐 |
cbnz x0, label | x0 != 0 の場合に分岐 |
bl func | リンク付きで分岐(呼び出し) |
blr x0 | x0 のアドレスへリンク付きで分岐 |
ret | 戻る(x30 へ分岐) |
ret x0 | x0 のアドレスへ戻る |
adrp x0, symbol | PC 相対のページアドレス |
add x0, x0, :lo12:symbol | symbol のオフセットの下位 12 ビット |
5. 典型的な関数のプロローグ/エピローグ
// Non-leaf function
stp x29, x30, [sp, #-32]! // save fp, lr; allocate 32 bytes
mov x29, sp // set frame pointer
stp x19, x20, [sp, #16] // save callee-saved registers
// ... body ...
ldp x19, x20, [sp, #16] // restore
ldp x29, x30, [sp], #32 // restore fp, lr; deallocate
ret
// Leaf function (no calls, no callee-saved regs needed)
// Can use red zone (no rsp adjustment) — but AArch64 has no red zone
sub sp, sp, #16 // allocate locals
// ... body ...
add sp, sp, #16
ret
6. インラインアセンブリ(GCC/Clang)
// Barrier
__asm__ volatile ("dmb ish" ::: "memory");
// Load acquire
static inline int load_acquire(volatile int *p) {
int val;
__asm__ volatile ("ldar %w0, %1" : "=r"(val) : "Q"(*p));
return val;
}
// Store release
static inline void store_release(volatile int *p, int val) {
__asm__ volatile ("stlr %w1, %0" : "=Q"(*p) : "r"(val));
}
// Read system counter
static inline uint64_t read_cntvct(void) {
uint64_t val;
__asm__ volatile ("mrs %0, cntvct_el0" : "=r"(val));
return val;
}
AArch64 固有の制約:
"Q"— 排他/取得/解放命令に適したメモリーオペランド"r"— 任意の汎用レジスター"w"— 任意の FP/SIMD レジスター
7. NEON SIMD intrinsic
#include <arm_neon.h>
// Add 4 floats at once
float32x4_t a = vld1q_f32(arr_a); // load 4 floats
float32x4_t b = vld1q_f32(arr_b);
float32x4_t c = vaddq_f32(a, b);
vst1q_f32(result, c);
// Horizontal sum
float32x4_t sum = vpaddq_f32(c, c);
sum = vpaddq_f32(sum, sum);
float total = vgetq_lane_f32(sum, 0);
命名規則:v<op><q>_<type>
q接尾辞:128 ビット(クアッド)ベクトル_f32:float32、_s32:int32、_u8:uint8 など
8. Darwin と Linux の AArch64 ABI の違い
| 項目 | Linux(AAPCS64) | Apple Darwin(arm64) |
|---|---|---|
| スタックの整列 | 公開インターフェースで 16 バイト | 16 バイト |
| レッドゾーン | SP の下に 128 バイト | レッドゾーンなし |
x18 レジスター | プラットフォーム予約済み(TLS) | プラットフォームレジスター(使用しないこと) |
| 可変長引数 | x0–x7、続いてスタック | 同じ。ただし objc_msgSend の規約は異なる |
| 名前修飾 | Itanium C++ ABI | 同じ + Apple blocks |
macOS/iOS では、x18 の使用を避け、プラットフォーム型には _DARWIN_C_LEVEL ヘッダーを使用してください。
9. AMX の概要(Apple Silicon)
Apple Matrix Coprocessor(AMX)は、公開されている組み込み関数を通じて利用できません。アクセス方法:
// Practical: Accelerate/vecLib uses AMX internally
#include <Accelerate/Accelerate.h>
// cblas_sgemm, vDSP_* dispatch to AMX on M-series
// Low-level: community-documented opcodes — not portable, avoid in production
Apple Silicon で行列演算を行う場合は、Metal Performance Shaders または Accelerate を使用してください(skills/platform/apple-silicon)。
10. Apple M シリーズの 16KB ページサイズ
Apple Silicon 上の macOS では、4KB ではなく 16KB ページが使用されます:
#include <unistd.h>
long page = sysconf(_SC_PAGESIZE); // 16384 on macOS arm64
// Align mmap and posix_memalign to page size
PAGE_SIZE == 4096 を前提とするコードは、バッファーのアラインメントがずれたり、macOS で mmap が失敗したりする可能性があります。
11. NEON から SVE2 への移行のヒント
Porting checklist
├── Replace 128-bit fixed loops with svcnt*() strides on SVE hardware
├── Use predicates (svwhilelt) for tails instead of scalar epilogues
├── Guard SVE code with #ifdef __ARM_FEATURE_SVE
└── Keep NEON path for Apple M1–M3 (no SVE); use SVE2 on Graviton/M4+
SVE の組み込み関数と自動ベクトル化フラグについては、skills/platform/arm-sve を参照してください。
レジスターのリファレンスについては、references/reference.md を参照してください。
関連スキル
- x86-64 アセンブリーには、
skills/low-level-programming/assembly-x86を使用してください - クロスコンパイルツールチェーンには、
skills/compilers/cross-gccを使用してください - gdbserver を使用した ARM コードのデバッグには、
skills/debuggers/gdbを使用してください - SVE/SVE2 のスケーラブルベクトルには、
skills/platform/arm-sveを使用してください - M シリーズのユニファイドメモリーと AMX には、
skills/platform/apple-siliconを使用してください