October 15, 2002
Crazy ABI Layout Rules

A couple of years ago, EDG was invited to participate in the development of an ABI (Application Binary Interface) for C++ on the Itanium architecture. The weekly development meetings ocurred in the Bay Area (SGI facilities), and since I lived close to there at the time, I represented EDG.

For the C language, the ABI consists of data layout rules, calling conventions, object file format specs, and a few other relatively simple choices. For C++, however, things are harder: layout of base classes, virtual function dispatch (and the data structures associated therewith), exception handling, name mangling, and RTTI offer a much larger variety of options to disagree on. The “holy C++ ABI grail,” then, is to be able to seemlessly blend libraries from different vendors in a single application.

I hear you say “But what about templates?” Good reflex, but forget about those for now. Instead, let me rant about a more basic topic: Laying out subobjects in memory.

Consider the following piece of code:

struct D: B1, B2 {
int i;

An object of type D contains three direct subobjects: a field i and two base subobjects (of types B1 and B2 respectively). Most of the time, each of these subobjects take up some bytes of memory within the sizeof(D) bytes occupied by D. One exception is that if a base class type is “empty” it may be optimized not to take up any space at all. Still, an optimized empty base class (OEBC) must have its own address.

Until now, I always assumed that direct subobjects cannot overlap. Specifically, in the example above, I would expect the base subobject of type B1 to take up the first zero or more bytes of a D object, then the subobject of type B2 would follow with perhaps an alignment gap between the two bases, and finally the integer field would take up four bytes or so. The ordering of these three parts may be different for different ABIs, and it may even depend on the kind of base classes (e.g., if B2 has virtual functions and B1 does not, it is not uncommon for ABIs to place the subobject of type B2 first).

In the IA-64 ABI however, the nonoverlap principle need not hold. Indeed, if the base class types are defined as follows:

struct B1 {};
struct B2: B1 {};

then the base subobject of type B2 ends up inside the field of type int.

That, in my opinion, is crazy.

Posted by Daveed at 06:46 PM | Comments (1)

I think parking the addresses of fake subobjects in the middle of real subobjects is brilliant. It means the claim in your book that the empty-base optimization doesn't extend nicely to empty members is not strictly correct.

I'm surprised, though, to find that Intel accepted such a tricky approach in their standard. It's the sort of thing I expect implementers to get wrong.

Posted by: Nathan Myers on November 27, 2002 01:38 PM
Post a comment

Email Address:



Remember info?