4

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

CeeMan
  • 41
  • 3

5 Answers5

6

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

Paul
  • 13,042
  • 3
  • 41
  • 59
  • Isn't that option declared as "deprecated" ? – LiraNuna Jul 22 '09 at 23:51
  • 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 Jul 23 '09 at 00:44
  • 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 Jul 23 '09 at 05:25
  • I checked MSDN - it is deprecated since VS2008 and I am using VS2005 where it is not deprecated yet. – Paul Jul 23 '09 at 07:47
  • /Wp64 is deprecated because it doesn't work very well. The 64-bit compiler is a better choice to find truncation problems at compile time. To find problems at runtime see shoelzer's answer. – Bruce Dawson May 07 '15 at 18:31
4

As a programmer, what do I need to worry about when moving to 64-bit windows?

Community
  • 1
  • 1
MSN
  • 53,214
  • 7
  • 75
  • 105
3

Bruce Dawson posted code for a technique to reserve the bottom 4 GB of VM:

https://randomascii.wordpress.com/2012/02/14/64-bit-made-easy/

It reserves most of the address space (not actual memory) using VirtualAlloc, then goes after the process heap with HeapAlloc, and finishes off the CRT heap with malloc. It is straightforward, fast, and works great. On my machine it does about 3.8 GB of virtual allocations and only 1 MB of actual allocations.

The first time I tried it, I immediately found a longstanding bug in the project I was working on. Highly recommended.

shoelzer
  • 10,648
  • 2
  • 28
  • 49
  • 1
    The early VirtualAlloc technique won't prevent all code from being in the bottom 4 GB, but it is rarer for function pointers to get truncated so this may not matter. Plus, ASLR should be placing your binaries above the 4 GB line, especially if you put it in extra-entropy mode. – Bruce Dawson May 07 '15 at 18:33
2

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.)

DaveR
  • 9,540
  • 3
  • 39
  • 58
  • 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 Jul 23 '09 at 00:04
  • 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 Jul 23 '09 at 05:29
  • 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 Jul 23 '09 at 10:38
1

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
  • 61,365
  • 24
  • 124
  • 204
  • 1
    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 Jul 23 '09 at 05:33