📘

アセンブラチートシート

に公開

アセンブラ完全ガイド

予約語とオペランド一覧表

データ移動命令

予約語 オペランド形式 説明 使用例
mov dest, src データを移動/コピー mov rax, 5
movsx dest, src 符号拡張付き移動 movsx rax, al
movzx dest, src ゼロ拡張付き移動 movzx rax, al
lea dest, [addr] 実効アドレスを読み込み lea rax, [rbx+8]
xchg op1, op2 二つの値を交換 xchg rax, rbx

算術演算命令

予約語 オペランド形式 説明 使用例
add dest, src 加算 add rax, 10
sub dest, src 減算 sub rax, rbx
mul src 符号なし乗算 mul rbx
imul dest, src または src 符号付き乗算 imul rax, 5
div src 符号なし除算 div rbx
idiv src 符号付き除算 idiv rcx
inc dest インクリメント inc rax
dec dest デクリメント dec rbx
neg dest 符号反転 neg rax

ビット演算命令

予約語 オペランド形式 説明 使用例
and dest, src 論理積 and rax, 0xFF
or dest, src 論理和 or rax, rbx
xor dest, src 排他的論理和 xor rax, rax
not dest ビット反転 not rax
shl dest, count 左シフト shl rax, 2
shr dest, count 右シフト(論理) shr rax, 1
sar dest, count 右シフト(算術) sar rax, 3
rol dest, count 左ローテート rol rax, 4
ror dest, count 右ローテート ror rax, 2

比較・テスト命令

予約語 オペランド形式 説明 使用例
cmp op1, op2 比較(減算結果でフラグ設定) cmp rax, 10
test op1, op2 テスト(AND結果でフラグ設定) test rax, rax

条件分岐命令

予約語 オペランド形式 条件 説明 使用例
je / jz label ZF=1 等しい/ゼロ je equal
jne / jnz label ZF=0 等しくない/非ゼロ jne not_equal
jg / jnle label ZF=0 and SF=OF より大きい(符号付き) jg greater
jge / jnl label SF=OF 以上(符号付き) jge greater_equal
jl / jnge label SF≠OF より小さい(符号付き) jl less
jle / jng label ZF=1 or SF≠OF 以下(符号付き) jle less_equal
ja / jnbe label CF=0 and ZF=0 より大きい(符号なし) ja above
jae / jnb label CF=0 以上(符号なし) jae above_equal
jb / jnae label CF=1 より小さい(符号なし) jb below
jbe / jna label CF=1 or ZF=1 以下(符号なし) jbe below_equal
jc label CF=1 キャリーフラグセット jc carry_set
jnc label CF=0 キャリーフラグクリア jnc no_carry
jo label OF=1 オーバーフロー jo overflow
jno label OF=0 オーバーフローなし jno no_overflow
js label SF=1 符号フラグセット js negative
jns label SF=0 符号フラグクリア jns positive

無条件分岐・制御命令

予約語 オペランド形式 説明 使用例
jmp label または addr 無条件ジャンプ jmp start
call label または addr 関数呼び出し call function
ret なし または imm16 関数から戻る ret
loop label RCXをデクリメントして条件ジャンプ loop loop_start
loope / loopz label 等しい間ループ loope equal_loop
loopne / loopnz label 等しくない間ループ loopne not_equal_loop

スタック操作命令

予約語 オペランド形式 説明 使用例
push src スタックにプッシュ push rax
pop dest スタックからポップ pop rbx
pushf / pushfq なし フラグレジスタをプッシュ pushfq
popf / popfq なし フラグレジスタをポップ popfq
pusha / pushad なし 全汎用レジスタをプッシュ pushad
popa / popad なし 全汎用レジスタをポップ popad

文字列操作命令

予約語 オペランド形式 説明 使用例
movs なし 文字列移動 movsb
stos なし 文字列格納 stosb
lods なし 文字列読み込み lodsb
scas なし 文字列検索 scasb
cmps なし 文字列比較 cmpsb
rep prefix 反復プリフィックス rep movsb
repe / repz prefix 等しい間反復 repe cmpsb
repne / repnz prefix 等しくない間反復 repne scasb

