回 3-5 道 3 コンピュータの中
機械語は、CPU が
読み終えたら1 行の
この頁の流れ
1 行のコードと、
1 行の 足し算は、 CPU に とって 何個の仕事か
c = a + b の 1 行は、CPU (コンピュータの
CPU は、変数の名前も = の
CPU は どうやって 命令を 実行するのか
CPU は、メモリから命令を 1 つ取り出し、
機械語は数の並び
機械語は、
この
| オペコード (16 進) | 名前 | すること |
|---|---|---|
| 10 | LOAD A | 番地の |
| 11 | LOAD B | 番地の |
| 20 | ADD A,B | A と |
| 30 | STORE A | A の |
| 01 | HALT | 止まる |
レジスタは、c = a + b を
動かす c = a + b を機械語にする
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
10 0a LOAD A 10
11 0b LOAD B 11
20 00 ADD A,B 0
30 0c STORE A 12
01 00 HALT 0
10 0a 11 0b 20 00 30 0c 01 00
10 バイト1 行が 1 命令で、左の 2 つの 16 進数が10 0a 11 0b … が、= も
取り出す、 解読する、 実行する、次へ進む
CPU は、
| 段 | すること | 模型で言うと |
|---|---|---|
| 取り出す | PC が | mem[pc] と mem[pc + 1] を読む |
| 解読する | 何の | オペコードが |
| 実行する | 命令の | レジスタや |
| 次へ進む | PC を | PC に |
下の図を 1 段ずつ進めると、
命令も
アセンブリ言語は 機械語に 名前を付けた物
アセンブリ言語は、
プログラムの
| 言葉 | 例 | 1 行が表す物 |
|---|---|---|
| 機械語 | 10 0a | CPU の |
| アセンブリ言語 | LOAD A 10 | CPU の |
| 高水準言語 | c = a + b | 命令いく |
C 言語のような
本物の CPU では 何個の 命令になるか
本物のuname -m が
add.c
int a = 5, b = 3, c = 0;
void f(void) {
c = a + b;
}道具はcc -O1 -S add.c は
cc -O1 -S の結果 (arm64)
adrp x8, _a@PAGE
ldr w8, [x8, _a@PAGEOFF]
adrp x9, _b@PAGE
ldr w9, [x9, _b@PAGEOFF]
add w8, w9, w8
adrp x9, _c@PAGE
str w8, [x9, _c@PAGEOFF]
retこのret は数えず、c = a + b のadrp (変数のあるldr (読み込み) が 2 回、add (足し算) が 1 回、str (
同じcc -O1 -c add.c でobjdump -d add.o で
objdump -d の結果 (arm64)
0: 90000008 adrp x8, 0x0
4: b9400108 ldr w8, [x8]
8: 90000009 adrp x9, 0x0
c: b9400129 ldr w9, [x9]
10: 0b080128 add w8, w9, w8
14: 90000009 adrp x9, 0x0
18: b9000128 str w8, [x9]
1c: d65f03c0 ret左から、0x0 のように
真ん中の 90000008 は、objdump -s で
objdump -s の結果 (1 行を 2 行に折った)
0000 08000090 080140b9
09000090 290140b9
0010 2801080b 09000090
280100b9 c0035fd690000008 は、
同じcc -O1 -fomit-frame-pointer -target x86_64-apple-macos で
cc -S の結果 (x86_64)
movl _b(%rip), %eax
addl _a(%rip), %eax
movl %eax, _c(%rip)
retqobjdump -d の結果 (x86_64)
0: 8b 05 00 00 00 00 movl
6: 03 05 00 00 00 00 addl
c: 89 05 00 00 00 00 movl
12: c3 retqx86_64 では、retq をaddl が
| 書いた所 | c = a + b の命令の数 | 1 命令の長さ |
|---|---|---|
| この頁の模型 | 4 | 2 バイト |
| arm64 (上の cc) | 7 | 4 バイト |
| x86_64 (上の cc) | 3 | 6 バイト (retq は 1) |
動かして確かめる
模型の CPU を Python でbytearray (0〜255 の
動かす 1 命令ずつ進める
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
0 10 0a LOAD A 5 0
2 11 0b LOAD B 5 3
4 20 00 ADD A,B 8 3
6 30 0c STORE A 8 3
8 01 00 HALT
c = 8左から
次に、+ が
動かす 1 行を命令に直して数える
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
c = a + b → 4
LOAD A a
LOAD B b
ADD A,B
STORE A c
d = a + b + c → 6
LOAD A a
LOAD B b
ADD A,B
LOAD B c
ADD A,B
STORE A d
e = a → 2
LOAD A a
STORE A e右辺の名前が 1 つ増えるc = a + b は 4、3 個の d = a + b + c は 6、1 個の e = a は
前提が 崩れると 何が起きるか
CPU は、
壊れた 命令と、 ずれた PC
模型を関数にまとめ、
動かす 壊れた命令とずれた PC
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
ff は命令に無い c = 0
00 は命令に無い c = 8
0a は命令に無い c = 01 つ目は、
2 つ目は、
3 つ目は、
8 ビットの レジスタからあふれる
模型の& 0xFF (下の
動かす 8 ビットのレジスタで足す
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
5 + 3 → 8 000001000
200 + 50 → 250 011111010
200 + 100 → 44 100101100
255 + 1 → 0 100000000右の
崩れる
- メモリの中身は
正しい 命令だ、という前提 - PC は
命令の 頭を 指し、 止まる 命令が ある、という前提 - 計算の
結果は レジスタに 入る、という 前提。 8 ビットなら 256 以上はこぼれる
仕事で どう 確かめるか
仕事では、
1 つ目は、cc -O1 -S で
2 つ目は、objdump -d で
3 つ目は、どの CPU 向けかをfile add.o add86.o を打つと、Mach-O 64-bit object arm64 と Mach-O 64-bit object x86_64 と
Python の dis でdis.dis("c = a + b") を
Python 3.14 の dis の結果
0 RESUME 0
1 LOAD_NAME 0 (a)
LOAD_NAME 1 (b)
BINARY_OP 0 (+)
STORE_NAME 2 (c)
LOAD_CONST 0 (None)
RETURN_VALUELOAD、
関わる実例
模型の CPU は命令を 1 つずつ順番に
Spectre と Meltdown (2018 年 1 月公表)
Google の
Meltdown は、
崩れた
よくある問い
機械語の 良い所と 困る 所は何ですか
良い所は、CPU が
機械語の 命令の 一覧は ありますか
CPU のc = a + b が、adrp、ldr、add、str、ret は、
Python は 機械語に 訳されるのですか
標準の Python (CPython) は、
機械語を 読める 人が いるのは なぜですか
機械語はobjdump のような
確認クイズ
答えだと
1 問目
この
8 ビットで足す
A, B = 250, 10
A = (A + B) & 0xFF
print(A)2 問目
このd = a + b + c は
3 問目
CPU が、
4 問目
アセンブリ言語と
説明課題
次の
c = a + bの 1 行が、CPU の命令の 何個に なるかと、 その 命令の名前 - CPU が
その命令を 1 つずつ進める手順
自分の
この回の 先の一歩
遅い
一次資料
どれも 2026年10月27日に開いて、
- clang the Clang C, C++, and Objective-C compiler (LLVM 公式文書、英語)。コード生成の
段が 中間の 形を 機械語に 直すこと、 -Sがアセンブリ言語のファイルを、 -cが機械語の 入った ファイル (.o) を出すこと - dis Disassembler for Python bytecode (Python 公式文書、英語)。バイトコードは
CPython の インタプリタの 実装の 詳細で、 版の 間で 足されたり消されたり 変わったりしうること - Spectre Attacks Exploiting Speculative Execution (arXiv、英語)。2018 年 1 月 3 日に出された
こと、今の CPU が 分岐予測と 投機的 実行を 使い、 外れた 実行を 捨てても 測れる 跡が残ること - Reading privileged memory with a side-channel (Google Project Zero、英語)。2017 年 6 月 1 日に Intel、
AMD、 ARM に 報告したこと、3 つの型と CVE-2017-5753、 CVE-2017-5715、 CVE-2017-5754 の 番号、 外れた 実行が 読んだ データが CPU のキャッシュに残ること - Meltdown and Spectre (Graz 工科大学などの
研究者の 。Meltdown が公式の 頁、英語) アプリと OS の 間の 隔たりを 破る こと、 順番を 入れ替えて 実行する Intel の CPU は 1995 年以降の ほぼ すべて (2013 年より 前の Itanium と Atom を 除く ) が 影響を 受けうること
