2 おまけ: C言語のプログラムのコンパイル・リンクの仕方をのぞく

C言語で書かれたプログラムは、 機械語に翻訳された上で (コンパイルされて) 実行される。

どういう手順で処理されるかは、簡単に確認できる。 一度くらい見ておこう。

サンプル・プログラム

/*
 * prog1.c
 */

#include <stdio.h>

int sum(int a, int b)
{
  return a+b;
}

int main(void)
{
  int a,b;
  printf("input two integers: ");
  scanf("%d%d", &a, &b);
  printf("sum of %d, %d is %d\n", a, b, sum(a,b));
  return 0;
}

cc コマンドは、普通 C プログラムから実行形式を作成するが、 内部では、色々な処理 (前処理、コンパイル、アセンブル、リンク等々) を段階的に実行している。
前処理とは何をするのか
$ cc -E prog1.c
標準出力に前処理されたプログラムが出力される。 stdio.h の中身が見える。 (-C も指定すると、コメントが削除されず、読みやすいかも。)

アセンブリ言語に変換する (かなりの大仕事)
$ cc -S prog1.c
$ ls
$ cat prog1.s
prog1.s というファイルが出来ている。 中身はアセンブリ言語のプログラムである。 (字句解析、構文解析、中間コード生成、アセンブリ言語出力、 というたくさんの処理をしているが、ここは分解して見せることは出来ない。)

アセンブル (オブジェクト・ファイルへの変換)
$ cc -c prog1.s
$ ls
$ cat prog1.o
(文字化けすると思うが、それが正常である。)
prog1.o というファイル (オブジェクト・ファイル) が出来ている。 これは機械語プログラムであり、 バイナリー・ファイルなので (cat しても訳が分からない) 中身が今ひとつ確かめにくい。

でも、main(), sum() が確かに入っていることは、 次のようにして確かめられる。
オブジェクト・ファイルの中をチェックする
$ nm prog1.o
0000000000000020 T _main
                 U _printf
                 U _scanf
0000000000000000 T _sum

何となく意味が想像できる?
オブジェクト・ファイルをライブラリィとリンクさせて実行形式を作る
$ cc prog1.o
$ ls
標準ライブラリィとリンクされて、a.out と実行形式が出来ている。

実行する
$ ./a.out
input two integers: 2 3
sum of 2, 3 is 5

桂田 祐史
2019-12-02