システム制御命令

予約語 オペランド形式 説明 使用例
nop なし 何もしない nop
hlt なし ハルト(停止) hlt
int imm8 割り込み int 0x80
iret / iretq なし 割り込みから戻る iretq
cli なし 割り込み禁止 cli
sti なし 割り込み許可 sti
cld なし 方向フラグクリア cld
std なし 方向フラグセット std
clc なし キャリーフラグクリア clc
stc なし キャリーフラグセット stc

条件設定命令

予約語 オペランド形式 条件 説明 使用例
sete / setz dest ZF=1 等しければ1を設定 sete al
setne / setnz dest ZF=0 等しくなければ1を設定 setne bl
setg / setnle dest ZF=0 and SF=OF より大きければ1を設定 setg cl
setl / setnge dest SF≠OF より小さければ1を設定 setl dl

浮動小数点命令(x87 FPU)

予約語 オペランド形式 説明 使用例
fld src 浮動小数点数をロード fld qword [rax]
fst dest 浮動小数点数を格納 fst dword [rbx]
fstp dest 格納してポップ fstp qword [rcx]
fadd src または st(i) 加算 fadd st(1)
fsub src または st(i) 減算 fsub dword [rax]
fmul src または st(i) 乗算 fmul st(2)
fdiv src または st(i) 除算 fdiv qword [rbx]

SSE命令(一部)

予約語 オペランド形式 説明 使用例
movss dest, src 単精度浮動小数点移動 movss xmm0, xmm1
movsd dest, src 倍精度浮動小数点移動 movsd xmm0, [rax]
addss dest, src 単精度加算 addss xmm0, xmm1
addsd dest, src 倍精度加算 addsd xmm0, [rbx]
subss dest, src 単精度減算 subss xmm0, xmm1
mulss dest, src 単精度乗算 mulss xmm0, xmm1
divss dest, src 単精度除算 divss xmm0, xmm1

アセンブラの使い方

1. 基本的な文法

; コメントはセミコロンで開始
label:              ; ラベル定義
    instruction operand1, operand2  ; 命令

2. セクション定義

.section .data      ; データセクション
    variable: .quad 100     ; 64ビット変数
    string: .ascii "Hello"  ; 文字列

.section .bss       ; 未初期化データセクション
    buffer: .space 256      ; 256バイトのバッファ

.section .text      ; コードセクション
.global _start      ; エントリーポイント
_start:
    ; プログラム開始

3. データ型定義

疑似命令 サイズ 説明 使用例
.byte 1バイト バイトデータ .byte 0x41
.word 2バイト ワードデータ .word 1000
.dword / .long 4バイト ダブルワード .dword 100000
.qword / .quad 8バイト クワッドワード .quad 1000000000
.ascii 可変 ASCII文字列 .ascii "Hello"
.asciz / .string 可変 NULL終端文字列 .asciz "World"
.space / .skip 可変 未初期化領域 .space 100

4. 実践例

基本的なプログラム構造

.section .data
    msg: .asciz "Hello, World!\n"
    msg_len = . - msg - 1

.section .text
.global _start

_start:
    ; write システムコール
    mov rax, 1          ; sys_write
    mov rdi, 1          ; stdout
    mov rsi, msg        ; メッセージのアドレス
    mov rdx, msg_len    ; メッセージの長さ
    syscall             ; システムコール実行
    
    ; exit システムコール
    mov rax, 60         ; sys_exit
    mov rdi, 0          ; 終了コード
    syscall

ループの実装

.section .text
.global _start

_start:
    mov rcx, 10         ; カウンタを10に設定
    mov rax, 0          ; 累積値を0に初期化

loop_start:
    add rax, rcx        ; RAXにRCXを加算
    dec rcx             ; カウンタをデクリメント
    jnz loop_start      ; カウンタが0でなければループ継続
    
    ; RAXには1+2+3+...+10 = 55が格納される

条件分岐の実装

.section .text
.global _start

