Hello all, I've been tooling around with building a C++ application using Winelib and I've come across a couple of problems resulting from the use of global constructors. The problems can be reproduced with a simple C++ application which from a constructor calls a method which is resolved through a dll import.
1) If this program is the main program, wine_dll_set_callback has not yet been invoked so the __wine_dll_register call doesn't resolve the import list. The problem is that the constructors of the program are run immediately after the dll is registered which results in calling a non resolved import.
This can be worked around by simply creating a non C++ stub which does a LoadLibrary/GetProcAddress on the real main exe. However I'm wondering if there is a good reason for needing to wait until after the main exe is loaded before being able to resolve imports? I must be missing something from my quick view of the code.
2) The order of running constructor execution and DLL entry point is incorrect.
To show the problem assume you have foo.dll which imports bar.dll
Present order for builtins: Load foo.dll Start to resolve foo.dll dependencies Start to resolve bar.dll dependencies Finsh resolving bar.dll dependencies Run bar.dll C++ constructors Finish resolving foo.dll dependencies Run foo.dll C++ constructors Run bar.dll DLL entry point Run foo.dll DLL entry point
I actually haven't checked if PE images presently have the same problem since I don't know what triggers the ctor execution for a PE image. I assume that it's the running of the DLL entry point, but I don't know for sure. Hopefully I'll find the time at some point this week to whip up a test.
The correct order: Load foo.dll Start to resolve foo.dll dependencies Start to resolve bar.dll dependencies Finsh resolving bar.dll dependencies Run bar.dll C++ constructors Run bar.dll DLL entry point Finish resolving foo.dll dependencies Run foo.dll C++ constructors Run foo.dll DLL entry point
The problem seems reasonably simple enough to resolve but I'm sure that I'm missing something since my patch doesn't work for the present version of wine :(. I think that the problem is that there's an issue with inter DLL dependencies somewhere as it dies in SYSMETRICS_Init with a bad hdc.
I've attached a patch which removes the recursive dep search from MODULE_DllProcessAttach and moves MODULE_DllProcessAttach from LoadLibraryExA into MODULE_LoadLibraryExA. Does this seem like a reasonable approach to take? Any problems with the patch?
Ciao, Peter
"Peter Hunnisett" peter@transgaming.com writes:
I've attached a patch which removes the recursive dep search from
MODULE_DllProcessAttach and moves MODULE_DllProcessAttach from LoadLibraryExA into MODULE_LoadLibraryExA. Does this seem like a reasonable approach to take? Any problems with the patch?
I think the current order is correct, and it needs to be done this way because of circular dependencies. The problem is that you need to delay calling constructors until the DLL entry point is called. This probably requires some compiler/linker magic.
On 22 Jan 2002 15:23:34 -0800, Alexandre Julliard said:
"Peter Hunnisett" peter@transgaming.com writes:
I've attached a patch which removes the recursive dep search from
MODULE_DllProcessAttach and moves MODULE_DllProcessAttach from LoadLibraryExA into MODULE_LoadLibraryExA. Does this seem like a reasonable approach to take? Any problems with the patch?
I think the current order is correct, and it needs to be done this way because of circular dependencies. The problem is that you need to delay calling constructors until the DLL entry point is called. This probably requires some compiler/linker magic.
Ok. This is about the best voodo I can chant up at this point in time. I'm not terribly fond of it but I didn't have a chicken, or chicken substitute, around to sacrifice for extra coding power. It's not tested with unicode stuff and on any platforms other than x86, but it appears to have the semblance of a solution.
The basic concept is that you must link the 32 bit spec file last among the spec files, but before any object files. We short circuit the normal way to build the ELF init section by starting a new function __wine_dllname_deferred_init which should end up containing any special init section code from the object files and the standard ELF initialization stuff. We then bind in an entry point for the builtin dll which invokes the deferred initialization code and then run the actual initialization entry point if there is one.
It requires a little bit of grease since ntdll can't be called until the ctor stuff is invoked so it gets special permission to be built the old way but of course, wine wants to call it early on in life. Other than that, basically everything is limited to making winebuild produce even more stuff.
How does this seem? On the right track? Suggestions for improvement? Am I missing anything with the assembler?
-- Alexandre Julliard julliard@winehq.com
Ciao, Peter