How does CorFlags.exe /32BIT+ work?
Asked Answered
T

2

13

I guess my question is about the CLR Loader. I want to understand the mechanics behind CorFlags.exe /32BIT+ functionality.

We know that when one starts an assembly compiled with the Any CPU flag set on 64-bit Windows, it starts as a 64-bit process. If one run CorFlags /32BIT+ on that assembly, it will start as a 32-bit process. I think this is a fascinating feature.

I have so many questions about it:

  1. How is it implemented?
  2. Does the OS Loader get involved?
  3. Is possible to build a custom application (I guess an unmanaged one) that loads 32-bit or 64-bit CLR at a wish?

Is there an article, book, blog, etc that explains the inner workings of this feature?

Tertius answered 30/4, 2012 at 19:55 Comment(0)
S
7

This isn't well documented in any place I know of, I can only point you to a relevant MSDN article. Yes, your assumption is correct, the loader in Windows XP and up has awareness of managed executables. It automatically loads the .NET loader shim (c:\windows\system32\mscoree.dll), the relevant entrypoint is _CorValidateImage(). The Remarks section in the linked MSDN article describes the mechanism that turns a 32-bit .exe file into a 64-bit process:

In Windows XP and later versions, the operating system loader checks for managed modules by examining the COM Descriptor Directory bit in the common object file format (COFF) header. A set bit indicates a managed module. If the loader detects a managed module, it loads MsCorEE.dll and calls _CorValidateImage, which performs the following actions:

  • Confirms that the image is a valid managed module.
  • Changes the entry point in the image to an entry point in the common language runtime (CLR).
  • For 64-bit versions of Windows, modifies the image that is in memory by transforming it from PE32 to PE32+ format.
  • Returns to the loader when the managed module images are loaded.

For executable images, the operating system loader then calls the _CorExeMain function, regardless of the entry point specified in the executable. For DLL assembly images, the loader calls the _CorDllMain function.

_CorExeMain or _CorDllMain performs the following actions:

  • Initializes the CLR.
  • Locates the managed entry point from the assembly's CLR header.
  • Begins execution.

The loader calls the _CorImageUnloading function when managed module images are unloaded. However, this function does not perform any action; it just returns.

Seed answered 1/5, 2012 at 1:9 Comment(4)
Thanks for the quick answer. This is a good starting point. I wanted to find out how clr deals with .reloc sections. I dug in sscli, mostly in pedecoder.h/pewriter.cpp and found my answers. Still there are many questions (e.g. what about Windows 2000 x64) but I guess I will find the answers in sscli.Tertius
That's an easy one, Windows 2000 x64 has last been seen used by the great white Yeti.Seed
Wow. I wonder if there is any way to take advantage of this "special awareness" to create proper fat (native code) binaries for Windows.Colvin
Tried that, found no answer. Probably, this magic won't work at all if no .NET is installed in the OS. Which renders this useless for native executables.Pelagian
S
2

To add on Hans' answer, there is also some Windows kernel mode code that responds to that flag. Every loaded executable has a kernel structure, SECTION_IMAGE_INFORMATION, associated with it. Here's its symbol information:

 0: kd> dt nt!_SECTION_IMAGE_INFORMATION
           +0x000 TransferAddress           : Ptr64 Void
           +0x008 ZeroBits                  : Uint4B
           +0x010 MaximumStackSize          : Uint8B
           +0x018 CommittedStackSize        : Uint8B
           +0x020 SubSystemType             : Uint4B
           +0x024 SubSystemMinorVersion     : Uint2B
           +0x026 SubSystemMajorVersion     : Uint2B
           +0x024 SubSystemVersion          : Uint4B
           +0x028 GpValue                   : Uint4B
           +0x02c ImageCharacteristics      : Uint2B
           +0x02e DllCharacteristics        : Uint2B
           +0x030 Machine                   : Uint2B
           +0x032 ImageContainsCode         : UChar
           +0x033 ImageFlags                : UChar
           +0x033 ComPlusNativeReady        : Pos 0, 1 Bit
           +0x033 ComPlusILOnly             : Pos 1, 1 Bit
           +0x033 ImageDynamicallyRelocated : Pos 2, 1 Bit
           +0x033 ImageMappedFlat           : Pos 3, 1 Bit
           +0x033 BaseBelow4gb              : Pos 4, 1 Bit
           +0x033 Reserved                  : Pos 5, 3 Bits

The flags ComPlusILOnly and ComPlusNativeReady are related to .NET, ComPlusILOnly simply tells if the assembly is CIL only (not mixed or native - in which case the assembly is already architecture specific), and ComPlusNativeReady is 1 only if /32BIT+ is not set (32BITREQ or 32BITPREF in newer CorFlags version). Those flags are checked during nt!PspAllocateProcess and based on them a 32-bit or 64-bit process is created.

I wrote about it with some details.

Shawm answered 18/4, 2015 at 19:10 Comment(1)
Many thanks!!! I've got confused in calculating some offsets of fields this structure using obsoleted information in Windows NT/2000 Native API Reference.Apologete

© 2022 - 2024 — McMap. All rights reserved.