_start:
    mov rax, 15         ; テスト値
    cmp rax, 10         ; 10と比較
    
    jl  less_than_10    ; 10未満の場合
    je  equal_to_10     ; 10と等しい場合
    jg  greater_than_10 ; 10より大きい場合

less_than_10:
    mov rbx, 1          ; 1を設定
    jmp end

equal_to_10:
    mov rbx, 2          ; 2を設定
    jmp end

greater_than_10:
    mov rbx, 3          ; 3を設定

end:
    ; RBXには結果が格納される

関数の実装

.section .text
.global _start

_start:
    mov rdi, 5          ; 第1引数
    mov rsi, 3          ; 第2引数
    call add_function   ; 関数呼び出し
    
    ; RAXには結果が格納される
    mov rdi, rax        ; 終了コード
    mov rax, 60         ; sys_exit
    syscall

add_function:
    push rbp            ; ベースポインタ保存
    mov rbp, rsp        ; 新しいフレーム設定
    
    mov rax, rdi        ; 第1引数をRAXに
    add rax, rsi        ; 第2引数を加算
    
    mov rsp, rbp        ; スタック復元
    pop rbp             ; ベースポインタ復元
    ret                 ; 呼び出し元に戻る

5. アセンブル・リンク手順

GASを使用した場合

# アセンブル
as -64 program.s -o program.o

# リンク
ld program.o -o program

# 実行
./program

NASMを使用した場合

# アセンブル
nasm -f elf64 program.asm -o program.o

# リンク
ld program.o -o program

# 実行
./program

6. デバッグのコツ

GDBでのデバッグ

# デバッグ情報付きでアセンブル
as -64 --gstabs program.s -o program.o
ld program.o -o program

# GDBで実行
gdb ./program

# GDB内でのコマンド
(gdb) break _start      # ブレークポイント設定
(gdb) run              # 実行
(gdb) stepi            # 1命令ずつ実行
(gdb) info registers   # レジスタ表示
(gdb) x/10x $rsp       # スタック内容表示

7. よく使われるパターン

レジスタのクリア

xor rax, rax    ; RAXを0にクリア(高速)
mov rax, 0      ; RAXを0に設定(通常)

文字列の長さ計算

mov rdi, string     ; 文字列のアドレス
mov rcx, -1         ; 最大長
mov al, 0           ; NULL文字
cld                 ; 前進方向
repne scasb         ; NULL文字を検索
not rcx             ; 長さを計算
dec rcx             ; NULL文字分を除く

メモリのクリア

mov rdi, buffer     ; バッファのアドレス
mov rcx, 256        ; クリアするバイト数
xor rax, rax        ; 0で埋める
rep stosb           ; メモリをクリア

レジスタ一覧

x86-64 汎用レジスタ

64ビット 32ビット 16ビット 8ビット(上位) 8ビット(下位) 用途
RAX EAX AX AH AL アキュムレータ
RBX EBX BX BH BL ベース
RCX ECX CX CH CL カウンタ
RDX EDX DX DH DL データ
RSI ESI SI - SIL ソースインデックス
RDI EDI DI - DIL デスティネーションインデックス
RSP ESP SP - SPL スタックポインタ
RBP EBP BP - BPL ベースポインタ
R8 R8D R8W - R8B 汎用レジスタ
R9 R9D R9W - R9B 汎用レジスタ
R10 R10D R10W - R10B 汎用レジスタ
R11 R11D R11W - R11B 汎用レジスタ
R12 R12D R12W - R12B 汎用レジスタ
R13 R13D R13W - R13B 汎用レジスタ
R14 R14D R14W - R14B 汎用レジスタ
R15 R15D R15W - R15B 汎用レジスタ

フラグレジスタ(RFLAGS)

ビット フラグ 名称 説明
0 CF キャリーフラグ 演算でキャリー/ボローが発生
2 PF パリティフラグ 結果の下位8ビットの1の個数が偶数
4 AF 補助キャリーフラグ BCD演算でキャリーが発生
6 ZF ゼロフラグ 演算結果が0
7 SF 符号フラグ 演算結果が負
8 TF トラップフラグ シングルステップモード
9 IF 割り込みフラグ 割り込み許可
10 DF 方向フラグ 文字列操作の方向
11 OF オーバーフローフラグ 符号付き演算でオーバーフロー

