Porting to 64-bit: Aches and Pains

Basic Differences

Type 32 bit size (ILP32) 64 bit size (LP64)
any pointer type 4 8
long long 8 8
long 4 8
long double 12 16
double 8 8
float 4 4
int 4 4
short 2 2
char 1 1

A Flame About 64-bit Pointers

A quote from Knuth himself: "It is absolutely idiotic to have 64-bit pointers when I compile a program that uses less than 4 gigabytes of RAM. When such pointer values appear inside a struct, they not only waste half the memory, they effectively throw away half of the cache."

The gcc manpage advertises an option "-m32" that sounds like what I want. Namely, I think it would compile code for my x86-64 architecture, taking advantage of the extra registers etc., but it would also know that my program is going to live inside a 32-bit virtual address space.

If the machine doesn't have loads of RAM/swap? Why then use 64 bit pointers? There is only one other reason to run in 64 bit mode: SSE instructions if you bother to use them. Otherwise it is a net loss.

Rule #1: Don't Mix Int/Longs

That is, don't use long when you mean int and vs. versa. Also note that calculations which include longs will be 64 bit results, and a cast may be required to 'stuff' the result into a 32 bit int.

Rule #2: Beware Pointer Arithmetic:

Ever need to pass integer data via a void *? (Bad practice for sure, but it seems to appear.) With void *'s being 64 bits the value will first need to be converted to long (int64), and then to int (int32):
    void foo(void *p)
    {
        int x;
        x = (int)(long)p; // works everywhere
        x = (int)p;       // only works on 32 bit
    }

Rule #3: Time Types

Note that the clock_t is of type long, and therefore changes size. Guess that solves the 2036 problem, but we have 28 years to upgrade.

Rule #4: Beware sign extension

Note that int's passed on the stack are automagically extended to 64bit register size, with sign extension. So passing the value 0x80000000 to a function taking a long results in the value: 0xffffffff80000000.

Floating Point Implications

See this document for starters.

Varargs ...

The following cropped up in swig'd code using swig 1.3. Normally '0' means (int32_t)0, unless the context says otherwise. When varargs is used the context is sometimes not clear. Consider the two routines:
int
SWIG_GetArgs(int *interp, int objc, const int *objv[], const char *fmt, ...)
{
int        argno = 0;
const char *c;
va_list    ap;
void      *vptr;

    va_start(ap,fmt);
    for (c = fmt; (*c && (*c != ':') && (*c != ';')); c++,argno++)
    {
        vptr = va_arg(ap,void *);   <------------------64 bit access
        if (vptr == 0)
            printf("arg %d(%c) is null\n", argno, *c);
        else
            printf("arg %d(%c) is not null\n", argno, *c);
    }
}

int
wrap_TclMonitor_stopData(int *clientData, int *interp, int objc, const int *objv[]) +--------------------- (32 bit 0's)
{                                                                                   |       +------------- (32 bit 0's)
char *arg2;                                                                         v       v
    SWIG_GetArgs(interp, objc, objv,"oso:TclMonitor_stopData self computerName dd ",0,&arg2,0);
}

The call in the second function has 4 well defined arg types, followed by '0, &arg2, 0' which maps to the '...' portion of the first function. Also note that the first function accesses the ... region as 64 bit pointers. Also note that the first six args are passed in registers, but the 7th will be on the stack. As it turns out in this case, the zero's passed in registers are extended properly, but the value passed on the stack is not, thus a runtime fault.

The fix is trivial: change the Source/Modules1.1/tcl8.cxx file to emit '(void *)0' instead of just '0'.

Footnotes:

  1. What is this ILP32, LP64 jargon? Apparently there is more that one 64bit model. Linux-64 bit uses the (LP64) model, but Windows-64 uses the (P64) model where only pointers become 64bit, longs remain at 32 bits.

-- JoeBrandt - 07 Jul 2008
Topic revision: r4 - 2012-04-18, JoeBrandt
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding NRAO Public Wiki? Send feedback