From: wang@cs.uiuc.edu (Eric Wang)
Subject: Can I tell g++ NOT to assume that doubles are 8-byte aligned?
Reply-To: wang@cs.uiuc.edu
Organization: University of Illinois at Urbana-Champaign
Distribution: usa
Date: Mon, 4 Jan 1993 20:50:58 GMT

Sparcstation 2
SunOS 4.1.1
gcc & libg++ 2.2.2
Problem summary: an app's own version of malloc() is 4-byte aligned, but
    when the allocated struct starts with a double, g++'s generated code
    assumes that it's 8-byte aligned, and uses double-word instructions
    to access this pointer, which causes a bus error.

I'm trying to use g++ to customize an app by writing extensions that
will be linked into the app's libraries.  Among other things, this app's
libraries defines its own memory-allocation functions, including
malloc(), free(), etc, and these apparently get linked into my app
before either the system version or libg++'s version.  The app's vendor
distributes only the libraries, so there's no way for me to hack their
source and recompile it.

I must perforce do this work on a Sparcstation 2 (running SunOS 4.1.1),
which is a Sun-4.  The Sun-4 programmers' references says that C (and
hence C++) doubles must be 8-byte aligned, which is a change from Sun-3
and earlier architectures, which require only 4-byte alignment.  They
also say that the system's version of malloc() returns pointers that are
aligned to point to any kind of data, i.e. they're aligned to 8 bytes.
However, my tests don't bear this out; Sun's malloc() still is 4-byte
aligned, and if you malloc() a (double *) that is 4-byte aligned, the
correct (but less efficient) single-word code is generated to operate on
this pointer.  Apparently, forcing doubles to be 8-byte aligned is a
compiler switch, not the default compiler setting.

The problem is that this app's own versions of the mem-alloc routines
seems not to take Sun-4 architecture into account, so it remains only
4-byte aligned, regardless of the compiler switches (since it's already
been compiled without the switch).  g++, on the other hand, seems to
assume that doubles, and (double *)s, are 8-byte aligned; when I compile
it without any funky compiler switches, it generates code that does
double-word operations.  Hence, using operator new to allocate an array
of (double *)s, or an array of structs or objects whose first field is a
double, gives me a pointer which is only 4-byte aligned, and attempting
to access in any way the double at this pointer results in a Bus Error,
since the pointer is not properly aligned to support double-word
accesses.  (BTW, g++'s code generation seems to contradict the Info
entry gcc/Invoking GCC/Submodel Options/SPARC Options/`-mforce-align',
which says "Force doubles to be 8-byte aligned, and use dword accesses",
and implies "I am NOT the default action, since you have to specify me
explicitly to get this effect".  Nonetheless, it does seem to do this by
default.)

Finally, due to limited disk space and my limited user privileges, I am
not in a position to recompile gcc.  I need a fix that doesn't requiring
building a new gcc.

I've identified some potential solutions:

1.  Specify -mno-force-align to g++.

    Unfortunately, this doesn't seem to be a valid switch; g++ complains
    about it.  Is there any other way AT COMPILE-TIME to make g++ on a
    Sun-4 NOT assume that (double *)s are 8-byte aligned?

2.  Force g++ to link in the libg++ version of malloc, free, and
    realloc.

    I'm not sure if my copy of libg++ even has these functions.
    Whatever version of free() I get does NOT zero out the free'd block
    of memory, contrary to the libg++/New Info entry.  How can I find
    out for sure?  (Again, I don't have the source code for libg++, I
    didn't build it, and I probably couldn't get the resources to build
    it.)

2.  Do all accesses to these data structures in C instead of C++, and
    compile them with Sun cc instead of gcc/g++.

    But this essentially forces me to abandon g++ altogether, as these
    data structures are prevalent throughout my code.  I really would
    prefer to stay with C++.

3.  Get the app's vendor to fix its mem-alloc routines.

    I am pursuing this separately, but not holding my breath.

4.  Write my own wrappers around the app's malloc() and free() that
    insure 8-byte alignment.

    Icky, but probably the sol'n with the best ease-to-time trade-off.
    Note that I can't just overload new() and delete() for this one
    struct, since I need to new() an array of these structs, and
    new()ing an array always uses the global ::new(), not the
    class-specific new().  (Stroustrup r.5.3.3)

The bottom line is that this "bug" isn't necessarily an error in either
the app or g++, since both work fine when they stand alone; rather, it's
a case of mismatched expectactions between the two.  If there's an easy
way to have g++ "bridge the gap" and allow single-word access to C/C++
doubles, I'd like to know about it.  (The real fix would be to have the
app bridge the gap from its end, but I expect this will take too long to
be practical.)

Any help or hints would be appreciated.

Eric Wang
wang@cs.uiuc.edu