kubo39's blog

ただの雑記です。

DMDはmain関数(not _Dmain)を実行する前になにをするのか

たとえば自前で pragma(crt_constructor) とか使った場合にどういう順で実行されるんだろう、とか。

こういうコードを用意して、

enum body = "import std.stdio;writeln(__PRETTY_FUNCTION__);";

pragma(crt_constructor)
extern (C) void crt_constructor()
{
    mixin(body);
}

void main()
{
    mixin(body);
}

一応環境

$ dmd --version| head -1
DMD64 D Compiler v2.090.1
$ uname -mrsv
Linux 4.15.0-76-generic #86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020 x86_64

コンパイルして .init_array セクションをみてみるとこんな感じ。

$ dmd hoge.d
$ LANG=C readelf -Wx .init_array ./hoge

Hex dump of section '.init_array':
  0x00291dd0 70590400 00000000 70530400 00000000 pY......pS......
  0x00291de0 7c530400 00000000 f0d80600 00000000 |S..............
  0x00291df0 bcfb0600 00000000 54fc0600 00000000 ........T.......

適当にアドレスひっかけて(リトルエンディアンなことに注意)、nmコマンドでシンボルをひいてみる。

一番最初のやつは .init_array の先頭を表すやつ。

$ nm ./hoge| grep 291dd0
0000000000291dd0 t __init_array_start

他のやつは関数ポインタっぽいやつ。frame_dummyはgccが入れてるやつ。

$ nm ./hoge| grep 00045370
0000000000045370 t frame_dummy
$ nm ./hoge| grep 0004537c
000000000004537c t
000000000004537c W crt_constructor
$ nm ./hoge| grep 0006fbbc
000000000006fbbc t
000000000006fbbc W _d_register_conservative_gc
$ nm ./hoge| grep 0006d8f0
000000000006d8f0 t
000000000006d8f0 W _d_register_manual_gc
$ nm ./hoge| grep 0006fc54
000000000006fc54 W _d_register_precise_gc

こうしてみると基本はユーザ定義のやつがGCの初期化処理より先に呼ばれるので、GC使うコードは書けないはず。リンク順に依存してしまうので絶対ではないだろうけど。