在Windows上,为什么同一模块有不同的地址?

时间:2015-03-20 07:04:11

标签: c++ windows api dll module

我在Windows上看到,可执行文件的模块映射在同一个地址空间中。 我不明白为什么

typedef int (__stdcall *fptr)();

int     main(void)
{

    HINSTANCE   h;
    fptr        f;
    std::stringstream oss;

    h = LoadLibrary("test.dll");
    if (! h)
        return EXIT_FAILURE;
    f = (fptr)GetProcAddress(h, "function");
    if (! f)
        return EXIT_FAILURE;

    oss << (DWORD *)f;
    std::cout <<"main: "<< oss << std::endl;

    _getch();
    return EXIT_SUCCESS;
}

extern "C" {
    void __declspec(dllexport) function() {
        return ;
    }
}

int     main(HMODULE m)
{
    std::stringstream oss;  

    oss << (DWORD *)function;

    std::cout << "dll: " << oss << std::endl;
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        main(hModule);
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

得出这个结果:

> "test.exe"
dll: 007BFDB8
main: 0039F944

此外,无法从主进程访问地址007BFD88。 为什么两个地址不同?

2 个答案:

答案 0 :(得分:1)

基本规则是DLL在使用它的进程的地址空间中加载 allways 。所以你的函数指针必须是相同的。

双方的地址相同:

我尝试使用一个小变体的代码片段。在DLL的main()中,我使用过:

    std::cout << "f in dll: " << (DWORD *)function << std::endl;

在节目的主要部分()中,我使用过:

    std::cout << "f in main: " << (DWORD *)f << std::endl;

完全相同的地址出来了!永远!

您的代码存在什么问题?

在您的代码段中,您不必直接宣传功能地址,但使用oss

std::stringstream oss;
oss << (DWORD *)function;
std::cout << "f in dll: " << oss << std::endl;  // ??? 

在我的编译器(MSVC13)上,我收到了oss的编译错误。我不知道它为什么适合你,但我怀疑你打印的是字符串流的地址,而不是它的内容。由于oss是一个局部变量,它在两个函数中都有不同的地址,因此引起您的担忧。

试试alternative

    std::cout << "f in dll: " << oss.str() << std::endl;

并且您将再次获得双方相同的结果(地址打印出来)。

在GCC上,您的代码会编译,但不会产生您期望的结果online snippet

补充说明

如果相同的DLL函数具有不同的地址,则意味着您存在两个不同的进程,每个进程都有自己的地址空间。

当您使用可选的DllMain()入口点,并在那里调用(非导出的)main()函数时,它可能会给人一种独特过程的印象,但这真的很棒不是这样的。

我还想补充一点,函数指针是函数poitners。它没有黑魔法。两个完全相同类型的指针,指向完全相同的函数,将具有完全相同的地址。这里是C ++标准中的规范性引用:

  

5.10 / 1:相同类型的两个指针比较相等,当且仅当它们都为空,都指向相同的函数,或者两者都是   代表相同的地址。

答案 1 :(得分:0)

地址007BFD88不必是DLL中导出函数的地址(GetProcAddress()返回);它只是一个函数指针。 C / C ++中的函数指针有一些有趣的属性,请查看:Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?

相关问题