Thread View: comp.sys.mac.programmer.codewarrior
13 messages
13 total messages
Started by Stefan Haller
Wed, 18 Jun 2003 14:43
Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Stefan Haller
Date: Wed, 18 Jun 2003 14:43
Date: Wed, 18 Jun 2003 14:43
52 lines
2275 bytes
2275 bytes
We need to pass objects between a Mach-O application and a CFM shared
library, built from the same source code.
It seems that the Mach-O and CFM compilers behave differently with
regard to the alignment of derived classes, so that the object layout is
different. Obviously this is a serious problem for us.
The following sample code illustrates the problem. I don't understand
what the padding rules are here; CFM doesn't *always* pad so that the
derived class starts on the next 8-byte boundary, because if you comment
out the "int i" in Base, the offset of b2 is 1 on both compilers.
Is this a bug in one of the compilers? Is there anything we can do to
work around this problem? (We could manually pad all our classes to
multiples of 8 bytes, but this is very error-prone.)
(I have played with the various "#pragma options align=", but it doesn't
seem to make a difference.)
#include <stdlib.h> // for offsetof
#include <assert.h>
class Base
{
public:
int i;
bool b1;
};
class Derived : public Base
{
public:
bool b2;
};
int main(void)
{
#ifdef __MACH__
assert(offsetof(Derived,b2) == 5);
#else
assert(offsetof(Derived,b2) == 8);
#endif
return 0;
}
--
Stefan Haller
Berlin, Germany
http://home.snafu.de/stk/
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Ed Swartz
Date: Fri, 20 Jun 2003 00:52
Date: Fri, 20 Jun 2003 00:52
73 lines
3620 bytes
3620 bytes
"Stefan Haller" <stk@snafu.de> wrote in message
news:1fwrc5z.1wbucc58vha4aN%stk@snafu.de...
> We need to pass objects between a Mach-O application and a CFM shared
> library, built from the same source code.
>
> It seems that the Mach-O and CFM compilers behave differently with
> regard to the alignment of derived classes, so that the object layout is
> different. Obviously this is a serious problem for us.
Well, even given the specific rules, your problem is deeper than the member
layout. CFM and Mach-O use completely different ABIs, so the layout of C++
objects is unlikely to correspond between the two (the vtable pointer, for
instance, is in different places). CFM is based off a 16-bit 68K
architecture, while Mach-O is based off a 32-bit PPC architecture, so there
are inherent unconfigurable differences in the ways the invisible parts of
the classes are aligned.
Not to mention, using any features like RTTI, virtual methods, etc. will
simply not work if you try to pass these objects back and forth between
programs using the two ABIs.
I would recommend using C structs instead. In this case, the "Mac 68K
2-byte" alignment is probably your best bet. Beyond that, #pragma pack(1)
... pack(8) would be best for assuring the struct layouts are the same
between the two compilers.
>
> The following sample code illustrates the problem. I don't understand
> what the padding rules are here; CFM doesn't *always* pad so that the
> derived class starts on the next 8-byte boundary, because if you comment
> out the "int i" in Base, the offset of b2 is 1 on both compilers.
>
> Is this a bug in one of the compilers? Is there anything we can do to
> work around this problem? (We could manually pad all our classes to
> multiples of 8 bytes, but this is very error-prone.)
>
> (I have played with the various "#pragma options align=", but it doesn't
> seem to make a difference.)
>
>
> #include <stdlib.h> // for offsetof
> #include <assert.h>
>
> class Base
> {
> public:
> int i;
> bool b1;
> };
>
> class Derived : public Base
> {
> public:
> bool b2;
> };
>
> int main(void)
> {
> #ifdef __MACH__
> assert(offsetof(Derived,b2) == 5);
> #else
> assert(offsetof(Derived,b2) == 8);
> #endif
>
> return 0;
> }
>
>
> --
> Stefan Haller
> Berlin, Germany
> http://home.snafu.de/stk/
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Stefan Haller
Date: Fri, 20 Jun 2003 12:39
Date: Fri, 20 Jun 2003 12:39
49 lines
3040 bytes
3040 bytes
Ed Swartz <eswartz@antispam.metrowerks.com> wrote: > Well, even given the specific rules, your problem is deeper than the member > layout. CFM and Mach-O use completely different ABIs, so the layout of C++ > objects is unlikely to correspond between the two (the vtable pointer, for > instance, is in different places). CFM is based off a 16-bit 68K > architecture, while Mach-O is based off a 32-bit PPC architecture, so there > are inherent unconfigurable differences in the ways the invisible parts of > the classes are aligned. Our classes do have virtual functions (destructors, mostly), but we are careful to call them only from the Mach-O side. This is working fine. We are not using any other RTTI features on these objects. So far it seems that the alignment problem with derived classes is the only problem in practice. We had this only for very few classes, and were able to fix the problems by manually padding the classes. The problem with this approach is that it is hard to test. (We are considering putting BOOST_STATIC_ASSERT((sizeof(MyClass) % 8) == 0); after the declaration of each of the shared classes, but this is still easy to forget for new classes.) > I would recommend using C structs instead. This is not an option. We have a very large code base that is already using these C++ classes, there's no way we can rewrite it all, using different data structures. > Beyond that, #pragma pack(1) ... pack(8) would be best for assuring the > struct layouts are the same between the two compilers. The C compiler manual doesn't list this as supported by the Mac compilers. #pragma pack(1) does work though, and it even achieves the desired effect of getting the same alignment on both Mach-O and CFM; however, it is completely useless, because it will merrily put ints and doubles on odd addresses. To sum it up: it seems that manually padding our classes to multiples of 8 bytes is our only option, right? -- Stefan Haller Berlin, Germany http://home.snafu.de/stk/
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Thorrsten Froehlich
Date: Fri, 20 Jun 2003 18:41
Date: Fri, 20 Jun 2003 18:41
23 lines
2127 bytes
2127 bytes
stk@snafu.de (Stefan Haller) wrote in message news:<1fwuuqx.ngui9t15gtnejN%stk@snafu.de>...
> Ed Swartz <eswartz@antispam.metrowerks.com> wrote:
>
> > CFM is based off a 16-bit 68K
> > architecture, while Mach-O is based off a 32-bit PPC architecture, so there
> > are inherent unconfigurable differences in the ways the invisible parts of
> > the classes are aligned.
Actually, the poster of this is wrong regarding CFM using 2-byte
alignment on PowerPC. It of course has always used 4-byte alignment.
He is also wrong suggestioning to use pack(), see below.
> To sum it up: it seems that manually padding our classes to multiples of
> 8 bytes is our only option, right?
No, you may want to check out the "C Compilers Reference 3.0" in the
CodeWarrior manuals folder. In the PDF version, go to page 130. You
are looking for "#pragma options align", which is the appropriate way
to set alignment when compiling for PowerPC . You may also want to
take a look at the other options listed, there is a lot of useful
information there...
Thorsten
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Thorrsten Froehlich
Date: Fri, 20 Jun 2003 19:35
Date: Fri, 20 Jun 2003 19:35
32 lines
2609 bytes
2609 bytes
stk@snafu.de (Stefan Haller) wrote in message news:<1fwrc5z.1wbucc58vha4aN%stk@snafu.de>...
> We need to pass objects between a Mach-O application and a CFM shared
> library, built from the same source code.
>
> It seems that the Mach-O and CFM compilers behave differently with
> regard to the alignment of derived classes, so that the object layout is
> different. Obviously this is a serious problem for us.
>
> The following sample code illustrates the problem. I don't understand
> what the padding rules are here; CFM doesn't *always* pad so that the
> derived class starts on the next 8-byte boundary, because if you comment
> out the "int i" in Base, the offset of b2 is 1 on both compilers.
Actually, a minimal padding can be a good thing if you need to a lot
of small objects. Anyway, I see your problem is similar to one I have
been having some time ago (but not directly related, I had stack
alignment issues in my own code generated at runtime when interfacing
to CW functions).
> Is this a bug in one of the compilers?
No, the ABI is different, and it is actually documented what is being
used. Not in any of the manuals as I just noticed, also I thought I
had read it there. There are more options for alignment, and they are
not documented in the compiler manual yet, it seems:
You find them in "CW Mac PPC Notes 3.0.txt" in the Release Notes
folder. If you play with them a bit, in particular the "power_gcc"
options, I guess you get what you want assuming Apple and Metrowerks
follow the same revision gcc ABI for Mach-O to be compatible with each
other.
Thorsten
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Sean McBride
Date: Sat, 21 Jun 2003 21:18
Date: Sat, 21 Jun 2003 21:18
7 lines
1264 bytes
1264 bytes
In article <1fwuuqx.ngui9t15gtnejN%stk@snafu.de>, stk@snafu.de (Stefan Haller) wrote: > The C compiler manual doesn't list this as supported by the Mac > compilers. #pragma pack(1) does work though, That's an error in the manual actually, pragma pack does work on CW Mac.
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Stefan Haller
Date: Sun, 22 Jun 2003 08:35
Date: Sun, 22 Jun 2003 08:35
16 lines
1584 bytes
1584 bytes
Thorrsten Froehlich <froetho@charlie.iit.edu> wrote: > There are more options for alignment, and they are > not documented in the compiler manual yet, it seems: > You find them in "CW Mac PPC Notes 3.0.txt" in the Release Notes > folder. If you play with them a bit, in particular the "power_gcc" > options, I guess you get what you want No. I tried them all before posting; none of them appears to have any influence on what happens between a base class and a derived class. -- Stefan Haller Berlin, Germany http://home.snafu.de/stk/
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Thorrsten Froehlich
Date: Tue, 24 Jun 2003 19:43
Date: Tue, 24 Jun 2003 19:43
40 lines
3181 bytes
3181 bytes
stk@snafu.de (Stefan Haller) wrote in message news:<1fwyaln.v7pwbouxanswN%stk@snafu.de>...
> Thorrsten Froehlich <froetho@charlie.iit.edu> wrote:
>
> > There are more options for alignment, and they are
> > not documented in the compiler manual yet, it seems:
> > You find them in "CW Mac PPC Notes 3.0.txt" in the Release Notes
> > folder. If you play with them a bit, in particular the "power_gcc"
> > options, I guess you get what you want
>
> No. I tried them all before posting; none of them appears to have any
> influence on what happens between a base class and a derived class.
Hmm, so Metrowerks offers control only over C alignment, but no
control whatsoever over C++ structure alignment. I am surprised
regular structs are treated different from classes to such an extend.
If it isn't a bug (I would file it) that the alignment options don't
change behavior of anything C++ ABI related, I would say it is really
a worthwhile feature to be able to exchange data this way. Of course,
if I think about it, I suppose having different alignment might
require some of the compiler-generated code for C++ to be adjusted,
which is more difficult to do than it sounds.
In any case, given that you know where to look for the ABI
specifications, it is possible to work around this problem reliably
using either manual padding as you suggested, or maybe something else:
Did you try putting the members of each class into a separate struct?
That is, will the alignment then match on Mach-O and CFM? I would
assume structs always get aligned, but I don't know if they are...
Alternatively, you could of course recreate the class structure with
structs on either Mach-O or CFM (should be possible with the ABI
specs). With a few scripts one could probably even automate this. That
way, you could adapt to whatever alignment the other side uses. If
performance isn't a major issue, transforming the class structure at
runtime would be another option.
In the end it all depends on how important the ability to make
cross-ABI calls is for you.
Thorsten Froehlich
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Miro Jurisic
Date: Wed, 25 Jun 2003 02:15
Date: Wed, 25 Jun 2003 02:15
10 lines
1210 bytes
1210 bytes
In article <1fwrc5z.1wbucc58vha4aN%stk@snafu.de>, stk@snafu.de (Stefan Haller) wrote: > We need to pass objects between a Mach-O application and a CFM shared > library, built from the same source code. You are doomed. It will never work because the vtbl layout and offsets to base classes are different. meeroh
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Thorrsten Froehlich
Date: Wed, 25 Jun 2003 07:41
Date: Wed, 25 Jun 2003 07:41
33 lines
2565 bytes
2565 bytes
Miro Jurisic <macdev@meeroh.org> wrote in message news:<macdev-7428E9.22150424062003@senator-bedfellow.mit.edu>...
> In article <1fwrc5z.1wbucc58vha4aN%stk@snafu.de>, stk@snafu.de (Stefan Haller)
> wrote:
>
> > We need to pass objects between a Mach-O application and a CFM shared
> > library, built from the same source code.
>
> You are doomed. It will never work because the vtbl layout and offsets to base
> classes are different.
But that should be all, and according to his observations, data within
the class is also aligned differently and independent of the struct
alignment compiler options.
So assuming one can get the alignment of member data to match (which
he says he cannot change except to byte alignment using pack(1)), one
can at least pass data. He didn't say he wants to make calls to member
functions, so only the vtable pointer size matters, but not the
content of the vtable structure. As both ABIs use a single pointer for
the vtable pointer, and specify that data memebrs are aligned
following that pointer, imho there is nothing unreasonable about
assuming one can exchange data this way. The only potential problem
then would be different rules for data placement in the multiple
inheritance case.
So the question is why the alignment of data members can be set to
pack(1) and then it works as expected, but as he observed, not changed
otherwise?
Thorsten
Note: I did not test myself that the alignment does not change for
C++, I take his word for this.
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Stefan Haller
Date: Wed, 25 Jun 2003 09:32
Date: Wed, 25 Jun 2003 09:32
19 lines
1800 bytes
1800 bytes
Thorrsten Froehlich <froetho@charlie.iit.edu> wrote: > > No. I tried them all before posting; none of them appears to have any > > influence on what happens between a base class and a derived class. > > Hmm, so Metrowerks offers control only over C alignment, but no > control whatsoever over C++ structure alignment. I am surprised > regular structs are treated different from classes to such an extend. That's not what I said. "#pragma options align" does of course control the alignment of members of a C++ class. However, it does not have any influence on the padding that is added between a base class and a derived class. -- Stefan Haller Berlin, Germany http://home.snafu.de/stk/
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Thorrsten Froehlich
Date: Wed, 25 Jun 2003 18:16
Date: Wed, 25 Jun 2003 18:16
46 lines
3526 bytes
3526 bytes
stk@snafu.de (Stefan Haller) wrote in message news:<1fx3x6k.1dzfady1to3r7kN%stk@snafu.de>... > Thorrsten Froehlich <froetho@charlie.iit.edu> wrote: > > > > No. I tried them all before posting; none of them appears to have any > > > influence on what happens between a base class and a derived class. > > > > Hmm, so Metrowerks offers control only over C alignment, but no > > control whatsoever over C++ structure alignment. I am surprised > > regular structs are treated different from classes to such an extend. > > That's not what I said. "#pragma options align" does of course control > the alignment of members of a C++ class. However, it does not have any > influence on the padding that is added between a base class and a > derived class. Ok, wait a second. I re-read your initial post. So the alignment is correct, there there must be something else, and looking much closer suggests there is tail padding for CFM, as specified by "The total size of a struct or union is rounded up to a multiple of its embedding alignment" (3.3.1.2 in the CFM ABI spec). However, the gcc C++ ABI says tail padding should be ignored. It says "dsize(O): the data size of an object, which is the size of O without tail padding." And it further specifies "If D is not an empty base class or D is a data member: Start at offset dsize(C), incremented if necessary for alignment to nvalign(D) for base classes or to align(D) for data members." (2.4 II. in the gcc ABi spec). So, the CFM struct embedding specification of the base-derived case uses tail padding, and the Mach-O gcc C++ ABI way is to not use tail padding (as discussed in <http://gcc.gnu.org/ml/gcc/2002-08/msg00880.html>). Now, there is only one way I can imagine that will solve your problem for everything but charcater arrays (because you cannot apply the trick to them, unless you make them multiples of four in size and disable the macro processor trick for them). I would suggest to use the macro preprocessor to perform #define bool int, #define char int, #define short int in the class declarations. This way, everything will be aligned to four bytes on both ABIs and it should work. Of course, you don't want to need to do this in your source code. I suppose in conclusion a feature Metrowerks could add is control over tail padding ;-) Thorsten
Re: Alignment (padding) of derived classes, Mach-O vs. CFM
Author: Stefan Haller
Date: Wed, 25 Jun 2003 19:06
Date: Wed, 25 Jun 2003 19:06
25 lines
1970 bytes
1970 bytes
Miro Jurisic <macdev@meeroh.org> wrote: > In article <1fwrc5z.1wbucc58vha4aN%stk@snafu.de>, stk@snafu.de (Stefan Haller) > wrote: > > > We need to pass objects between a Mach-O application and a CFM shared > > library, built from the same source code. > > You are doomed. Well, fortunately we are not. We call virtual functions only from the Mach-O side, and we don't use dynamic_cast on the CFM side. With these restrictions everything works well, except for the padding-between-base- and-derived problem. We were able to solve that problem by adding compile-time assertions to make sure that the offset of the first member of every derived class is equal to sizeof(base). It turned out that we had to add manual padding only in two classes (out of some 400). -- Stefan Haller Berlin, Germany http://home.snafu.de/stk/
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads