2

I read that on windows, modules of an executable are mapped in the same address space. I don't understand why

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;
}

and

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;
}

yields this result:

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

Also, the address 007BFD88 can not be accessed from the main process. Why are the two addresses different ?

antoine
  • 29
  • 2
  • 1
    Incremental linking as implemented by the MSVC++ linker and used in the Debug build is one explanation. The address you get in your DLL is the address of a JMP instruction that jumps to the real function. Try it again with the Release build. – Hans Passant Mar 20 '15 at 11:23
  • @HansPassant if exactly the same function would have different addresses because of some code generation / linking conventions, the C++ compiler would be non compliant with the standard. – Christophe Mar 20 '15 at 18:43
  • Hmm, let me consult the C++ standard that describes how modules should behave. – Hans Passant Mar 20 '15 at 20:42

2 Answers2

1

The fundamental rule is that DLL are allways loaded in the address space of the process that uses it. So your function pointer must be the same.

It's the same address on both sides:

I tried your code snippet with a small variant. In the DLL's main(), I've used:

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

And in the programme's main(), I've used:

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

Exactly the same address comes out ! Allways !

What's the problem with your code ?

In your code snippet, you don't cout the function address directly, but you use oss:

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

On my compiler (MSVC13), I get a compilation error for oss. I don't know why it works for you, but I suspect that you print the address of your stringstream and not its content. As oss is a local variable, it has a different address in both functions and hence the cause of you worries.

Try the alternative:

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

and you'll get again the same result (address printed out) on both sides.

On GCC your code compiles but doesn't produce the result that you expect as this online snippet shows.

Additional remarks

If the same DLL function would have different addresses, it would mean that you are in presence of two different processes, each with it's own address space.

When you make use of the optional DllMain() entry point, and call a (non exported) main() function there, it could give the impression of a distinct process, but that's really not the case.

I'd also like to add that function pointers are function poitners. There is no black magic with it. Two pointers of exactly the same type, pointing to exactly the same function, will have exactly the same address. Here the normative reference in the C++ standard:

5.10/1: Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address.

Community
  • 1
  • 1
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • AFAIK, as soon as you introduce dynamic linking, you're outside of the coverage of the C++ standard. In particular, the standard does not require that the function you get via dynamic linking has to be the same as the function inside the DLL. It could be a proxy function that calls the actual function. – Harry Johnston Mar 21 '15 at 22:54
  • As said, I did the test, it works perfectly with the code correction that I documetned here: same address on both side. I invite you to test the online snippet, that highlights the problem of the op: in his code he doesn't print the function pointer at all, but only the address of its local stringsrtream ! – Christophe Mar 21 '15 at 23:08
  • Some caution is required here - if you can't reproduce the problem, you can't be sure of the cause. Note that the OP reports that the problem went away as soon as he switched from Debug to Release, which your answer can't explain. At any rate, even if your hypothesis is in fact correct, that doesn't change the fact that the C++ standard does not require this behaviour. – Harry Johnston Mar 22 '15 at 06:10
  • i can reproduce the weird behaviour of op, which is solely caused by an error in the use of extractors. I can demonstrate that the function pointers all have the same value by correcting his error. Finally about the standard quote: it applies to the c++ implementation as a whole, including compiler AND linker (see chapter 1). So what is still unclear in these hard facts @harryjohnston ? – Christophe Mar 22 '15 at 09:15
  • According to your answer, you couldn't reproduce the symptoms described by the OP; you got a compilation error instead. That's not the same thing. Also, the quote from the standard only applies if the two pointers are to the *same* function, but AFAIK there is nothing in the standard that requires GetProcAddress to return a pointer to the requested function rather than a pointer to a [thunk](http://en.wikipedia.org/wiki/Thunk). (Besides, doesn't the standard also require the usual signature for the main function? If VS ignores that, what makes you think it doesn't ignore this?) – Harry Johnston Mar 22 '15 at 19:07
  • Did you try the code of the op and mine, or are you just speaking without any practical reference ? Do you have a reproductible code snippet that demonstrates your affirmations ? If yes, please post it as an answer. – Christophe Mar 22 '15 at 19:15
  • I'm not affirming anything, I'm just pointing out the flaws in your reasoning. But Hans is rarely wrong about this sort of thing. (Now that I'm back in the office, I will try the OPs code out, but without more information about which build tools he's using and how the project is configured I'll be flying blind.) – Harry Johnston Mar 22 '15 at 19:21
  • 1
    OK, I can confirm that in Visual Studio 2010 the OPs code does not print the value of the function pointer. Stepping into that line, it appears to be invoking `operator void *()` on the `ios_base` class - heaven knows why, but then, that's C++ for you. I still believe that you're wrong about the standard *requiring* that the pointers be the same, but spotting the problem with the output was a good catch, so +1 anyway. :-) – Harry Johnston Mar 22 '15 at 19:57
0

address 007BFD88 does not have to be the address of an exported function from a DLL (which GetProcAddress() returns); it is just a function pointer. Function pointers in C/C++ have a few interesting properties, check this out: Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?

Community
  • 1
  • 1
Sergei Vorobiev
  • 364
  • 2
  • 8
  • A verry interesting link ! But all the different function pointers of that example contain exactly the same address. So it doesn't really answer the question... – Christophe Mar 20 '15 at 17:21
  • it is not an address. it is a function pointer. Now, what GetProcAddress() returns is indeed an address. – Sergei Vorobiev Mar 20 '15 at 18:39
  • It may or may not be an address. check out the snippet from the standard you quoted: there is a distinction between having the same address and pointing to a function. – Sergei Vorobiev Mar 20 '15 at 18:52
  • Ok, but regardless of the name of the content of a pointer, doesn't the c++ standard state in 5.10/1 that *Two pointers of the same type compare equal **if and only if** they are both null, **both point to the same function**, or both represent the same address.* ? – Christophe Mar 20 '15 at 19:08
  • that's exactly the snippet I referred to. Pointing to a function is not the same as representing an address. One pointer represents an address (the one from GetProcAddress), another is a pointer to a function (more precisely, thunk, an artifact of a debug build). They are BTW of different types. – Sergei Vorobiev Mar 20 '15 at 19:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73445/discussion-between-christophe-and-sergei-vorobiev). – Christophe Mar 20 '15 at 19:18