assemblyx86cpubeginner
図で見るアセンブリ入門:種類・書き方・x86の基本
アセンブリは、CPUに近い言葉です。
はじめに
アセンブリは、CPUに近い言葉です。
普通のプログラムより、CPUが何をしているかが見えます。
人間が書くコード
↓
高級言語 C / Rust / Python
↓
アセンブリ
↓
機械語 010101...
↓
CPUが動く
この記事では、深くやりすぎずに、
- アセンブリの種類
- アセンブリの書き方
- x86の基本
- label と jmp
までを紹介します。
アセンブリとは
アセンブリは、機械語を人間が読めるようにしたものです。
機械語
10111000 00000001 00000000 00000000 00000000
↓ 人間向けにすると
アセンブリ
mov eax, 1
イメージです。
CPU「数字だけだと人間が大変そう」
人間「mov とか add なら読める」
CPU「でも最後は機械語にしてね」
アセンブリの種類
アセンブリは1種類ではありません。
CPUの種類によって、使う命令が違います。
| 種類 | よく使われる場所 | イメージ |
|---|---|---|
| x86 / x86-64 | Windows PC、Linux PC | パソコン系 |
| ARM / AArch64 | スマホ、Apple Silicon | 省電力で強い |
| RISC-V | 研究、教育、組み込み | オープンなCPU |
| MIPS | 教科書、古い機器 | 学習で見やすい |
図にするとこうです。
アセンブリ
├─ x86 / x86-64
├─ ARM / AArch64
├─ RISC-V
└─ MIPS
同じ「足し算」でも、CPUが違うと書き方が変わります。
CPUが違う
↓
命令の名前や形が違う
↓
アセンブリも違う
書き方にも種類がある
x86でも、書き方の流派があります。
| 記法 | よく見る場所 | 特徴 |
|---|---|---|
| Intel記法 | NASM、MASM | mov rax, 1 のように見やすい |
| AT&T記法 | GAS、Linuxの一部 | %rax や $1 が出る |
同じ意味でも、見た目が違います。
Intel記法
mov rax, 1
rax に 1 を入れる
AT&T記法
movq $1, %rax
1 を rax に入れる
この記事では、読みやすい Intel記法 で書きます。
アセンブリの基本形
アセンブリは、だいたいこの形です。
ラベル:
命令 目的地, 材料 ; コメント
例です。
start:
mov rax, 1 ; rax に 1 を入れる
add rax, 2 ; rax に 2 を足す
分解するとこうです。
start:
│
└─ ラベル
場所につける名前
mov rax, 1
│ │ │
│ │ └─ 材料
│ └────── 目的地
└────────── 命令
x86の考え方
x86では、CPUの中に小さな入れ物があります。
それが レジスタ です。
CPU
┌────────────────────┐
│ レジスタ │
│ ┌────┐ ┌────┐ │
│ │RAX │ │RBX │ ... │
│ └────┘ └────┘ │
└────────────────────┘
イメージです。
レジスタ = CPUのポケット
メモリ = 大きな棚
CPUは、ポケットに入れた値を使って計算します。
よく見るx86-64レジスタ
| レジスタ | よくある役割 |
|---|---|
| RAX | 計算結果を入れがち |
| RBX | 一時的な値を入れがち |
| RCX | 回数を数えるときに使いがち |
| RDX | 計算やデータで使いがち |
| RSP | スタックの位置 |
| RBP | 関数の基準位置 |
最初は全部覚えなくて大丈夫です。
まずはこれだけでOKです。
RAX = よく使う計算用の箱
基本命令
まずはこの4つだけ見るとわかりやすいです。
| 命令 | 意味 | 例 |
|---|---|---|
mov |
入れる | mov rax, 1 |
add |
足す | add rax, 2 |
sub |
引く | sub rax, 1 |
cmp |
比べる | cmp rax, 10 |
mov:値を入れる
mov rax, 10
10 ─────▶ RAX
つまり、
RAX = 10
です。
add:足す
mov rax, 10
add rax, 5
RAX = 10
RAX = RAX + 5
RAX = 15
図にするとこうです。
RAX
┌────┐
│ 10 │
└────┘
│ +5
▼
┌────┐
│ 15 │
└────┘
sub:引く
mov rax, 10
sub rax, 3
RAX = 10
RAX = RAX - 3
RAX = 7
cmp:比べる
cmp rax, 10
これは、
rax と 10 を比べる
という意味です。
ただし、答えをRAXに入れるわけではありません。
cmp は「比べた結果」をCPUのメモに残す
ざっくり図です。
cmp rax, 10
↓
CPUの中のメモ
┌─────────────┐
│ 同じ? │
│ 大きい? │
│ 小さい? │
└─────────────┘
この結果を使って、次の jmp 系の命令で移動します。
label:場所に名前をつける
labelは、コードの場所につける名前です。
start:
mov rax, 1
end:
mov rbx, 2
図にするとこうです。
start:
↓
mov rax, 1
↓
end:
↓
mov rbx, 2
labelがあると、
ここに飛びたい
ここから始めたい
ここで終わりたい
のように、場所を指定できます。
jmp:別の場所へ飛ぶ
jmp はジャンプです。
jmp end
意味は、
end というラベルへ飛ぶ
です。
例です。
start:
mov rax, 1
jmp end
mov rax, 999
end:
mov rbx, 2
流れです。
start
↓
mov rax, 1
↓
jmp end
└──────────────┐
↓
end
↓
mov rbx, 2
mov rax, 999 は飛ばされます。
jmp で飛ぶ
↓
途中の命令は実行されない
条件つきジャンプ
cmp と jmp 系を合わせると、if文みたいなことができます。
| 命令 | 意味 |
|---|---|
je |
同じなら飛ぶ |
jne |
違うなら飛ぶ |
jg |
大きいなら飛ぶ |
jl |
小さいなら飛ぶ |
例です。
mov rax, 10
cmp rax, 10
je same
mov rbx, 0
jmp end
same:
mov rbx, 1
end:
図です。
RAX == 10 ?
│
├─ yes → same へ飛ぶ → RBX = 1
│
└─ no → RBX = 0
C言語っぽく書くとこうです。
if (rax == 10) {
rbx = 1;
} else {
rbx = 0;
}
小さなまとめ
アセンブリ = CPUに近い言葉
種類
├─ x86
├─ ARM
├─ RISC-V
└─ MIPS
x86の基本
├─ mov 入れる
├─ add 足す
├─ sub 引く
├─ cmp 比べる
├─ label 場所の名前
└─ jmp 飛ぶ
最後に、この記事の内容を1枚にするとこうです。
人間のコード
↓
アセンブリ
↓
CPUの命令
CPUの中
┌──────────────┐
│ RAXなどの箱 │
└──────────────┘
命令
mov → 入れる
add → 足す
cmp → 比べる
jmp → 飛ぶ
アセンブリは難しく見えます。
でも最初は、
値を入れる
計算する
比べる
飛ぶ
だけ見ればOKです。