DLL主要在Windows Vs. __attribute __((构造函数))Linux上的入口点

时间:2014-03-31 14:14:46

标签: c++ linux windows shared-libraries dllmain

考虑代码

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, loading library
DLL Moo, constructor
DllMain, DLL_PROCESS_ATTACH
Executable Main, Freeing library
DllMain, DLL_PROCESS_DETACH
DLL Moo, destructor
Executable Main, exiting

Linux

Executable Main, loading library
DllInitializer
DLL Moo, constructor
Executable Main, Freeing library
DllFinalizer
DLL Moo, destructor
Executable Main, exiting

在Windows上,Moo构造函数在DLLMain之前被调用,而在linux上,它是在使用attribute((constructor))定义的Initializer之后调用的。

为什么?

2 个答案:

答案 0 :(得分:5)

Moo构造函数在 DllMain之前未被称为,它从 DllMain被称为。确切地说,它是从真正的DllMain调用的,Windows首先调用的函数。这个真正的DllMain调用C ++构造函数,然后调用C ++ DllMain。这个真实DllMain的原因正是初始化构造函数,这是C之前不需要的东西

Linux(GCC / ELF)根本没有这个概念;它只有构造函数。你的手册ctor和Moo的C ++ ctor也是一样的。

答案 1 :(得分:0)

有一种方法:

StartupCleanup.cpp:

// Redefine the same StartupCleanup class as it is in DllMain.cpp
// Definition of constructor and destructor must stay in DllMain.cpp
// And including here any headers which may define normal static or global constructors/destructors is strictly forbidden!
struct StartupAndCleanup
{
    /**/  StartupAndCleanup();
    /**/ ~StartupAndCleanup();
};

// It ensures this instance is the first to be constructed *BEFORE* any normal static or global constructors calls
// and the last to be destructed *AFTER* all normal destructors calls.
// The key to do so is using #pragma init_seg(lib), but that key applies for all the static and global constructors/destructors in the same .obj file! 
#pragma warning(push)
#pragma warning(disable:4073)
#pragma init_seg(lib)
#pragma warning(pop)

// this function is just to keep linker from discarding startupAndCleanup.obj when linking to an executable or dll
void needStartupAndCleanup()
{
}

static StartupAndCleanup startupAndCleanup;

DllMain.cpp:

...
// Definition of this class should be the same as in StartupAndCleanup.cpp!
struct StartupAndCleanup
{
    /**/  StartupAndCleanup();
    /**/ ~StartupAndCleanup();
};

StartupAndCleanup::StartupAndCleanup()
{
    // Do your initialization here !
}

StartupAndCleanup::~StartupAndCleanup()
{
    // Do your termination here !
}

你DllMain必须只是一个空壳,并在那些构造函数和析构函数中执行常规的安全初始化和终止,例如Linux。

注意:小心!如果您打算同步它们,则无法在静态或全局构造函数/析构函数内创建/删除线程。 那是所有人!

编辑:你还需要在你知道它被链接的函数中调用needStartupAndCleanup(),否则将丢弃目标文件StartupCleanup.obj以及那些全局构造函数/析构函数。