We ran into an interesting problem at work. We had recently migrated one of our larger .NET 3.5 applications to Windows 64-bit servers from Windows 32-bit servers. Even though the application is built on .NET, we couldn’t run it completely in native 64-bit mode because of some third-party references we use. Through that process we dug up a couple of handy nuggets of information regarding WOW64.
Quick Memory Recap
On Windows 32-bit platform, each process can only use up to 4 gig of RAM (2^32). However, your application can only use 2 gig of that 4 gig because the other 2 gig is used by the Windows kernel. There is a boot option in Windows to make the kernel space allocation to 1 gig so you can use 3 gig but there are risks to that approach.
There is still an advantage to moving a 32-bit app to a 64-bit platform even if it has to run in 32-bit mode(WOW64). Running your 32-bit app on Windows 64-bit means the process can now use the full 4 gig of RAM per process because the Windows kernel functionality has been moved out of the process.
But, as always there are a few gotchas. The application mentioned above has many components: .NET Remoting hosted in IIS, ASP.NET web site and web services and .NET Window services. We found the components that were hosted by the ASP.NET framework were taking advantage of the > 2 gig memory space. However, the .NET Windows service would start to throw Out of Memory exceptions as it approached 2 gigs.
editbin /LARGEADDRESSAWARE to the rescue
It turns out there is a header needed in your executable to flag that it is safe to allow the process to use more than 2 gigs. If you have Visual Studio installed, you should have a utility called editbin. Simply run the editbin utility on your .NET exe with the /LARGEADDRESSAWARE flag and it will modify your executable to include the header.
editbin /LARGEADDRESSAWARE C:\data\blog\WOW64Blog\WOW64Blog\bin\Debug\WOW64Blog.exe
click the image below to see a larger image:
Dumpbin (included with Visual Studio also) can be used to get information regarding an executable. If you run the following command on your exe before adding the LARGEADDRESSAWARE header, it should look something like this.
dumpbin /HEADERS C:\data\blog\WOW64Blog\WOW64Blog\bin\Debug\WOW64Blog.exe
output:
Microsoft (R) COFF/PE Dumper Version 9.00.21022.08Copyright (C) Microsoft Corporation. All rights reserved.Dump of file C:\data\blog\WOW64Blog\WOW64Blog\bin\DebugLINK : fatal error LNK1104: cannot open file 'C:\data\blog\WOW64Blog\WOW64Blog\bin\Debug'Microsoft (R) COFF/PE Dumper Version 9.00.21022.08Copyright (C) Microsoft Corporation. All rights reserved.Dump of file C:\data\blog\WOW64Blog\WOW64Blog\bin\Debug\WOW64Blog.exePE signature foundFile Type: EXECUTABLE IMAGEFILE HEADER VALUES14C machine (x86)3 number of sections494A6185 time date stamp Thu Dec 18 09:43:17 20080 file pointer to symbol table0 number of symbolsE0 size of optional header102 characteristicsExecutable32 bit word machineOPTIONAL HEADER VALUES10B magic # (PE32)8.00 linker version800 size of code800 size of initialized data0 size of uninitialized data266E entry point (0040266E)2000 base of code4000 base of data400000 image base (00400000 to 00407FFF)2000 section alignment200 file alignment4.00 operating system version0.00 image version4.00 subsystem version0 Win32 version8000 size of image200 size of headers0 checksum3 subsystem (Windows CUI)8540 DLL characteristicsDynamic baseNX compatibleNo structured exception handlerTerminal Server Aware100000 size of stack reserve1000 size of stack commit100000 size of heap reserve1000 size of heap commit0 loader flags10 number of directories0 [ 0] RVA [size] of Export Directory2618 [ 53] RVA [size] of Import Directory4000 [ 540] RVA [size] of Resource Directory0 [ 0] RVA [size] of Exception Directory0 [ 0] RVA [size] of Certificates Directory6000 [ C] RVA [size] of Base Relocation Directory25A8 [ 1C] RVA [size] of Debug Directory0 [ 0] RVA [size] of Architecture Directory0 [ 0] RVA [size] of Global Pointer Directory0 [ 0] RVA [size] of Thread Storage Directory0 [ 0] RVA [size] of Load Configuration Directory0 [ 0] RVA [size] of Bound Import Directory2000 [ 8] RVA [size] of Import Address Table Directory0 [ 0] RVA [size] of Delay Import Directory2008 [ 48] RVA [size] of COM Descriptor Directory0 [ 0] RVA [size] of Reserved DirectorySECTION HEADER #1.text name674 virtual size2000 virtual address (00402000 to 00402673)800 size of raw data200 file pointer to raw data (00000200 to 000009FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers60000020 flagsCodeExecute ReadDebug DirectoriesTime Type Size RVA Pointer-------- ------ -------- -------- --------494A6185 cv 51 000025C4 7C4 Format: RSDS, {5EA6DDBE-E293-412D-8263-2E9BD5D63D6D}, 1, C:\data\blog\WOW64Blog\WOW64Blog\obj\Debug\WOW64Blog.pdbSECTION HEADER #2.rsrc name540 virtual size4000 virtual address (00404000 to 0040453F)600 size of raw dataA00 file pointer to raw data (00000A00 to 00000FFF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers40000040 flagsInitialized DataRead OnlySECTION HEADER #3.reloc nameC virtual size6000 virtual address (00406000 to 0040600B)200 size of raw data1000 file pointer to raw data (00001000 to 000011FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers42000040 flagsInitialized DataDiscardableRead OnlySummary2000 .reloc2000 .rsrc2000 .text
running dumpbin /headers on your exe after adding the LARGEADDRESSAWARE header the output should be similar to this:
Near the top, In the FILE HEADER VALUES section you should see the comment “Application can handle large (>2GB) addresses”. As a side-note, I found that text amusing as I was expecting something along the lines of “1 LARGEADDRESSAWARE”.Microsoft (R) COFF/PE Dumper Version 9.00.21022.08Copyright (C) Microsoft Corporation. All rights reserved.Dump of file C:\data\blog\WOW64Blog\WOW64Blog\bin\Debug\WOW64Blog.exePE signature foundFile Type: EXECUTABLE IMAGEFILE HEADER VALUES14C machine (x86)3 number of sections494A6185 time date stamp Thu Dec 18 09:43:17 20080 file pointer to symbol table0 number of symbolsE0 size of optional header122 characteristicsExecutableApplication can handle large (>2GB) addresses32 bit word machineOPTIONAL HEADER VALUES10B magic # (PE32)8.00 linker version800 size of code800 size of initialized data0 size of uninitialized data266E entry point (0040266E)2000 base of code4000 base of data400000 image base (00400000 to 00407FFF)2000 section alignment200 file alignment4.00 operating system version0.00 image version4.00 subsystem version0 Win32 version8000 size of image200 size of headersDFDF checksum3 subsystem (Windows CUI)8540 DLL characteristicsDynamic baseNX compatibleNo structured exception handlerTerminal Server Aware100000 size of stack reserve1000 size of stack commit100000 size of heap reserve1000 size of heap commit0 loader flags10 number of directories0 [ 0] RVA [size] of Export Directory2618 [ 53] RVA [size] of Import Directory4000 [ 540] RVA [size] of Resource Directory0 [ 0] RVA [size] of Exception Directory0 [ 0] RVA [size] of Certificates Directory6000 [ C] RVA [size] of Base Relocation Directory25A8 [ 1C] RVA [size] of Debug Directory0 [ 0] RVA [size] of Architecture Directory0 [ 0] RVA [size] of Global Pointer Directory0 [ 0] RVA [size] of Thread Storage Directory0 [ 0] RVA [size] of Load Configuration Directory0 [ 0] RVA [size] of Bound Import Directory2000 [ 8] RVA [size] of Import Address Table Directory0 [ 0] RVA [size] of Delay Import Directory2008 [ 48] RVA [size] of COM Descriptor Directory0 [ 0] RVA [size] of Reserved DirectorySECTION HEADER #1.text name674 virtual size2000 virtual address (00402000 to 00402673)800 size of raw data200 file pointer to raw data (00000200 to 000009FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers60000020 flagsCodeExecute ReadDebug DirectoriesTime Type Size RVA Pointer-------- ------ -------- -------- --------494A6185 cv 51 000025C4 7C4 Format: RSDS, {5EA6DDBE-E293-412D-8263-2E9BD5D63D6D}, 1, C:\data\blog\WOW64Blog\WOW64Blog\obj\Debug\WOW64Blog.pdbSECTION HEADER #2.rsrc name540 virtual size4000 virtual address (00404000 to 0040453F)600 size of raw dataA00 file pointer to raw data (00000A00 to 00000FFF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers40000040 flagsInitialized DataRead OnlySECTION HEADER #3.reloc nameC virtual size6000 virtual address (00406000 to 0040600B)200 size of raw data1000 file pointer to raw data (00001000 to 000011FF)0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers42000040 flagsInitialized DataDiscardableRead OnlySummary2000 .reloc2000 .rsrc2000 .text
Compiling a .NET Windows app to run in WOW64.
As usual, it seems anything that runs in the ASP.NET framework has a leg up on Windows applications. What determines if your ASP.NET runs in WOW64 or true 64-bit is based upon what framework you have installed (either 32-bit or 64-bit). On Windows 2003 / IIS 6 this is a system wide configuration (i.e. you can’t run WOW64 and true 64-bit ASP.NET at the same time). This has been corrected in Windows 2008 / IIS 7 which allows you to target each app pool to 32-bit or 64-bit framework.
But, back to the Windows world. If you open Visual Studio, create a console app, reference a 32-bit component, deployed to Windows 64-bit server it will crash down in flames like the Hindenburg. The reason is because Windows will try and run the application in 64-bit mode because Visual Studio by default sets the target platform to be “AnyCPU”. This can be corrected by specifying your application as only targeting the 32-bit platform.
Within Visual Studio, navigate to Project->Properties->Build.
Change the Platform target to x86 and that will allow your exe to run in WOW64 mode when running on Windows 64-bit.
64-bit is a good thing. But you might find out you can’t easily switch your application to true 64-bit. These secrets can allow you to take advantage of some of the 64-bit capabilities without having to wait until you have the time to completely migrate your application to native 64-bit.
» Similar Posts
- Yes, Virginia, you can write through the BDC – Part One.
- Creating a Lookup List for SharePoint with VSeWSS
- Yes, Virginia, you can write through the BDC – Part Two.
» Trackbacks & Pingbacks
http://bilbroblog.com/trackback.ashx?id=15
» Comments
-
Nice trick. Should help us.
Joshua — March 12, 2009 10:17 PM -
Thanks for the very important comment about Server 2008/IIs7 and the option to set a website to run under 32 or 64-bit. Very important feature and very helpful to us. Thanks!
In Server 2008, if you have a website that uses older DLL third party components that are built around 32-bit systems, just create an Application Pool for your website, assign your website to the pool, then open the pool, choose Advanced Settings, and in there set your 32-bit setting to true. That allows you to use the WoW64 technology with these older DLL's.
Until the world moves into 64-bit, thats the best solution for older technologies. Sure helped us!
Website Photo Gallery Guy — March 27, 2009 11:17 AM