1

Q :DllMain()共有ライブラリに関数を記述し、さらに を含む関数を記述した__attribute__((constructor))場合、ライブラリがロードされたときに最初に実行されるのはどれですか?

Q : その共有ライブラリにリンクされた実行可能ファイルに関数がある場合__attribute__((constructor))、ライブラリDllMain()の関数または実行可能関数のどちらが最初に呼び出され__attribute__((constructor))ますか?

4

2 に答える 2

6

A : 関数は次の順序で呼び出されます。

  • DLL constructor
  • DLL DllMain() (process attach)
  • EXE constructor
  • EXE main()
  • EXE main() ends
  • EXE destructor
  • DLL DllMain() (process detach)
  • DLL destructor

リンクが実行時に行われる場合 ( LoadLibrary()/ FreeLibrary())、関数は次の順序で呼び出されます。

  • EXE constructor
  • EXE main()
  • EXE LoadLibrary()
  • DLL constructor
  • DLL DllMain() (process attach)
  • EXE main() continues
  • EXE FreeLibaray()
  • DLL DllMain() (process detach)
  • DLL destructor
  • EXE main() ends
  • EXE destructor

ライブラリを解放するのを忘れた場合の順序は次のとおりです。

  • EXE constructor
  • EXE main()
  • EXE LoadLibrary()
  • DLL constructor
  • DLL DllMain() (process attach)
  • EXE main() continues
  • EXE main() ends
  • EXE destructor
  • EXE FreeLibaray() (system cleans up for you)
  • DLL DllMain() (process detach)
  • DLL destructor
于 2012-09-13T02:10:46.573 に答える
0

コードを検討する

EXE:

int main ()
{

    printf("Executable Main, loading library\n");
#ifdef HAVE_WINDOWS
    HMODULE lib = LoadLibraryA ("testdll.dll"); 
#elif defined(HAVE_LINUX)
    void * lib  = dlopen("testdll.so", RTLD_LAZY);  
#endif 

    if (lib) {
        printf("Executable Main, Freeing library\n");
    #ifdef HAVE_WINDOWS
        FreeLibrary (lib); 
    #elif defined(HAVE_LINUX)
        dlclose(lib);   
    #endif 
    }
    printf("Executable Main, exiting\n");
    return 0;
}

DLL

struct Moo
{
    Moo() { printf("DLL Moo, constructor\n"); }
    ~Moo() { printf("DLL Moo, destructor\n"); }
};

Moo m;

#ifdef HAVE_WINDOWS
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        printf("DllMain, DLL_PROCESS_ATTACH\n");
        break;
    case DLL_THREAD_ATTACH:
        printf("DllMain, DLL_THREAD_ATTACH\n");
        break;
    case DLL_THREAD_DETACH:
        printf("DllMain, DLL_THREAD_DETACH\n");
        break;
    case DLL_PROCESS_DETACH:
        printf("DllMain, DLL_PROCESS_DETACH\n");
        break;
    default:
        printf("DllMain, ????\n");
        break;
    }
    return TRUE;
}
#else
CP_BEGIN_EXTERN_C
__attribute__((constructor))
/**
 * initializer of the dylib.
 */
static void Initializer(int argc, char** argv, char** envp)
{
    printf("DllInitializer\n");
}

__attribute__((destructor))
/** 
 * It is called when dylib is being unloaded.
 * 
 */
static void Finalizer()
{
    printf("DllFinalizer\n");
}

CP_END_EXTERN_C
#endif

出力が異なります: Windows では、Executable Main、ライブラリ DLL Moo の読み込み、コンストラクタ DllMain、DLL_PROCESS_ATTACH Executable Main、ライブラリ DllMain の解放、DLL_PROCESS_DETACH DLL Moo、デストラクタ Executable Main、終了

Linux Executable Main、ロード ライブラリ DllInitializer DLL Moo、コンストラクタ Executable Main、解放ライブラリ DllFinalizer DLL Moo、デストラクタ Executable Main、終了

Windows では、Moo コンストラクターは DLLMain の前に呼び出されますが、Linux では、属性((constructor)) を使用して定義された Initializer の後に呼び出されます。

なぜ?

于 2014-03-31T14:08:29.430 に答える