[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Understanding the non-fragile ABI
From: |
David Chisnall |
Subject: |
Understanding the non-fragile ABI |
Date: |
Sat, 20 Mar 2010 17:41:54 +0000 |
A few people have asked me questions about the non-fragile ABI recently, which
lead me to believe that I haven't properly explained it in the past, so here is
a more full explanation:
How it Works (with some simplification):
With the fragile ABI, ivars are turned into fixed offsets. Imagine that you
have a class like this:
@interface AClass : ASuperClass
{
int foo;
id bar;
}
@end
An access to foo becomes something like this:
*(int*)((char*)self + sizeof(ASuperClass))
An access to bar becomes something like this:
*(id*)((char*)self + sizeof(ASuperClass)+sizeof(int))
If sizeof(ASuperClass) changes - which happens when you add or remove ivars -
then all of these offsets are incorrect.
With the non-fragile ABI, these are implemented differently. For code compiled
with the non-fragile ABI, the accesses become:
*(int*)((char*)self + **__objc_ivar_offset_AClass.foo)
An access to bar becomes something like this:
*(id*)((char*)self + **__objc_ivar_offset_AClass.bar)
The __objc_ivar_offset_AClass.foo is created as a weak symbol in each
compilation unit that references the instance variable but doesn't contain the
class definition. This is initialised to point to a guess variable, which
contains the offset that the compiler would have hard-coded with the old ABI.
In compilation units containing the class definition, this variable points
instead to a canonical definition. There is also a pointer to this definition
in the class structure. At load time, if the canonical definition exists (i.e.
if the class in which the ivar was declared was compiled with the clang), the
loader will use it. If not, it will fall back to the guess. The runtime will
then fix up the ivar offsets for any class compiled with the non-fragile ABI.
The runtime also now does some sanity checking to make sure that every loaded
class's ivars start at the end of its superclass's ones. This will make it
abort in a number of cases where you're using binary-incompatible classes,
where previously it would have just corrupted your ivars.
There is an optimisation pass in the libobjc2/opts directory that will turn the
double indirection into single indirection or hard-coding when possible. If
all of the superclasses are in the same compilation unit (framework or
application, if you run it as a link-time optimisation), then you will get
hard-coded offsets because the superclass layout can't change without the
subclasses being recompiled.
If the canonical definition exists in the same compilation unit, then you only
get single indirection after running this pass. This means that any class can
access its own instance variables with only single indirection, but it may need
to use double indirection for its superclass.
If all code is compiled with the non-fragile ABI, then you never need to use
the double indirection. In the next version of the ABI, I will always use
single-indirection and abort when you try loading a class that uses the GCC ABI
as a superclass of one that uses the incompatible ABI.
What This Means:
If you compile a class with the non-fragile ABI, it can access its instance
variables with the correct offsets. It can access its superclass's instance
variables at the correct offsets if one or more of the following holds:
- The superclass's instance variables are where they the @interface says they
should be.
- The superclass is compiled with the non-fragile ABI.
- The superclass is compiled with clang.
Clang always emits the non-fragile ABI offsets variables, even when it does not
use these offsets. This means that clang-compiled code that does not use
-fobjc-nonfragile-abi will work with both the GCC and GNUstep runtimes. If you
use the GCC runtime, it will behave like GCC-compiled code.
If you compile a class with the non-fragile ABI then you may subclass it with a
class compiled with the fragile ABI, but the normal conditions for the fragile
ABI apply, specifically that the ivar layout that the compiler sees in the
@interface must be correct. Changes to the superclass ivar layout will break
this subclass, but will not break any subclasses compiled with the non-fragile
ABI.
David
-- Send from my Jacquard Loom
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Understanding the non-fragile ABI,
David Chisnall <=