高級言語が機械語に変換されるまでの内部メカニズム

高級言語で書かれたプログラムが、最終的に 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 でネイティブコードを生成するかの違いがある。次回は、これらの命令がどのように条件分岐や関数呼び出しを実現するかを詳述する。

タグ: MIPS ISA objdump ELF x86-64

9月26日 05:32 投稿