views:

212

answers:

5

Working on porting a 32bit Windows C++ app to 64 bit. Unfortunately, the code uses frequent casting in both directions between DWORD and pointer values.

One of the ideas is to reserve the first 4GB of virtual process space as early as possible during process startup so that all subsequent calls to reserve memory will be from virtual addresses greater than 4 GB. This would cause an access violation error any unsafe cast from pointer to DWORD and then back to pointer and would help catch errors early.

When I look at the memory map of a very simple one line C++ program, there are many libraries loaded within bottom 4GB? Is there a way to make sure that all libraries, etc get loaded only above 4GB?

Thanks

+1  A: 

The best solution is to fix these casts ...

You may get away with it truncated the pointer regardless (Same as casting to a POINTER_32) because I believe windows favours the lower 4GB for your application anyway. This is in no way guaranteed, though. You really are best off fixing these problem.

Search the code for "(DWORD)" and fix any you find. There is no better solution ...

What you are asking for is, essentially, to run 64-bit code in a 32-bit memory mode with AWE enabled (ie lose all the real advantages of 64-bit). I don't think microsoft could be bothered providing this for so little gain ... and who can blame them?

Goz
Did you read the question? The poster isn't asking how to avoid addresses over 4 GB. (And if so, the answer would be to pass /LARGEADDRESSAWARE=NO to the linker.) And there are much better ways to find pointer truncation problems than to grep the code for C-style casts.
bk1e
+6  A: 

Compile your project with /Wp64 switch (Detect 64-bit Portability Issues) and fix all warnings.

Paul
Isn't that option declared as "deprecated" ?
LiraNuna
Thanks. I will try this flag.
CeeMan
Just compiling with the x64 compiler should get you all the warnings (and more accurately than /Wp64 - which is why that switch is deprecated).
Michael Burr
The documentation says that /Wp64 is deprecated, and it will generate annoying "Command line warning D9035 : 'Wp64' has been deprecated and will be removed in a future release" warnings, but enabling it for your x64 builds will give you useful warnings (regarding casting pointers to/from smaller integral types) that you would not get otherwise.
bk1e
I checked MSDN - it is deprecated since VS2008 and I am using VS2005 where it is not deprecated yet.
Paul
+2  A: 

You could insert calls to VirtualAlloc() as early as possible in your application, to allocate memory in the lower 4GB. If you use the MEM_RESERVE parameter, then only virtual memory space is allocated and so this will only use a very small amount of actual RAM.

However, this will only help you for memory allocated from the heap - any static data in your program will have already been allocated before WinMain(), and so you won't be able to change it's location.

(As an aside, even if you could reserve memory before your main binary was loaded, I think that the main binary needs to be loaded at a specific address - unless it is a built as a position-independent executable.)

Dave Rigby
Thanks. I am planning to use VirtualAlloc in one of DllMain's if possible. The problem is MSVC Runtime gets loaded before 4GB. The executable has a preferred address higher than 4GB hence that is fine getting loaded above 4GB.
CeeMan
You can change the location of your program's (or DLL's) static/global data and code by setting its preferred base address at link time, or by using rebase.exe to change its preferred base address.
bk1e
Some cerative abuse of delay loading DLLs can allow you to call VirtualAlloc() before most DLLs load. Obviously you'll still need Kernel32.DLL loaded.
MSalters
+1  A: 

1) Recommend article about /wp64 and porting: 64 bits, Wp64, Visual Studio 2008, Viva64 and all the rest...

2) You can find all the bad casts and many other errors using the specialized tool Viva64.

Andrey Karpov