セグメントレジスタ

レジスタ 名称 用途
CS コードセグメント 実行中のコード
DS データセグメント データアクセス
ES エクストラセグメント 追加のデータアクセス
FS ファイルセグメント スレッドローカルストレージ
GS ジェネラルセグメント 追加用途
SS スタックセグメント スタック操作

浮動小数点レジスタ

x87 FPU レジスタ

  • ST(0) - ST(7): 80ビット浮動小数点レジスタスタック

SSE/AVX レジスタ

  • XMM0 - XMM15: 128ビット(SSE)
  • YMM0 - YMM15: 256ビット(AVX)
  • ZMM0 - ZMM31: 512ビット(AVX-512)

アドレッシングモード

即値アドレッシング

mov rax, 100        ; 即値100をRAXに格納

レジスタアドレッシング

mov rax, rbx        ; RBXの値をRAXにコピー

直接アドレッシング

mov rax, [1000]     ; メモリアドレス1000の値をRAXに読み込み

間接アドレッシング

mov rax, [rbx]      ; RBXが指すアドレスの値をRAXに読み込み

ベース+ディスプレースメント

mov rax, [rbx+8]    ; RBX+8のアドレスの値を読み込み

ベース+インデックス

mov rax, [rbx+rcx]  ; RBX+RCXのアドレスの値を読み込み

ベース+インデックス+スケール

mov rax, [rbx+rcx*2]    ; RBX+(RCX*2)のアドレスの値を読み込み
mov rax, [rbx+rcx*4+8]  ; RBX+(RCX*4)+8のアドレスの値を読み込み

システムコール(Linux x86-64)

主要なシステムコール

番号 名前 引数 説明
0 sys_read rdi=fd, rsi=buf, rdx=count ファイル読み込み
1 sys_write rdi=fd, rsi=buf, rdx=count ファイル書き込み
2 sys_open rdi=filename, rsi=flags, rdx=mode ファイルオープン
3 sys_close rdi=fd ファイルクローズ
9 sys_mmap 複数の引数 メモリマップ
11 sys_munmap rdi=addr, rsi=length メモリアンマップ
39 sys_getpid なし プロセスID取得
57 sys_fork なし プロセス複製
59 sys_execve rdi=filename, rsi=argv, rdx=envp プログラム実行
60 sys_exit rdi=status プロセス終了

システムコールの使用例

; Hello World を出力
.section .data
    msg: .asciz "Hello, World!\n"
    msg_len = . - msg - 1

.section .text
.global _start

_start:
    ; write(1, msg, msg_len)
    mov rax, 1          ; sys_write
    mov rdi, 1          ; stdout
    mov rsi, msg        ; メッセージ
    mov rdx, msg_len    ; 長さ
    syscall
    
    ; exit(0)
    mov rax, 60         ; sys_exit
    mov rdi, 0          ; 終了ステータス
    syscall

アセンブリの読み方・考え方

1. 読み方の基本原則

トップダウン方式

main:               ; 1. まずメイン関数を見つける
    call setup      ; 2. 初期化処理を確認
    call process    ; 3. メイン処理を確認
    call cleanup    ; 4. 終了処理を確認
    ret

ボトムアップ方式

; 1. 個別の関数から理解していく
multiply:
    push rbp
    mov rbp, rsp
    ; この関数が何をするか理解
    pop rbp
    ret

; 2. それらがどう組み合わされるか把握

2. 読み方の手順

ステップ1: 全体構造の把握

.section .data      ; データ領域を確認
.section .bss       ; 未初期化領域を確認  
.section .text      ; コード領域を確認

ステップ2: エントリーポイントの特定

.global _start      ; プログラムの開始点
_start:
    ; ここから実行が始まる

ステップ3: データ構造の理解

.section .data
    array: .quad 1, 2, 3, 4, 5    ; 配列
    counter: .long 0              ; カウンタ変数
    message: .asciz "Hello"       ; 文字列

