I'm starting to look seriously into the rotor sources. Since they are fairly large, I thought I'd start at the begining and wade my way through deeper and deeper. I've decided to write some light comments as I go along, trying to put my thoughts in order and make sure I get it right. Don't expect anything out of this world, though... it's very likely I'll make mistakes as I learn about it, but I hope my good friends more familiar with the SSCLI set me straight :)

So, to begin, I decided to take a look at what the start-up tool, clix.exe, does when starting a managed application. You'll find the source for this utility in your sscli\clr\src\tools\clix directory.

The magic of clix begins, of course, at its main() function. While long, there's not much to say about it. It basically parses the command line and calls the meaty Launch() function to start the application. However, there's an interesting line right at the start of main():


From looking at its Win32 implementation (located in sscli\pal\win32\win32pal.c), it looks as if all it did was return a handle to an already loaded module (which clix immediately discards). On the other hand, the Unix version, located in sscli\pal\unix\loader\module.c, does a little bit more, ending with a call to LoadLibraryW(), implemented a little bit lower in the same file.

By now, you're probably asking what all this talk of the PAL is... well, the PAL, as I see it, is basically just an abstraction layer, similar to the Windows NT HAL. The PAL implements, among other things, a bunch of the basic Win32 APIs on Unix systems, so that most of the code in Rotor could remain unchanged. This is evident by the fact that most of the Win32 version of the PAL fits roughly in 8 or so files, while the Unix one has a few dozens :)

Now, back to clix.exe, it's time to look at the Launch() function, whose signature is:

DWORD Launch(WCHAR* pRunTime, WCHAR* pFileName, WCHAR* pCmdLine)

The first argument, pRuntime, is the name of the managed runtime to load, which in this case is hardcoded to be the constant MSCOREE_SHIM_W. The exact value of this constant varies with the platform, but you can see it defined in sscli\clr\src\inc\cor.h starting line 135. The second and third arguments are self evident.

Now, what Launch() basically does is memory-map the specified file, ensure it is a valid PE image and that it has the appropriate COR headers in place (that is, validate it is a valid managed image). Once that is done, it will load the the actual runtime engine and call into its _CorExeMain2() exported function to run the image.

Next time around, I'll explore (hopefully) what it is that _CorExeMain2() does and how the runtime starts up.

Tomas Restrepo

Software developer located in Colombia.