When a managed application is built on Visual Studio , we get four options to choose for a platform .Lets discuss these options in detail .
X86 is the generic name for all Intel x86 32 bit architectures. If you build your application using x86 switch , your binary will run as 32 bit process. Technically speaking a pure managed application is compiled into MSIL .So when this IL is jitted or you convert IL image to native image using NGEN, 32 bit code will be generated .And if an application is a mix mode application, the native code generated will be 32 bit.
X64 refers to 64 bit descendant of x86 family. There are two major 64 bit architectures available ,one is x64 and other is IA64. These architectures are totally different architectures .Following are major differences in terms of compatibility with x86:
a) Instruction Set
· The Itanium processor has a different instruction set from its x86 predecessors; in fact, it had a new kind of instruction set altogether, a kind which it called EPIC, which stands for, Explicitly Parallel Instruction Computing, it is not backwardly compatible with the established x86 instruction set.
· The instruction set for the x64 is a superset of that the x86 instruction set. In fact, only two instructions were added in Opteron from AMD!
b) Capability to run x86 code.
· The Itanium processor incorporates a decoder that translates x86 instructions into EPIC instructions .That decoding process takes time, and, as a result, x86 applications perform relatively poorly on Itanium processors: they run at the speed they typically would on a 1.5 GHz Xeon processor. Crucially, a machine with an Itanium processor cannot boot an x86 operating system. Although the Itanium CPUs packaged inside Itanium PCs cannot boot a 32-bit OS, that was in fact a design goal for the chip. They still support 16-bit real mode and are capable of booting DOS. The EFI firmware and many other changes to the PC block that from happening any more.
· Second, the processor has a switch to be flipped by the operating system that determines whether it is executing instructions in 32-bit or 64-bit mode. If the operating system is itself 32-bit, then the processor goes into 32-bit mode for the duration of its execution of that O/S. If the operating system is 64-bit, but a 32-bit x86 application is executed, then the processor goes into 32-bit mode as it executes that application’s instructions.
So if you use x64/Itanium, binary generated will run as a 64 bit process. Again if it is pure managed application is compiled into MSIL .So when this IL is jitted or you convert IL image to native image using NGEN, 64 bit code will be generated .And if application is a mix mode application native code generated will be 64 bit.
3) Any CPU
If you use this option code generated can run on any platform. Pure managed code can only have this option. To be very precise, It will compiled into 32 bit code on a 32 bit machine and into 64 bit code on 64 bit machine.
Your application’s manifest contains a field corflags. The value of this filed, among other things determines whether IL will be converted to a 32 bit code or 64 bit code. Corflags field is a bit field and, Its following are of interest to us :
1) 0x1(IL_ONLY) It means that assembly’s code is IL_ONLY that is it is pure IL thus it can be compiled to either 32 bit or 64 bit
2) 0x2(32BIT_ONLY) means that assembly’s code must be compiled to 32 bit code and cannot be compiled to 64 bit.
3) 0x8 means assembly is signed.
Open assembly file in ILDASM and have a look at its manifest. Value of corflags field can be found at bottom of the manifest file. A value of 0x3 means assembly contains pure IL but it can be compiled only into 32 bit code. 0xb means assembly is signed contains IL only code with restriction that it can be compiled only as 32 bit code.
Note on opening the assembly in dumpbin utility one finds that x64 and IA64 images generated by the compiler with /platform:x64 or :IA64 are PE32+ images (the 64bit extension to PE32) whereas x86 and MSIL(IL_ONLY) are PE32 images (otherwise they wouldn’t work on 32bit OS’s). When the OS loader comes across a managed image the first thing it does is hand it to some CLR code called the shim (mscoree.dll) which among other things modifies MSIL images in memory to turn them into PE32+ images before handing them back to the OS loader to get the OS loader to load your app as a 64bit process.
If your assembly is running as a 32 bit process it cannot load a 64 bit dll and vice versa. If it tries to load a 64 bit dll we get a BadImageFormat Exception. Technically speaking a 32 bit process should never load a 64 bit dll. To be very precise the only 64 bit dlls that a 32 bit process can load are WOW dlls and ntdll.dll which are essential for it to run on a 64 bit machine. Following is a brief description of WOW64 dlls.
- Wow64.dll provides the core emulation infrastructure and the thunks for the Ntoskrnl.exe entry-point functions.
- Wow64Win.dll provides thunks for the Win32k.sys entry-point functions.
· Wow64Cpu.dll provides x86 instruction emulation on Itanium processors. It executes mode-switch instructions on the processor. This DLL, on all WOW64 variants, abstracts out the code needed to execute x86 instructions. On IA64, it can either use the IA64 hardware or software emulator. On x64 it is responsible for the mode-switch via JMP FAR.
If an assembly on loading is throwing a BadImageFormat Exception, first thing to do is check the corflags field. Typically
1) Open assembly’s manifest in ildasm tool. Check its corflags field.
2) If its value is x64 , your assembly has a dependency on a 32 bit dll. Either change the dll to 64 bit or modify corflags field to x86.
3) If its value is Any CPU , and you are running on a 64 bit machine , it is same scenario as described in 2.
Most of the times above two are the only reasons. In order to modify corflags field
1) Either use a utility known as corflags in order to change the corflags field without recompiling the assembly. Note that however if assembly is signed it needs to be resigned which can be done using sn tool.
2) Or best option is to recompile your application with appropriate /platform flag.