高級言語で書かれたプログラムが、最終的に CPU が解釈できる 0/1 の列となるまでの変換プロセスを俯瞰する。以降のセクションでは、条件分岐・ループ・関数呼び出し・再帰といった構造が実際にどう実行されるかを追う。
機械語と CPU 命令の違い
CPU はハードウェアとして巨大な集積回路であり、ソフトウェアの観点では「命令セット(ISA)」という言語を理解するプロセッサである。Intel 系と ARM 系では ISA が異なるため、それぞれ独自の「言語」で動作する。
ソースコードから機械語へ:コンパイル~アセンブル~リンク
以下のような最小限の C コードを例に取る。
// sample.c
int entry(void) {
int x = 5;
int y = 7;
return x + y;
}
Linux 環境では次のように変換を観察できる。
$ gcc -c -O0 sample.c # コンパイル:C → リロケータブルオブジェクト
$ objdump -d -M intel sample.o
出力抜粋:
0000000000000000 <entry>:
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
4: c7 45 fc 05 00 00 00 mov DWORD PTR [rbp-0x4],0x5
b: c7 45 f8 07 00 00 00 mov DWORD PTR [rbp-0x8],0x7
12: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8]
15: 8b 55 fc mov edx,DWORD PTR [rbp-0x4]
18: 01 d0 add eax,edx
1a: 5d pop rbp
1b: c3 ret
左側の 16 進列が機械語(バイト列)、右側が人間可読なアセンブリである。1 行の C が複数命令に展開されることも珍しくない。
命令フォーマットを読み解く:MIPS を例に
x86 の可変長命令は複雑なため、固定長 32 ビットの MIPS で構造を見る。
MIPS の 3 形式
- R-type:演算・論理命令。レジスタ同士の演算に使う。
- I-type:即値やメモリアクセス、条件分岐。
- J-type:ジャンプ先アドレスを直接指定。
加算例:add $t0,$s1,$s2
フィールド割当:
opcode rs rt rd shamt funct
000000 10001 10010 01000 00000 100000
32 ビット並べ:
00000010001100100100000000100000
16 進では 0x02324020
rs=17($s1)、rt=18($s2)、rd=8($t0) をエンコードし、shamt=0、funct=0x20(add)で加算を指示する。
まとめ
高級言語 → アセンブリ → 機械語という段階的変換により、CPU はプログラムを実行できる。インタープリタ型や VM 型言語も最終的には同じ 0/1 列に落ち着くが、実行時に逐次翻訳するか JIT でネイティブコードを生成するかの違いがある。次回は、これらの命令がどのように条件分岐や関数呼び出しを実現するかを詳述する。