ISA walk a
Define a class ABPerson that inherits NSObject to see the reference to ISA through the LLDB command.
The ISA of the instance object points to the class object
p/x p
Print instance objectp
The address of thex/4gx 0x0000000100538ae0
Print the memory of this address, output 4 segments, the first segment is storedISA
The relevant informationp/x 0x011d800100008185 & 0x00007ffffffffff8ULL
By aboutISA_MASK
X00007ffffffffff8ull (0)&
Operation to get the class objectABPerson
po 0x0000000100008180
Print class object
Conclusion: The ISA of the instance object points to the class object
The ISA of a class object points to its metaclass
According to the figure above,0x0000000100008180
Is the address of the class objectISA
To:You can see that you’ve got an address
0x0000000100008158
So is printingABPerson
This is the metaclass, which is generated by the system. Only one class object can be proved as follows:
Class object
ABPerson
The addresses are:0x100008190
.0x0000000100008158
Is a metaclass address.
Conclusion: ISA of a class object points to its metaclass
The ISA of the metaclass points to the root metaclass
According to the figure above,0x0000000100008158
Is the metaclass address of the classISA
To:That can see metaclasses
ISA
Is pointing toNSObject
, which is the root metaclass. Conclusion: metaclassISA
It points to the root metaclass
The ISA of the root metaclass points to itself
According to the figure above,0x00007fff88967fe0
Is a metaclassNSObject
Continue to look at the root metaclassISA
To:The addresses in the red box are all the same, they’re all themselves. Conclusion: The ISA of the root metaclass points to itself
ISA bitmap
Inheritance chain
Define a subclassABTeacher
inheritanceABPerson
NSObject
The root metaclass, root metaclass, root metaclass are all0x7fff88967fe0
Is a thing.ABPerson
isABTeacher
Is the parent class,ABTeacher
The superclass address of the metaclass is0x100008210
.ABPerson
As is the metaclass address of0x100008210
, soABTeacher
The parent of a metaclass isABPerson
The metaclass.- The root class
NSObject
The parent classnil
- The parent address of the root metaclass is
0x7fff88968008
isNSObject
Finally, attached is the official picture of Apple
The structure of the class
Objc source code for Class definition:
typedef struct objc_class *Class;
Objc_class struct definition:
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flagsOmit some codeCopy the code
The structure layout of the class looks like this:
ISA
andsuperclass
Both take up the size of a structure pointer8
bytecache
Account for16
Bytes,cache_t
Structure:
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask; / / 8
union {
// Combinations are mutually exclusive, so they account for 8
struct {
explicit_atomic<mask_t> _maybeMask; //uint32_t 4
#if __LP64__
uint16_t _flags; //uint16_t 2
#endif
uint16_t _occupied; //uint16_t 2
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache; / / 8
};
Copy the code
_bucketsAndMaybeMask is 8, the current Union is 8, so cache_t is 16
To access bits, memory shift 8+8+16=32 bytes.
Gets the attributes of the class
LLDB debugging:
Debug project download
@interface LGPerson : NSObject
// isa
@property (nonatomic.copy) NSString *name;
@property (nonatomic) int age;
- (void)saySomething;
@end
Copy the code
x/4gx LGPerson.class
Gets the first address of the classp/x 0x1000083a0 + 0x20
, the first address is offset32
One byte, get itbits
p (class_data_bits_t *)0x00000001000083c0
To forcibly convert the address toclass_data_bits_t
typep $2->data()
, the callclass_data_bits_t
In thedata()
function
structPublic: class_rw_t* data()const {
return(class_rw_t *)(bits & FAST_DATA_MASK); } omit some code}Copy the code
p $3->properties()
Gets the attributes of the class
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<constclass_ro_t *>(&ro_or_rw_ext)->baseProperties}; }}Copy the code
class property_array_t :
public list_array_tt<property_t, property_list_t, RawPtr>
{
typedef list_array_tt<property_t, property_list_t, RawPtr> Super;
public:
property_array_t() : Super() { }
property_array_t(property_list_t *l) : Super(l) { }
};
Copy the code
class list_array_tt {
struct array_t {
uint32_t count;
Ptr<List> lists[0];
static size_t byteSize(uint32_t count) {
return sizeof(array_t) + count*sizeof(lists[0]);
}
size_t byteSize() {
returnbyteSize(count); }}; Omit some code}Copy the code
Property_array_t inherits from list_array_tt. List_array_tt has a structure array_t, which contains variables lists
p $4.list
getproperty_list_t
The first addressp $5.ptr
printproperty_list_t
The first addressp *$6
Get address getproperty_list_t
p $7.get(0)
readproperty_list_t
Member variables in
Gets the instance method of the class
- The same steps are omitted here
p $3->methods()
Method to get the class
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<constclass_ro_t *>(&ro_or_rw_ext)->baseMethods()}; }}Copy the code
class method_array_t :
public list_array_tt<method_t, method_list_t, method_list_t_authed_ptr>
{
typedef list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> Super;
public:
method_array_t() : Super() { }
method_array_t(method_list_t *l) : Super(l) { }
const method_list_t_authed_ptr<method_list_t> *beginCategoryMethodLists() const {
return beginLists();
}
const method_list_t_authed_ptr<method_list_t> *endCategoryMethodLists(Class cls) const;
};
Copy the code
class list_array_tt {
struct array_t {
uint32_t count;
Ptr<List> lists[0];
static size_t byteSize(uint32_t count) {
return sizeof(array_t) + count*sizeof(lists[0]);
}
size_t byteSize() {
returnbyteSize(count); }}; Omit some code}Copy the code
Method_array_t inherits from list_array_tt, which has a structure array_t and variable lists in it
p $4.list
getmethod_list_t
The first addressp $5.ptr
printmethod_list_t
The first addressp *$6
Get address getmethod_list_t
p $7.get(0).big()
readmethod_list_t
Instance methods in
struct property_t {
const char *name;
const char *attributes;
};
Copy the code
struct method_t {
static const uint32_t smallMethodListFlag = 0x80000000;
method_t(const method_t &other) = delete;
// The representation of a "big" method. This is the traditional
// representation of three pointers storing the selector, types
// and implementation.
struct big {
SEL name;
const char*types; MethodListIMP imp; }; Omit some code}Copy the code
$7.get(0) gets the property from the property_t structure. Method_t also has a big structure inside big, so it calls big().
Gets a member variable of the class
Modify the LGPerson code to add a member variable and a class method
@interface LGPerson : NSObject
{
// Member variables
NSString *subject;
}
@property (nonatomic.copy) NSString *name;
@property (nonatomic) int age;
- (void)saySomething;
/ / class methods
+ (void)doSomething;
@end
Copy the code
@implementation LGPerson
- (void)saySomething{
NSLog(@"%s",__func__);
}
+ (void)doSomething{
NSLog(@"%s",__func__);
}
@end
Copy the code
- The same steps are omitted here
– $3->ro() to get the class_ro_t address
const class_ro_t *ro() const {
auto v = get_ro_or_rwe();
if (slowpath(v.is<class_rw_ext_t *>())) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro;
}
return v.get<const class_ro_t *>(&ro_or_rw_ext);
}
Copy the code
p *$4
Get address, getclass_ro_t
p $5.ivars
To obtainclass_ro_t
Is a list of member variablesivar_list_t
The first address
structClass_ro_t {omit some codeconstivar_list_t * ivars; Omit some code}Copy the code
p *$6
Get the address to get the list of member variablesivar_list_t
p $7.get(0)
Print member variables
Get class methods
x/4gx LGPerson.class
To printLGPerson
Memory, get the first 8 bytes0x00000001000083c0
p/x 0x00000001000083c0 & 0x00007ffffffffff8ULL
To get the metaclass address- The following steps are the same as obtaining the instance method (omitted)
conclusion
ISA
Bit: of the instance objectISA
Referring to a class objectISA
Referring to its metaclass, metaclassISA
Pointing to the root metaclass, root metaclassISA
Point to itself- Inheritance chain:
-
- A subclass inherits from a parent class, which inherits from a root class, which inherits from a root class
nil
- A subclass inherits from a parent class, which inherits from a root class, which inherits from a root class
-
- The child metaclass inherits from the parent metaclass, which inherits from the root metaclass, which inherits from the root metaclass
- Class structure:
ISA
,superclass
,cache
,bits
- Get class attributes: Get the first address of the class -> offset
32
Who getclass_data_bits_t
->data()
->properties()
->property_list_t
->get()
- Method for getting an instance of a class: Get the first address of the class -> offset
The 32 bits get class_datA_bits_t
->data()
->methods()
->method_list_t
->get().big()
- Get a class member variable: Get the first address of the class -> offset
32
Who getclass_data_bits_t
->data()
->ro()
->ivar_list_t
->get()
- Get class method: Get metaclass address -> offset
The 32 bits get class_datA_bits_t
->data()
->methods()
->method_list_t
->get().big()