GAC Nitty Gritty, Part 2

In the first post, we've gone through GAC, SNK, and how the CLR is loading the signed assemblies, in this post we'll examine the folder structure of the GAC, and see how the GAC is working behind the scenes, for more information please refer to the first part.

GAC Folder Structure

Global assembly cache is just a physical folder; just like any other folder, but when you browse to the default GAC location at : %WinDir%\assembly, the windows shell extension SHFusion.DLL shows you the customized GAC folder, the truth is that GAC is just a windows folder, if you hit your CTRL+R, and enter %WinDir%\assembly\gac , you will get the contents of the GAC folder, however browse one level up to %WinDir%\assembly, voila, now you can the folders under the GAC location, these are processed by SHFusion.DLL to show you the customized view of the GAC contents, now we'll examine the folder structure of the GAC

  • GAC : this folder contains .NET Framework 1.x assemblies.

  • GAC_32 : this folder contains assemblies to be run on 32bit operating systems, considering the operating system word size to be 32 bits.

  • GAC_64 : this folder contains assemblies to be run on 64bit operating systems, the word size is 64 bits, so the JIT compiler compiles these assemblies considering they will be running in 64bits environment, also note that if your OS is 32 bits so you will not have this folder in your GAC, but if your OS is 64 bits, so you will have both GAC_32 and GAC_64 folders, that is because Windows 64bit is able to running 32 bits applications through emulation or what's called WoW ( Windows on Windows ), for more information about WoW 32-bit emulator, please refer to this post.

  • GAC_MSIL : this folder contains assemblies that can run on either 32bit or 64bit platforms, they are compiled into MSIL, and in runtime, the JIT (Just In Time) Compiler, compiles them to the proper machine code ( with support for target word size ).

  • NativeImages_Vx_WordSize : whenever you compile your assemblies; they are compiled to MSIL code, and in runtime JIT compiler compiles the code to the machine language, this process is costly, so if you want to boost your application performance, you can use a .NET utility called NGen.exe, this utility compiles your MSIL assemblies to the machine language right away, saving you JIT compilation time, and this greatly boosts your application performance, taking into consideration that assemblies compiled using NGen are machine specific and not deployable, so first you have to deploy your assemblies, and then run NGen.exe on them, to generate the pre-compiled assemblies, so the native image of one assembly is the precompiled assembly, and they are saved in this folder, considering framework version ( Vx ), and word size 32bits or 64bits, ( WordSize ), so you will end up with more than one NativeImages folder according to your OS word size, and .NET framework versions you have installed, NGen is an interesting topic, to get more information about it, please refer to this MSDN column CLR Inside Out .

  • Temp folders : these are temporary folders.
Note that the Processor Architecture column in the GAC view, this reflects in which folder the assembly is saved.

So how .NET framework achieves versioning, let's take one example, if you open GAC_32 folder and then open Microsoft.SqlServer.Replication folder, you will find one folder named, apparently this is the folder name is the assembly name ( without .DLL extension ) , and the sub folder follows this pattern AssemblyVersion__PublicKey, go one level down and open this folder you will find the assembly named Microsoft.SqlServer.Replication.dll

Select the file, and hit Alt+Enter ( for properties ), select Version tab, you will find the comments field under other version information -> Item Name, has the value "NT INTEL X86", this explains why the assembly is placed inside GAC_32.

Select Digital Signatures tab, select Microsoft Corporation from Signature List, have a look at Timestamp column, then click Details button, click the Advanced Tab

Voila, Digest algorithm is SHA1, Digest encryption algorithm is RSA, and the message digest is there as well, so let's recall what we've explained in last post, in runtime CLR has the public key and the assembly contents ( MSIL + metadata ), it uses the assembly contents to generate a hash value using SHA1 algorithm, then it decrypts the encrypted message digest to get the original hash value ( message digest ), then it compares the one it generated first, to the one that 's just decrypted, if they are equivalent so it loads the assembly ( or installs it in the GAC if the assembly is to be installed in the GAC ), otherwise the installation or loading of the assembly is discontinued.

Now, everything is clear and we know how CLR manages versioning, so for target="_blank" each and every assembly version you install in the GAC, one folder is created behind the scenes to hold this new assembly version.


This post is not intended to teach you how to use the GacUtil.exe, however it is very simple to install and uninstall one assembly, for detailed information about the command line of Gacutil.exe please refer to MSDN, Global Assembly Cache Tool.

Tip: one of the differences between GAC in .NET 1.x and 2.0, is that when you use GacUtil /u AssemblyName.dll, it fails to uninstall the assembly, the right way to uninstall one assembly is to just pass the assembly name with no extension, and also it's worth mentioning that you can access the GAC through a set of APIs.

References and Related Readings
I hope I could make it clear, however if you have any comments, inquires, or you find any inconsistent information, please leave me a comment.


Links to this post:

Create a Link