スタートアップルーチンやらDLLのエントリポイントやら

散々はまりまくって、某スレで__CTOR_LIST__ の挙動の違い教えてもらいやっと理解した。
論理的には以下の順序で初期化が行われればOK

static リンク時

  1. malloc/free new/delete用ユーザー空間メモリ初期化
  2. staticリンクされたものの __CTOR_LIST__ で初期化ルーチンを実行
  3. ライブラリ固有の初期化

現実的には全て crt で行う

dynamic リンク時

  1. malloc/free new/delete用ユーザー空間メモリ初期化
  2. dynamiリンクされたものの __CTOR_LIST__ で初期化ルーチンを実行
  3. staticリンクされたものの __CTOR_LIST__ で初期化ルーチンを実行
  4. ライブラリ固有の初期化

1, 2, 4は dllmain で、3はcrtで行う。

やっかいな部分

  • static/dynamic リンクによって動きが異なる
  • メモリ初期化だけに限ってはライブラリ固有の初期化より前に行わなければいけない。(staticなクラスのコンストラクタでnewを使っていたりすることが考えられる。)
  • dllの依存関係

結局どうなったか?

monapi.cpp (crt)
/*----------------------------------------------------------------------
    entry point for application
----------------------------------------------------------------------*/
extern "C" int user_start()
{
    if (!monapi_memory_initialized)
    {
        monapi_initialize_memory(64 * 1024 * 1024);
    }
    invokeFuncList(__CTOR_LIST__, __FILE__, __LINE__);
    int result = user_start_c_impl(main);
    invokeFuncList(__DTOR_LIST__, __FILE__, __LINE__);
    return result;
}
monapi_impl.cpp
extern bool monapi_memory_initialized = false;
static bool monapi_initialized = false;

extern "C" int dllmain()
{
    monapi_initialize_memory(64 * 1024 * 1024);
    invokeFuncList(__CTOR_LIST__, __FILE__, __LINE__);
    monapi_memory_initialized = true;
    return 0;
}

extern "C" __attribute__((constructor)) void monapi_initialize()
{
    if (monapi_initialized) return;
    monapi_initialized = true;
}

// if __attribute__((constructor)) doesn't work, use this.
//static struct MonAPIInitWrapper {MonAPIInitWrapper(){monapi_initialize();}} MonAPI_initializer;
monalibc/crt/dllmain.cpp
extern "C" int dllmain()
{
    invokeFuncList(__CTOR_LIST__, __FILE__, __LINE__);
    return 0;
}

extern bool monalibc_initialized = false;

extern "C" __attribute__((constructor)) void monalibc_initialize()
{
    if (monalibc_initialized) return;
    monapi_initialize();
//     uint32_t handle;
//     handle = MonAPI::System::getProcessStdinID();
//     inStream = MonAPI::Stream::FromHandle(handle);
//     handle = MonAPI::System::getProcessStdoutID();
//     outStream = MonAPI::Stream::FromHandle(handle);
    init_stdio();
    monalibc_initialized = true;
}

// if __attribute__((constructor)) doesn't work, use this.
//static struct MonalibcInitWrapper {MonalibcInitWrapper(){monalibc_initialize();}} Monalibc_initializer;

問題点

monalibc/crt/dllmain.cppのmonalibc_initialize で inStream等のコードをコメントアウトから戻すと一部のコードが動かなくなる。
順序間違えている?
難しいのう。><