12

I am working on porting an application to 64-bit on Linux platform. The application is currently supported on Linux, Windows, Mac 32-bit and Windows 64-bit. One of the issues we are frequently encountering is the usage of long for int and vice versa. This wasn't a problem till now since long and int are interchangeable (both are 4 bytes) in the platforms the application is currently supported on. The codebase being a huge one, with lots of legacy code with #defines for many data types, makes it cumbersome to search all usage of long and replace appropriately with int.

  1. As a short term solution, is there a way to make GCC use 4 bytes instead of 8 for 'long'?
  2. If it has, what are issues that we might face? If not, is there an easier way to fix the long and int problem?
Chethan Ravindranath
  • 2,001
  • 2
  • 16
  • 28
  • 6
    This is not a solution for your immediate problem (hence the comment), but for future code I would use exact width types instead (e.g., `uint32_t`). – Marco Leogrande Oct 09 '12 at 07:13

3 Answers3

10

-m32 generates 32-bit code.

-mx32 generates 64-bit code but uses 32-bit longs and pointers.

Intel 386 and AMD x86-64 Options

Windows programmer
  • 7,871
  • 1
  • 22
  • 23
  • But how would that interact with the system libraries using 64 bit longs? – johv Oct 09 '12 at 07:26
  • The original poster seems to need longs to be 32 bits, so they need to link to libraries that work with 32 bit data. I think that when a function gets called, when it needs a 32 bit parameter, it doesn't care what datatype the caller had, and it doesn't care if the caller was a C function. But yes, the caller has to be sure not to call a library that expects 64 bit values. – Windows programmer Oct 09 '12 at 07:35
  • 2
    @johv: It won't. With -m32 you need to use libraries with the "usual" 32-bit x86 ABI, with -mx32 you need X32 libraries. – janneb Oct 09 '12 at 07:48
  • @Windowsprogrammer: Thanks! The problem i see with -mx32 is that it also truncates the pointers to 32-bit which somewhat defeats the purpose of supporting an application to 64-bit. I was looking more in terms of just make the long 4 bytes just like windows 64 does. – Chethan Ravindranath Oct 09 '12 at 07:52
  • 1
    So you want to generate 64-bit code, but you want datatype long to be 32-bits. Then a very ugly possibility is -Dlong=int, which will usually work but some coding styles might prevent it. – Windows programmer Oct 09 '12 at 07:57
  • 4
    @Windowsprogrammer: `-Dlong=int` translates `long int` to `int int`, which is a syntax error. – Keith Thompson Oct 09 '12 at 10:08
  • Keith Thompson, you are 100% correct about "-Dlong=int translates long int to int int, which is a syntax error", which is 100% the reason why you replied to my comment saying "but some coding styles might prevent it". You did read before replying, right? – Windows programmer Oct 09 '12 at 22:54
  • @Windowsprogrammer Any use of `long long` would also prevent it. – Daniel Fischer Oct 09 '12 at 22:58
  • Daniel Fischer, you're right, there are more problems than just coding styles. I guess I don't know any simpler solution than fixing the program itself. – Windows programmer Oct 11 '12 at 02:13
6
  1. No. On Linux x86_64 the ABI specifies that long is a 8 byte type (LP64). In fact, most if not all 64-bit Unix systems (including 64-bit OS X, AFAIK) are LP64 so this is nothing specific to Linux.

  2. Beyond fixing your code, no.

If you need a portable integer type which is large enough to store a pointer value, use intptr_t or uintptr_t (but usually wanting to store a pointer value into an integer means that you're doing something wrong, so think twice!). For an integer type which is capable of representing the difference between two pointers, use ptrdiff_t. For sizes of objects, use size_t.

janneb
  • 36,249
  • 2
  • 81
  • 97
  • If the run-time libraries are statically linked, the ABI shouldn't care about which type the compiler calls "long", provided that any external library prototypes are defined using fixed-width types and the compiler doesn't try to do annoying things with aliasing of types which have the same representation but don't match. – supercat May 18 '16 at 22:45
  • Is this answer obviously wrong (cf. the one from WinProg) or do I miss somehting? – calandoa Mar 14 '18 at 11:33
  • @janneb: This answer states that it is not possible for gcc on x86_64 to use 4 bytes for `long`. But yes, it is possible with the right flag, as indicated in the other answer. – calandoa Mar 14 '18 at 15:15
  • @calandoa: With the -m32 or -mx32 switches the compiler won't generate code for the 64-bit x86_64-pc-linux-gnu target, but rather for a 32-bit x86 target (i686-pc-linux-gnu and whatever the exact target triplet for X32 is). – janneb Mar 14 '18 at 17:30
  • @janneb: please refer to the [doc](https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mx32): _"The -mx32 option sets int, long, and pointer types to 32 bits, and generates code for the x86-64 architecture."_. But I think there is a confusion here in the question and in your answer (as there was on my side 10mn ago before I dig) : architecture can be 32 or 64, and ABI can be 32 or 64 too, so we end up with 32-32, 64-32 and 64-64 combinations. [1/2] – calandoa Mar 15 '18 at 11:58
  • You are assuming the question deals only with the ABI, but maybe the asker is more interested by the 64 bits architecture (e.g. for performances) than the 64 bits ABI (e.g. to link with specific libraries). I would propose to improve your answer, though I can write another one myself. [2/2] – calandoa Mar 15 '18 at 11:58
  • @calandoa: Yes, you're right in the sense that X32 actually runs the CPU in long (64-bit) mode, and works by zero-extending pointers to 64 bits, whereas the traditional 32-bit mode needs to switch the CPU to the 32-bit protected mode. But, that's a bit of technical trivia that I don't think is actually relevant to the question. Furthermore, the X32 ABI has seen roughly zero uptake, making it even less likely that it's what the OP was actually interested in. – janneb Mar 16 '18 at 07:45
3

It depends on what you mean by "porting to 64 bit".

  1. You simply want your application to work on a 64-bits linux: you can compile it in 32-bits and it will run in compatibility mode on most distributions which provides the 32-bits libraries. For this you must use a 32 bits version of gcc (e.g. package gcc:i386 on Ubuntu), or use the -m32 flag with the native gcc version.

  2. You want to benefit from the long mode of your processor (aka x86_64 architecture) but still use most 32-bits C conventions (including long int on 4 bytes): you can use the x32 ABI by using the -mx32 flag of gcc, which requires that your distribution allows it (support must be enable in your kernel and specific libraries are needed e.g. in /libx32). I am using Ubuntu 16.04 and this mode is working perfectly fine, except that there is much fewer precompiled libraries available.

  3. You want to exactly use the x86_64 architecture and ABI, but with 4 bytes long: this is impossible as the x86_64 ABI requires the long to be 8 bytes.

calandoa
  • 5,668
  • 2
  • 28
  • 25