昔の(非常に古い)時代、コンパイラは次のように機能していました。
- コンパイラはアセンブリ コードをファイルに生成し、それをディスクに書き込みました。
- アセンブラはそのファイルを取得し、バイナリを生成しました。
最近では、本当にアセンブリ出力が必要でない限り、コンパイラは明示的なアセンブリ言語コードを生成しません。メモリ内にアセンブリを生成するだけですが、それをマシンコード自体に変換し、マシンコードのみをファイルに書き込みます。これは、講師が C/C++ が直接マシン コードに変換されると言ったときに意味したことです。
知っておくべき重要なことがもう 1 つあります。機械語は基本的にアセンブリ言語と同じものです。アセンブリ言語では、命令には名前があり、文字列で記述されますが、機械語で使用される命令と同じ(1 対 1 のマッピング) です。これは重要なことなので、繰り返しますが、マシンコードとアセンブリは同じで、異なる表記法で書かれているだけです。
これが、どのバイナリも逆アセンブルできる理由です。マシンコードからアセンブリに何かを変換するには、表現を変更するだけで済みます (各命令とそのオペランドをバイナリから「ニーモニック」形式に変換します。
mov rax, 42
そのため、最新のコンパイラは、パフォーマンス上の理由から、実際には命令 (例: ) を表す実際の文字列を生成しない場合があります。誰もアセンブリ出力を必要としない場合、メモリとそれを生成する処理能力を無駄にする必要はありません。しかしもちろん、コンパイラが生成するより高速な同等のマシン コードを生成します。