开发者

Why is IL code packed into an exe in a C# application?

I was trying to regenerate an exe by doing a round trip of ILDASM and then ILASM on a C# executable file. As I understand, the .il file generated by ILDASM is sufficient to generate .exe back.

I am curious that why .NET framework is designed to use an exe file for deployment instead of depl开发者_Python百科oying a .il file to the users. Could not c# compiler generate .il file and the JIT compiler use the .il file directly as an input? Is it simply because operating system needs .exe extension to invoke the loader, or is it because of file size or performance considerations?

PS: The question is not of practical significance. I am asking this question to make my concepts more clear, as I am sure I am lacking a lot.


It wouldn't make any sense to add another type of extension just to cater for .NET.

.NET executables are PE files and they provide a minimal amount of native code to bootstrap the correct version of the CLR and pull the IL into memory and hand off to the CLR.

Windows natively knows what to do with PE files and with the indirection mechanism built into the EXE Windows also doesn't need to know about .NET.

With a .il file you'd need to register the extension with Windows then make sure that the correct version of the CLR is loaded - as far as I know you can only associate an extension with one executable.

To support multiple versions of the CLR you'd need some kind of intermediary that then inspects your .il file to determine which CLR to load....and things just get convoluted and fragile after that.

Packaging all this in a PE solves these problems neatly and elegantly.

Although this is an older article, the principles remains the same in current .NET Frameworks:

An In-Depth Look into the Win32 Portable Executable File Format, Part 2

The key section "The .NET Header" explains how this works:

Executables produced for the Microsoft .NET environment are first and foremost PE files. However, in most cases normal code and data in a .NET file are minimal. The primary purpose of a .NET executable is to get the .NET-specific information such as metadata and intermediate language (IL) into memory. In addition, a .NET executable links against MSCOREE.DLL. This DLL is the starting point for a .NET process. When a .NET executable loads, its entry point is usually a tiny stub of code. That stub just jumps to an exported function in MSCOREE.DLL (_CorExeMain or _CorDllMain). From there, MSCOREE takes charge, and starts using the metadata and IL from the executable file. This setup is similar to the way apps in Visual Basic (prior to .NET) used MSVBVM60.DLL. The starting point for .NET information is the IMAGE_COR20_HEADER structure, currently defined in CorHDR.H from the .NET Framework SDK and more recent versions of WINNT.H. The IMAGE_COR20_HEADER is pointed to by the IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR entry in the DataDirectory. Figure 10 shows the fields of an IMAGE_COR20_HEADER. The format of the metadata, method IL, and other things pointed to by the IMAGE_COR20_HEADER will be described in a subsequent article.


.exe files are smaller.
They also follow the existing standard PE format, making Windows integration simpler.

Java needs to register the .jar extension and associate it with java.exe in the path of a single JRE.

By contrast, since .Net assemblies are also normal Windows executables, .Net doesn't need to register any file associations. Instead, a .Net EXE contains code that locates the correct version of the runtime and invokes it to execute the EXE.
This allows multiple versions of the runtime to coexist on the same machine, without requiring a separate loader that would open a .il file, figure out what version it is, then run it with the correct version.

Also, parsing is slow; .il files would execute more slowly because the runtime would need to parse the IL.


Early versions of windows had no operating system level support for .net. That leads to some alternatives:

  1. An exe file that loads the .net CLR and then uses that to run the IL. The disadvantage of that is that you can't distinguish an exe containing .net IL and a native exe. This is relevant if you want to run it with reduced .net privileges.
    That the program is indistinguishable from a native program at a glance might lead to higher acceptance.
    It also allows replacing a native program with a .net program without needing to change all the code that calls it.
  2. A new file format containing binary IL. Similar to java's jar files. When doubleclicked they'd be opened with the associated program. Something like "rundotnet.exe myprogram.net".
    This leads to problems with programs that assume a one to one mapping between program executables and logical programs. This includes firewalls and the taskbar grouping feature. In the taskmanager you don't see what the multiple "rundotnet.exe"s you see correspond to,...
    And assemblies that mix native and .net code aren't possible with this solution either.
    The big advantage of this is that the program code can be verified by the .net runtime before execution.
  3. A PE file with a new file extension. That's my favorite one. In old versions of windows you can simply add a registry entry to run is as a normal program, and on new versions you can give it the special treatment. This avoids the problems of both 2 and 3.

With built in OS support it'd be possible to avoid most of the problems of a separate file format. Choosing 1) over 2) is understandable, but I don't know why they didn't choose 3. My guess is that they liked having all (modern) executables having the same file extension.


The .Net runtime/JIT uses the byte code representation of IL. This is similar to assembly being compiled into machine code. It takes less impact and is easier to verify integrity of the binary data than if you were to try to maintain the IL as the "executable" code. It would also make the files larger.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