ステップ4: 制御フローの追跡

    cmp rax, 0          ; 比較
    je zero_case        ; 条件分岐
    jmp normal_case     ; 無条件分岐

3. 考え方のコツ

レジスタの役割を意識する

; x86-64の一般的な使い方
mov rdi, arg1       ; 第1引数
mov rsi, arg2       ; 第2引数  
mov rdx, arg3       ; 第3引数
call function       ; 関数呼び出し
mov result, rax     ; 戻り値を保存

スタックの動きを追跡する

push rbp            ; ベースポインタ保存
mov rbp, rsp        ; 新しいフレーム作成
sub rsp, 16         ; ローカル変数用領域確保
; 処理...
add rsp, 16         ; スタック復元
pop rbp             ; ベースポインタ復元
ret                 ; 関数終了

メモリレイアウトを意識する

; 高位アドレス
; +--------+
; |  引数  |
; +--------+
; |戻りアドレス|
; +--------+
; |旧RBP   | <- RBP
; +--------+
; |ローカル変数|
; +--------+ <- RSP
; 低位アドレス

4. パターン認識

典型的な関数プロローグ

function:
    push rbp        ; 関数開始の定型文
    mov rbp, rsp    ; スタックフレーム設定
    sub rsp, N      ; ローカル変数確保

典型的な関数エピローグ

    add rsp, N      ; スタック復元
    pop rbp         ; ベースポインタ復元
    ret             ; 関数終了の定型文

ループパターンの認識

    mov rcx, 10     ; カウンタ初期化
loop_start:
    ; 処理内容
    dec rcx         ; カウンタ減算
    jnz loop_start  ; 条件ループ

条件分岐パターン

    cmp rax, rbx    ; 比較
    jl less_case    ; 分岐1
    je equal_case   ; 分岐2  
    ; else case      ; デフォルトケース

アセンブリあるある集

初心者あるある

1. レジスタサイズ混同あるある

; ❌ 混同しがち
mov eax, 0x100000000    ; 32ビットレジスタに64ビット値
mov al, 256             ; 8ビットレジスタに9ビット値

; ✅ 正しい使い方
mov rax, 0x100000000    ; 64ビット値は64ビットレジスタに
mov al, 255             ; 8ビット値は8ビットレジスタに

2. アドレッシングモード間違いあるある

; ❌ よくある間違い
mov rax, 100        ; 即値100をRAXに
mov rbx, rax        ; RAXの値をRBXに
mov rcx, [100]      ; アドレス100の値をRCXに(混同)

; ✅ 正しい理解
mov rax, 100        ; RAX = 100(即値)
mov rbx, [100]      ; RBX = メモリ[100]の値(間接参照)

3. スタック操作忘れあるある

; ❌ スタック不均衡
function:
    push rbp
    push rbx
    ; 処理...
    pop rbp         ; 順序が間違い!
    ret

; ✅ 正しいスタック操作
function:
    push rbp
    push rbx
    ; 処理...
    pop rbx         ; 逆順でポップ
    pop rbp
    ret

中級者あるある

4. フラグレジスタ忘れあるある

; ❌ フラグが上書きされる
cmp rax, 10
mov rbx, 5          ; movはフラグに影響しない(OK)
add rcx, 1          ; addはフラグを変更!(危険)
je equal_case       ; 間違ったフラグで判定

; ✅ フラグを意識した書き方
cmp rax, 10
je equal_case       ; 比較直後に分岐

5. 関数呼び出し規約混同あるある

; ❌ System V ABIとWindows ABIの混同
; System V (Linux): RDI, RSI, RDX, RCX, R8, R9
; Windows x64: RCX, RDX, R8, R9

; 環境を意識した呼び出し

6. オーバーフロー軽視あるある

; ❌ オーバーフローチェック忘れ
add rax, rbx
; オーバーフローしたらどうなる?

; ✅ オーバーフロー対策
add rax, rbx
jo overflow_handler  ; オーバーフローをチェック

上級者あるある

7. 最適化の逆効果あるある

