Thursday 7 February 2013

32 vs 64 bits again and again

Well, I already posted about the 32 vs 64 bits here and here. The thing is that I've come up today with a couple of new doubts with their ensuing answers, and I thought I should invoke a SerializeToBlog on them.

I've run into these issues while doing some .Net prototyping of a Windows Service doing P/Invoke calls. Admittedly, it's been a long while since the last time I needed to resort to P/Invoke, and that was a time when I still did not have any 64 bits machine. I ran into some stupid problems with the number of bits and installation of the output executable (that I won't further explain here to avoid public shame). I was using some functions in kernel32.dll, and one folk at work mentioned that using kernel32 could be forcing my .exe to be compiled as a 32 bits one. It seemed to make sense, as it would seem natural that the 64 bits of the dll would be called kernel64 or something alike. Well, pretty wrong assumption. Some googling brought up that the 64 bits version of the dll continues to be called, kernel32.dll, and to add up to the confusion it's located on: c:\Windows\System32!. The 32 bits version is located on c:\Windows\sysWOW64.

In the process of shedding some light on the above, I was playing around with Process Explorer to check the different dll's loaded by a 32 bits and a 64 bits version of the same .exe.
A 32 bits version will load the 32 bits versions of clr.dll and clrjit.dll (located on C:\Windows\Microsoft.NET\Framework\v4.0.30319 for .Net 4.5) and the 64 bit versions (located on C:\Windows\Microsoft.NET\Framework64\v4.0.30319) when it's a 64 bits .exe. So far so good, as clr.dll and clrjit.dll are native dll's and therefore they've been compiled for the different architectures.
Another natural finding was that for normal assemblies part of the BCL, something similar was happening. For the 32 bits process, the NGen'ed assemblies in C:\Windows\assembly\NativeImages_v4.0.30319_32 were being used, and the ones in C:\Windows\assembly\NativeImages_v4.0.30319_64 for the 64 bits version. This makes sense, cause as assemblies are jitted to 32 or 64 bits at execution time depending on the process, the same is done when compiled ahead of time.

The odd thing for me comes when we check the locations of the non precompiled BCL assemblies, again folders:
C:\Windows\Microsoft.NET\Framework and C:\Windows\Microsoft.NET\Framework64.
We have many native applications and dll's there, but for the .Net assemblies, they seem to be repeated on both folders. Hey, these assemblies contain just bytecodes, they should be architecture independent as mentioned in countless excellent articles like this, so why 2 versions?

Well, I sort of understand that some of the more low level assemblies there can contain some internal calls into the CLR that make necessary these different versions, but seems very odd to me that all the assemblies there need this. I haven't found any explanation about this on the net, but my tests show me that for some assemblies (like for example System.ServiceProcess.dll) the copies on both folders are just the same file (I did a binary diff), but on the other hand, the copies of mscorlib.dll are different files. I guess they duplicate the files to keep the thing more homogeneous.

If we run the corflags tool on these assemblies we'll see that while System.ServiceProcess.dll was compiled as AnyCPU, mscorlib.dll was compiled as 32 or 64 depending on the folder.

No comments:

Post a Comment