「a=10とb=5の平均は7.5です」をmain関数なしで表示する

発端

課題

Int a=10; Int b=5; と代入し平均を表示する

「a=10とb=5の平均は7.5です」と画面に表示する

f:id:mickey24:20190710115023p:plain:w300

考察

  • 「Int」と書いてあるがこれはtypedef int Int;が必要?とりあえず普通のintでもよいと解釈する。
  • 「Int a=10; Int b=5; と代入し」と言っているが、「代入後aとbを使わなければならない」とは言っていない。
  • 「平均を表示する」とは言っているが「平均を計算する」とは言っていない。
  • 「main関数を書く必要がある」とは言っていない。
  • 「どの環境でも実行できる必要がある」とは言っていない。

int a = 10;
int b = 5;
const char main[] = "\x48\xc7\xc0\x01\x00\x00\x00\xba\x20\x00\x00\x00\xbf\x01\x00\x00\x00\xe8\x0c\x00\x00\x00\x48\x81\xc6\x11\x00\x00\x00\x0f\x05\x31\xc0\xc3\x48\x8b\x34\x24\xc3\x61\x3d\x31\x30\xe3\x81\xa8\x62\x3d\x35\xe3\x81\xae\xe5\xb9\xb3\xe5\x9d\x87\xe3\x81\xaf\x37\x2e\x35\xe3\x81\xa7\xe3\x81\x99\n";

なにこれ

これはC言語で書かれたプログラムです。実行すると「a=10とb=5の平均は7.5です」とstdoutに出力されます。x64の一部の環境でしか動作しません。実行結果はこちら:https://wandbox.org/permlink/bWtd0lfQn0ErFgG9

おそらくこの課題に取り掛かった大学生のうち約7〜8割はこの解にたどり着くのではないかと思います。

なにこれ (1)

一見ランダムに見えるmain配列の文字列は「機械語」の命令に相当するもので、以下のような構成になっています。

int a = 10;
int b = 5;
const char main[] =
    // mov $0x01,%rax
    "\x48\xc7\xc0\x01\x00\x00\x00"
    // mov $0x20,%edx
    "\xba\x20\x00\x00\x00"
    // mov $0x01,%edi
    "\xbf\x01\x00\x00\x00"
    // callq 0x0c
    "\xe8\x0c\x00\x00\x00"
    // add $0x11,%rsi
    "\x48\x81\xc6\x11\x00\x00\x00"
    // syscall
    "\x0f\x05"
    // xor %eax,%eax
    "\x31\xc0"
    // ret
    "\xc3"
    // mov (%rsp),%rsi
    "\x48\x8b\x34\x24"
    // ret
    "\xc3"
    // "a=10と"
    "\x61\x3d\x31\x30\xe3\x81\xa8"
    // "b=5の"
    "\x62\x3d\x35\xe3\x81\xae"
    // "平均は"
    "\xe5\xb9\xb3\xe5\x9d\x87\xe3\x81\xaf"
    // "7.5です\n"
    "\x37\x2e\x35\xe3\x81\xa7\xe3\x81\x99\n";

このようなデータをmainという名前の配列に保持しておくことで、crt0がプログラム開始後にmainという名前が指している場所にあるデータを機械語の命令として実行してくれます。出力される文字列「a=10とb=5の平均は7.5です」はUTF-8バイト列の16進表記としてmain配列の末尾に格納してあります。

実際に実行される処理は以下とほぼ同等です。

write(1, "a=10とb=5の平均は7.5です\n", 32);

各機械語の命令の詳細は以下の記事が非常に参考になります。

koturn.hatenablog.com

感想

C言語はプログラマーに「main関数を書かない」という選択肢も与えてくれて自由度が高くていいなあとおもいました(白目)。

Cにおいてconst char main[]でプログラムを書けることは5年以上前から知っていましたが、実際にやってみたのは今回が初めてです。記号プログラミングもそうですが、言語仕様や処理系の実装の秘孔を突くのはやっぱり楽しいものです。GoやPythonといった最近の言語だとなかなかこういう遊びができないので、C言語はまだ人類に必要だと痛感しました。

参考文献