Hi Vincent,
thank you for your help so far and sorry for disturbing you with my patches again so soon. While looking a bit further into my app under Wine I found out that some mixed assemblies are completely broken under Wine/Mono due to the fact that native entry point is not called at all. It relates to both 32 bit and 64 bit. 32 bit works fine under native MS .Net which apparently does call the entry point. The entry point address is present in IMAGE_COR20_HEADER (when appropriate flag is set in Flags member). It is DllMain-type entry point having the same parameters. This entry point does static initialization, e. g. calls all the constructors for static classes. I am attaching preliminary patch to illustrate what I am talking about. It would be great if you could give some high level feedback on whether you like the idea of doing this in general before I will be spamming it to wine-patches.
The potential issue which I can imagine with it is that if there are some old apps (built with VS 2003) which called CLR code in native init but by chance worked if native init was not called at all, may stop working. MSDN says that such apps could non-deterministically deadlock when loaded; with Wine/Mono they will lock deterministically I think ( https://msdn.microsoft.com/en-us/library/ms173266.aspx). Still I suppose the issue with entry point should be addressed somehow since it affects "normal" newer applications.
Regards, Paul.
thank you for your help so far and sorry for disturbing you with my
patches again so soon.
Thank you for the work you've been putting into this. Please continue disturbing me with improvements in mixed-mode support for as long as you like.
While looking a bit further into my app under Wine I found out that some
mixed assemblies are completely broken under Wine/Mono due to the fact that native entry point is not called at all. It relates to both 32 bit and 64 bit. 32 bit works fine under native MS .Net which apparently does call the entry point. The entry point address is present in IMAGE_COR20_HEADER (when appropriate flag is set in Flags member). It is DllMain-type entry point having the same parameters. This entry point does static initialization, e. g. calls all the constructors for static classes. I am attaching preliminary patch to illustrate what I am talking about. It would be great if you could give some high level feedback on whether you like the idea of doing this in general before I will be spamming it to wine-patches.
This seems like the right approach. If the app works in .NET on Wine, that would be another indication that mscoree is the right place for this.
I checked ecma-335, and sadly the flag isn't documented there. How did you find out about it?
The potential issue which I can imagine with it is that if there are
some old apps (built with VS 2003) which called CLR code in native init but by chance worked if native init was not called at all, may stop working. MSDN says that such apps could non-deterministically deadlock when loaded; with Wine/Mono they will lock deterministically I think ( https://msdn.microsoft.com/en-us/library/ms173266.aspx). Still I suppose the issue with entry point should be addressed somehow since it affects "normal" newer applications.
Well, pretty much any change in behavior could cause a regression. Unless there's something else that we should fix first (because programs will start using it), I wouldn't worry about it.
On 01/26/2016 11:10 PM, Vincent Povirk wrote:
I checked ecma-335, and sadly the flag isn't documented there. How did you find out about it?
I was googling for "pe32+ IMAGE_COR20_HEADER" and "pe32+ mono dump IMAGE_COR20_HEADER". The search gives this, for instance: https://forum.tuts4you.com/topic/26862-net-directory-flags/#comment-127000
Before googling this, I made sure that init routine is called or not by inserting crashes in the app init routines and thus detecting if the routine is called under Mono & .Net (all under Wine). I initially suspected that this is somehow called from managed ctor, but it appeared to be not the case. I searched for these words being curious how .Net gets this entry point address while it is not in exports and normal PE entry point.
Well, pretty much any change in behavior could cause a regression. Unless there's something else that we should fix first (because programs will start using it), I wouldn't worry about it.
So then I will split this patch into two or three, look couple of times more and send it.
Thanks, Paul.
So then I will split this patch into two or three, look couple of times more and send it.
It seemed like one logical change to me, I don't think it needs splitting. (Except for the change to FixupVTable which seems unrelated.)
How can I build a DLL to test this? The default managed c++ dll doesn't seem to include an entry point.
On 01/26/2016 11:42 PM, Vincent Povirk wrote:
So then I will split this patch into two or three, look couple of times more and send it.
It seemed like one logical change to me, I don't think it needs splitting. (Except for the change to FixupVTable which seems unrelated.)
Shouldn't I add flag to winnt.h in a separate patch? The change I made to FixupVTable is for avoiding calling times assembly_from_hmodule twice when called from _CorDllMain (which involves extra heap allocation/free). If you think it is not an issue I can simplify the patch and do not touch FixupVTable. Or change FixupVTable as first part, then the main change as the next part.
How can I build a DLL to test this? The default managed c++ dll doesn't seem to include an entry point.
I suppose the simplest way to test it to make mixed mode C++ DLL with native C++ class with printf in constructor, and static instance of the class defined globally in DLL. And whatever in managed part which would be called from some normal DLL native exported function. Native entry point RVA should be in corhdr->EntryPointRVA of the DLL (while PE32 normal entry point just jumps to _CorDllMain). Unfortunately I still cannot build mixed mode DLLs myself and do not have exactly that test case, but the mixed mode dlls I have in the simplified test case I posted to Mono bug (https://bugzilla.xamarin.com/show_bug.cgi?id=37913) have native entry point.
Shouldn't I add flag to winnt.h in a separate patch? The change I made to FixupVTable is for avoiding calling times assembly_from_hmodule twice when called from _CorDllMain (which involves extra heap allocation/free). If you think it is not an issue I can simplify the patch and do not touch FixupVTable. Or change FixupVTable as first part, then the main change as the next part.
Ah, that makes sense now. I missed what you were doing with FixupVTable. I don't think parsing the header multiple times is a problem, but it also makes sense this way.
I think I've seen header changes done both ways.
On 01/27/2016 12:04 AM, Vincent Povirk wrote:
I think I've seen header changes done both ways.
I've sent 2 patches now. While looking at this more I realized that native entry point must be called not just for process attach but also for thread attach/detach, so I changed that in _CorDllMain. I removed the whole thing with switch because otherwise I was getting extra ugly checks & frees for the preloaded assembly and calls to entry point.