A C compiler can generate a 64-bit executable where pointers are 32-bit?

Asked

Viewed 998 times

35

Most programs fit well into address space of less than 4GB, but in some cases the program may need to use new processor features/instructions that are only available on x64 architecture. Unfortunately the normal procedure would be to generate a 64-bit executable and gain the cost of the pointers to be twice the size.

There are specific applications where most data structures have a large part of their pointer elements. Big pointers will produce miss cache more frequently and if you will not use memory beyond 4GB, 64 bit pointers are pure waste.

Are there compilers where I can use specific x64 registers and instructions, but preserving the 32-bit pointers to save memory? On which platforms?

Is it possible to do this transparently in legacy code? There is a switch/flag to link this in the compiler?

If it is not possible to work with legacy code, which you need to change in code to get 64-bit resources while maintaining 32-bit pointers?

I know this is only advantageous if this memory saving is really important.

  • In my view this should not be a concern, because in most cases applications have a higher performance when compiled in 64-bit version. The focus must be other to obtain performance, such as caching the most used information or that have high I/O cost.

2 answers

34


Yes, that is possible.

However, understand that this is not as simple as it seems. 32-bit libraries expect you to pass arguments through records in a given format, and pointers to be 4 bytes. The 64-bits use another incompatible form and the 8-byte pointers. If you are going to use 4-byte pointers and all other features equal to how it would be in 64-bit, neither of the two versions of the library will be compatible with your program. This basically means that you will need to compile all libraries that you use in this format.

Another problem is in the kernel. When making a system call, arguments are also passed differently. Then you will also need special kernel support to run a program like this.

This is implemented as a new architecture, the x32:

Wikipedia

To compile a program in x32 mode, you will need a reasonably modern linux environment:

  • Linux 64-bit version 3.4 compiled with CONFIG_X86_X32 option.
  • GLIBC 2.16
  • GCC 4.7
  • Binutils 2.22

My standard Ubuntu installation comes with these requirements. Compiling a program in x32 mode is simple: add to flag -mx32 to gcc. I was able to run the compiled programs without any additional procedure and observing the generated Assembly it is clear that 64-bit registers are used, even with 32-bit pointers.

Since it is a relatively new feature (integrated into the kernel at the end of 2011) and little used (i.e., poorly tested in production), it is possible that minor problems will be encountered.

If you don’t want to change architecture and prefer something more "stable", another option would be to exchange all pointers for uint32_t and make a conversion whenever necessary. There is no loss of performance as this conversion does not generate instructions. However there is the problem that the pointer points to something other than 4GB. This will happen, for example, for all stack pointers, since the stack starts at the end of the process virtual memory.

0

I don’t know if it helps, but in Visual C++ there is a link flag /LARGEADDRESSAWARE, that allows a 32bit executable to access up to 3 gigabytes of RAM, instead of 2, when it runs on a 64 version of Windows.

I use this at work because we have a program that often needs to allocate more than 2 gigs.

According to the flag documentation, it is possible to pass /LARGEADDRESSAWARE:NO for 64 programs, which limits those programs to 2 gigabytes of RAM. It is possible that this causes the pointers to be also in 32 bits, but I did not check.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.