Search code examples
.net.net-framework-version

What is the main difference between a PE and MSIL? Why do we explicitly use ILASM,NGEN.EXE when we have JIT compiler by default?


The concept of MSIL kept inside a PE file of PE format is confusing me. And why should we use ILASM.exe to generate a PE file and NGEN.EXE to generate a native code, when we have a JIT compiler that itself can do both by itself?


Solution

  • The PE file format is used on Windows to store executable code, DLL and EXE files. It is a very flexible format, it can contain many more things than just code. A capability that .NET exploits, a .NET assembly is a PE file with just 5 bytes of code. The rest is all data. You can compare it to a Java .jar file. That data is a header that identifies the runtime version that's required. A chunk of metadata that describes the types in the assembly. And a chunk of MSIL, the intermediate code that will be just-in-time compiled to machine code at runtime.

    You don't need ilasm.exe to generate such a file. Any .NET compiler knows how to create one. Under the hood, they all use the same low-level api to write an assembly.

    Ngen.exe is optional, it can help to improve the warm start of a program and bypass the need to just-in-time compile the MSIL to machine code. Instead of doing it at runtime, Ngen does it ahead of time. The generated machine code is stored in a file in c:\windows\assembly. The CLR will find it back there when you run the program and will bypass the jitting step, using the machine code in the file instead. The original assembly is still required for the metadata.

    Key point is that ngen.exe is optional. It is not always better to compile ahead of time, it actually makes the cold start of a program slower since it requires the CLR to find an extra file. Cold start times are dominated by the disk, they are slow.