This is a very valid question.
Alexandre, do we support generating regular executables for the apps we don't necessarily need the wrapper stuff for initialization purposes?
---------- Forwarded Message ----------
Subject: Re: [putty]Winelib support + patch Date: Mon, 25 Nov 2002 10:17:18 +0000 From: Simon Tatham anakin@pobox.com To: dpaun@rogers.com Cc: putty@projects.tartarus.org
"Dimitrie O. Paun" dpaun@rogers.com wrote:
FYI: the way it works is that instead of compiling the app as an executable, we generate a .so that's loaded by wine. Now, wine is simply a one page program that loads the libraries that the program expects (like kernel, gdi, user), and then loads the program itself. This is required by some apps which have C++ static initializers, which expect to be able to call Win32 functions, and they do so before we get a chance to initialize them, if we were to have the app load the libs.
OK, I've now read the docs and I understand this a bit better now. My next awkward question is: I can see that this is necessary for some apps which have C++ static initialisers, or which load libraries that have C++ static initialisers, but why does that mean it's necessary for PuTTY? PuTTY contains no C++, and as far as I know it uses no libraries _except_ standard Win32 API ones. Surely it should be possible _for these particular applications_ to compile them as standalone binaries? Or does Winelib currently only support doing things the inconvenient way?
Cheers, Simon -- Simon Tatham "The distinction between the enlightened and the anakin@pobox.com terminally confused is only apparent to the latter."
-------------------------------------------------------
On Mon, 25 Nov 2002, Dimitrie O. Paun wrote:
This is a very valid question.
Alexandre, do we support generating regular executables for the apps we don't necessarily need the wrapper stuff for initialization purposes?
I assume Putty was compile as: 'putty.exe.so'. It's necessary to compile Winelib applications as .so libraries due to initialization order issues. I'll let Alexandre explain it in more detail but I believe that in essence we need the wine loader to initialize things first.
However there is no wrapper involved in the above. if you have a wrapper, then the load sequence is: wine loads mfcapp.exe.so which is the wrapper, and then mfcapp.exe.so then loads mfcapp.dll.so which contains the actual application.
I say 'mfcapp' because it's a typical case where you need the arapper. The reason for this one is that because of C++ you need to link to the mfc library in the Unix sense (Winelib does not know how to import virtual table pointers because they are variables, not functions). But this causes MFC static initializers to run before the dlls it depends on have been loaded and initialized.
So we get wine to load mfcapp.exe.so which just links to a bunch of Wine libraries causing them to be loaded and initialize. Only then, i.e. in its 'WinMain', does the wrapper do a LoadLibrary of 'mfcapp.dll'. This causes libmfc.so to be loaded but that's ok since the libraries it depends on have been initialized by now.
So you see, the putty situation really is not that ugly<g>.
On November 25, 2002 05:39 pm, Francois Gouget wrote:
However there is no wrapper involved in the above. if you have a wrapper, then the load sequence is: wine loads mfcapp.exe.so which is the wrapper, and then mfcapp.exe.so then loads mfcapp.dll.so which contains the actual application.
But we have a wrapper already, why do we need two of them? It seems to me one should be enough, if we can instruct wine to load said libs before loading the app, no?
I say 'mfcapp' because it's a typical case where you need the arapper. The reason for this one is that because of C++ you need to link to the mfc library in the Unix sense (Winelib does not know how to import virtual table pointers because they are variables, not functions). But this causes MFC static initializers to run before the dlls it depends on have been loaded and initialized.
Sorry, I have to admit: this linking, importing, etc. is all Chinese to me. Is this ignorance of importing variables a limitation of Winelib that we can fix (import libraries?), or is it something fundamentally unfixable?
BTW, can you please take a look here: http://www.dssd.ca/wine/Winelib-Apps.html#visual-mingw It seems I'm running in the same problem.
The way I understand it though is a bit different (or so it seems to me): -- wine calls PROCESS_InitWine (first thing it does in main()) -- PROCESS_InitWine -> open_builtin_exe_file -> wine_dll_load_main_exe -- wine_dll_load_main_exe -> dlopen_dll So this one loads the .so, and this triggers the static initializers to run, thus calling the statically constructed classes, right? And here the problem happens. Why? Because the kernel & friends have not yet been loaded?
`On Fri, 29 Nov 2002, Dimitrie O. Paun wrote:
On November 25, 2002 05:39 pm, Francois Gouget wrote:
However there is no wrapper involved in the above. if you have a wrapper, then the load sequence is: wine loads mfcapp.exe.so which is the wrapper, and then mfcapp.exe.so then loads mfcapp.dll.so which contains the actual application.
But we have a wrapper already, why do we need two of them? It seems to me one should be enough, if we can instruct wine to load said libs before loading the app, no?
If you modify wine itself then you should be able to remove the wrapper. However, how will you instruct Wine to load just the right libraries? Note that Wine should not load extra libraries, especially not GDI and stuff, unless it's needed. So you need a way to instruct Wine to do that just for this application. You could do that by writting a wrapper script around Wine (hmm, a wrapper again, different level but still a wrapper), or by having Wine get that information from the .so without dlopening it.
I say 'mfcapp' because it's a typical case where you need the arapper. The reason for this one is that because of C++ you need to link to the mfc library in the Unix sense (Winelib does not know how to import virtual table pointers because they are variables, not functions). But this causes MFC static initializers to run before the dlls it depends on have been loaded and initialized.
Sorry, I have to admit: this linking, importing, etc. is all Chinese to me. Is this ignorance of importing variables a limitation of Winelib that we can fix (import libraries?), or is it something fundamentally unfixable?
Linking in the unix sense is the act of doing 'gcc -lfoo'. Unix will take care of loading the library foo. Importing is the act of telling winebuild that you want to import a WineLib library, and the act of loading the library is done by Wine using dlopen just before calling the 'WinMain' of your application (i.e. it's done after all the libraries you link with 'in the Unix sense' have been loaded and initialized).
For instance you 'import' gdi32, you don't link with it: you never use '-lgdi32' when compiling a WineLib application. However, you have to link with Unix libraries like opengl or curses and you cannot import them (because they don't have the required 'PE' information that winebuild adds in the .spec.c file).
So how does it work when you call something like CreateFileA? My understanding of it is that winebuild creates a strampoline for it in the .spec.c file. Then at load time Wine does a dlsym on the appropriate symbol and sets the trampoline to point to the right address. Thus when you call CreateFileA, your code jumps to the trampoline which jumps to the actual CreaFileA implementation.
But you cannot create trampolines for variables. When your code tries to access a variable it accesses a specific address. You cannot store a 'jmp' at that address to force it to read stuff from another address. To solve this problem it seems like we would need to replace all variable declarations with code that looks like '*get_variable()' which besides the compilation issues is impossible if the variable access is generated by the compiler itself which is what happens with class virtual tables.
BTW, can you please take a look here: http://www.dssd.ca/wine/Winelib-Apps.html#visual-mingw It seems I'm running in the same problem.
The way I understand it though is a bit different (or so it seems to me): -- wine calls PROCESS_InitWine (first thing it does in main()) -- PROCESS_InitWine -> open_builtin_exe_file -> wine_dll_load_main_exe -- wine_dll_load_main_exe -> dlopen_dll So this one loads the .so, and this triggers the static initializers to run, thus calling the statically constructed classes, right? And here the problem happens. Why? Because the kernel & friends have not yet been loaded?
Yes, I believe the problem is that dlopening your application exe causes all the libraries it is linked with in the Unix sense to be loaded and initialized immediately. Then your exe's static initializers are run which registers with Wine the list of dlls that your application wants to load. So when the CCriticalSection constructor tries to call a Wine function it is likely that the corresponding library has not yet been loaded or initialized.
On November 29, 2002 02:45 pm, Francois Gouget wrote:
If you modify wine itself then you should be able to remove the wrapper. However, how will you instruct Wine to load just the right libraries?
We already have a wrapper for the .exe.so, we can pass in some flags. Something like --preload ntdll,kernel,user,gdi,...
Of course, the ideal fix is if wine canfigure things out automatically from the .exe.so file. Since we are going to have that link script sooner or later, what about we store this information in a ELF section, and get it from there before dlopening the file? BTW, how hard would be to get to such a section?
But you cannot create trampolines for variables.
No, but I guess you can trigger a segfault, and do the fixup in the signal handler. But regardless, how does Windows deal with this? How come it works there, and not under Wine?
"Dimitrie O. Paun" dpaun@rogers.com writes:
This is a very valid question.
Alexandre, do we support generating regular executables for the apps we don't necessarily need the wrapper stuff for initialization purposes?
No, that's not supported at this point. It may be possible to support it again with some linker magic, now that apps no longer link to dlls directly. That's definitely something we should try to do as part of the "making winelib more user-friendly" task.