; ❌ 過度な最適化で可読性低下
xor rax, rax        ; RAX = 0(高速だが分かりにくい)
lea rbx, [rax+1]    ; RBX = 1(トリッキー)

; ✅ 適度な最適化
mov rax, 0          ; 明確
mov rbx, 1          ; 理解しやすい

8. アラインメント問題あるある

; ❌ アラインメントを考慮しない
.section .data
    char_val: .byte 1
    int_val: .long 100      ; 4バイト境界に来ない可能性

; ✅ アラインメントを意識
.section .data
    char_val: .byte 1
    .align 4                ; 4バイト境界に調整
    int_val: .long 100

9. キャッシュライン意識あるある

; CPUキャッシュを意識したデータ配置
.section .data
.align 64               ; キャッシュライン境界
hot_data:              ; 頻繁にアクセスするデータ
    .quad 1, 2, 3, 4
cold_data:             ; あまり使わないデータ  
    .quad 100, 200, 300, 400

デバッグあるある

10. セグメンテーションフォルト頻発あるある

; ❌ よくあるSegFaultの原因
mov rax, 0
mov [rax], 100      ; NULL pointer dereference

mov rsp, 0x1000     ; 不正なスタックポインタ
ret                 ; クラッシュ

; ✅ 安全なメモリアクセス
cmp rax, 0
je null_check       ; NULLチェック
mov [rax], 100

11. 無限ループ作成あるある

; ❌ 終了条件ミス
mov rcx, 10
loop_start:
    ; 処理...
    inc rcx             ; カウンタを増加(間違い)
    cmp rcx, 0
    jne loop_start      ; 永続ループ

; ✅ 正しいループ
mov rcx, 10
loop_start:
    ; 処理...
    dec rcx             ; カウンタを減少
    jnz loop_start      ; ゼロでなければ継続

プロあるある

12. コンパイラ出力解読あるある

; コンパイラが生成したコード
lea rax, [rdi+rdi*2]    ; RAX = RDI * 3(効率的な乗算)
sal rdi, 2              ; RDI = RDI * 4(左シフト)

13. インラインアセンブリ落とし穴あるある

// C言語でのインラインアセンブリ
asm volatile ("mov %1, %0"
              : "=r" (output)
              : "r" (input)
              : "memory");

14. アーキテクチャ依存コードあるある

; x86特有の命令(他のアーキテクチャでは動かない)
bswap rax           ; バイトスワップ(x86のみ)
xlat                ; テーブル参照変換(x86のみ)

現実世界のあるある

15. デバッガとの格闘あるある

# GDBでよくやること
(gdb) x/10x $rsp        # スタック内容確認
(gdb) info registers    # レジスタ一覧
(gdb) disas main        # 逆アセンブル

16. パフォーマンス測定あるある

; 測定用のコード挿入
rdtsc               ; タイムスタンプカウンタ読み取り
mov r15, rax        ; 開始時刻保存
; 測定対象の処理
rdtsc               ; 終了時刻
sub rax, r15        ; 経過サイクル計算

17. リバースエンジニアリングあるある

; よく見かける最適化パターン
test rax, rax       ; raxが0かチェック(cmp rax, 0と同じ)
jz zero_case        ; ゼロなら分岐

xor rax, rax        ; rax = 0(mov rax, 0より短い)

トラブルシューティング

よくあるエラーと対策

エラー 原因 対策
Segmentation fault 不正メモリアクセス NULLチェック、境界チェック
Stack overflow スタック溢れ 再帰深度制限、局所変数削減
Illegal instruction 未対応命令 CPUサポート確認
Bus error アラインメント違反 データ境界調整

デバッグ手法

; デバッグ用の仕込み
debug_print:
    push rax
    push rdi
    push rsi
    push rdx
    ; レジスタ値を出力
    pop rdx
    pop rsi  
    pop rdi
    pop rax
    ret

このガイドを参考に、アセンブラプログラミングの基本から応用、そして現実的な問題まで習得できます。実際のプログラミングでは、使用するアーキテクチャ(x86-64、ARM、RISC-V等)に応じて命令セットが異なることに注意してください。

Discussion