One, memory offset

1. Study of ordinary pointer

    int a = 10;
    int b = 10;
    int *a_p = &a;
    int *b_p = &b;
    NSLog(@"%d -- %p -- %p",a,&a,&a_p);
    NSLog(@"%d -- %p -- %p",b,&b,&b_p);
    
// Output the result
202107 -26 - 16:15:17.348698+0800Memory offset [7982:190211] 10 -- 0x7ffee841a03c -- 0x7ffee841a030
202107 -26 - 16:15:17.348855+0800Memory offset [7982:190211] 10 -- 0x7ffee841a038 -- 0x7ffee841a028

Copy the code
  • A and b both have values of 10 but a and B have different addressesCopy the valueA and B belong toTwo copies of the data
  • Address A is 0x7FFEE841A03C, address B is 0x7FFEE841A038 and the offset is 4, because a and B areThe int type
  • The a_P address is 0x7FFEE841A030, and the B_P address is 0x7FFEE841A028. The offset is 8, because a_p,b_p isInt * type
  • Address size comparison: a > b > a_p > b_p, because they are local variables, they are storedThe stack area!

2. Object pointer study

    NBPerson *p1 = [NBPerson alloc];
    NBPerson *p2 = [NBPerson alloc];
    NBPerson *p3 = p2;
    
    NSLog(@"---%@----%p",p1,&p1);
    NSLog(@"---%@----%p",p2,&p2);
    NSLog(@"---%@----%p",p3,&p3);
    
// Output the result
202107 -26 - 18:04:00.553396+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2e0>----0x7ffee47bb038
202107 -26 - 18:04:00.553507+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2f0>----0x7ffee47bb030
202107 -26 - 18:04:00.553599+0800Memory offset [10054:263449] ---<NBPerson: 0x6000012ac2f0>----0x7ffee47bb028
    
Copy the code
  • allocOpen up internal existenceThe heap area.A local variableOpen up internal existenceThe stack area
  • The heap arealowAddress — — >highAddress, stack areahighAddress — — >lowaddress
  • Both P3 and P2 store the address of the second allocSame data

3. Array pointer study

        int c[4] = {1.2.3.4};
        int *d   = c;
        NSLog(@"%p - %p - %p ",&c,&c[0],&c[1]);
        NSLog(@"%p - %p - %p ",d,d+1,d+2);

        for (int i = 0; i<4; i++) {
            //(d+ I) take the value inside the address
            int value =  *(d+i); 
            NSLog(@"value = %d",value);
        }
        
// Output the result
202107 -26 - 18:17:57.673897+0800Memory offset [10303:272382] 0x7ffeef40c040 - 0x7ffeef40c040 - 0x7ffeef40c044
202107 -26 - 18:17:57.674018+0800Memory offset [10303:272382] 0x7ffeef40c040 - 0x7ffeef40c044 - 0x7ffeef40c048
202107 -26 - 18:17:57.674109+0800Memory offset [10303:272382] value = 1
202107 -26 - 18:17:57.674187+0800Memory offset [10303:272382] value = 2
202107 -26 - 18:17:57.674255+0800Memory offset [10303:272382] value = 3
202107 -26 - 18:17:57.674330+0800Memory offset [10303:272382] value = 4

// the address of c is 7ffeef40C040
// The four elements of C are 7FFeEF40C040, 7FFeEF40C044, 7FFeEF40C048, 7FFeEF40C04c
Copy the code
  • The address of an array is the element in the arrayThe first address, i.e.,&cand&c[0]Are allThe first address
  • Between each element of an arrayAddress spaceBased on the current elementThe data typeDecision of the
  • The addresses of the elements of the array can be passedThe first address+n*The type sizeIn which the elements in the array must be of the same type.
  • Array elements are differentThe first address+The offsetMethod, based on the offset value of the current variable (requires the addition of the previous type sizes)

Second, isa moves

  • As you can see from the previous article, objects are essentiallyThe structure of the body, the first member variable of the structure isisa. And isa points to the current class, so why would Apple do that? Let’s explore

1. Apple’s official ISA bitmap

  • We can probably see some patterns in this picture
  1. Non-root class (NSObject)objectIsa points to the class,classIsa to metaclass,The metaclassIsa points to the root metaclass,A metaclassIsa points to itself
  2. Root class (NSObject)objectIsa points to the root class,The root classIsa points to the root metaclass,A metaclassIsa points to itself
  3. Non-root class (NSObject)The metaclass of the parent classisThe superclass of the metaclass

2. Number of class object memory

    Class class1 = [NBPerson class];
    Class class2 = [NBPerson alloc].class;
    Class class3 = object_getClass([NBPerson alloc]);
    Class class4 = [NBPerson alloc].class;
    NSLog(@"\n-%p-\n-%p-\n-%p-\n-%p-",class1,class2,class3,class4);
    
// Output the result
202107 -27 - 10:19:47.940292+0800Memory offset [21711:526731] 
-0x1021b5520-
-0x1021b5520-
-0x1021b5520-
-0x1021b5520-
Copy the code

Source code analysis: class object address is the same, each class in memory only a piece of memory, and ordinary object memory is not the same

  • In the previous article, there are three kinds of information to get the class, and using the mask to get the information is relatively fast and direct.

  • From the objC4 source code:

X86_64: define ISA_MASK0x00007ffffffffff8ULL arm64: define ISA_MASK0x0000000ffffffff8ULL ARM64 (Simulators) : Define ISA_MASK0x007ffffffffffff8ULL
Copy the code

3. Metaclass exploration

    NBPerson *p1 = [[NBPerson alloc]init];
    NSLog(@ "% @",p1);
Copy the code
  • Breakpoint debugging
202107 -27 - 10:29:03.000337+0800Memory offset [21861:534807] <NBPerson: 0x6000009e0230>
(lldb) p/x p1
(NBPerson *) $0 = 0x00006000009e0230
(lldb) x/4gx 0x00006000009e0230// Object address
0x6000009e0230: 0x000000010c315520 0x0000000000000000
0x6000009e0240: 0x00001759aa2a0240 0x0000600000bc0026

// Find the class address through the object's ISA
(lldb) p/x 0x000000010c315520 & 0x007ffffffffffff8
(long) $1 = 0x000000010c315520
(lldb) po 0x000000010c315520
NBPerson

// Find the metaclass address through the isa of the class
(lldb) x/4gx 0x000000010c315520
0x10c315520: 0x000000010c3154f8 0x00007fff86d50660
0x10c315530: 0x00006000037ed200 0x000580100000000f
(lldb) p/x 0x000000010c3154f8 & 0x007ffffffffffff8
(long) $9 = 0x000000010c3154f8
(lldb) po 0x000000010c3154f8
NBPerson

Copy the code
  • Breakpoint Process summary
  1. Through objectp1isa0x000000010c315520Find the address of the class0x000000010c315520
  2. Through the classNBPersonisa0x000000010c3154f8Find the address of the metaclass0x000000010c3154f8

4, root metaclass derivation

  • Continue the previous break point
// Metaclass isa finds root metaclass
(lldb) x/4gx 0x000000010c3154f8
0x10c3154f8: 0x00007fff86d50638 0x00007fff86d50638
0x10c315508: 0x00006000025e0700 0x0004c03100000007
(lldb) p/x 0x00007fff86d50638 & 0x007ffffffffffff8
(long) $11 = 0x00007fff86d50638
(lldb) po 0x00007fff86d50638
NSObject

// The root metaclass isa finds the root metaclass.
(lldb) x/4gx 0x00007fff86d50638
0x7fff86d50638: 0x00007fff86d50638 0x00007fff86d50660
0x7fff86d50648: 0x00006000037e8400 0x0009c0310000000f
(lldb) p/x 0x00007fff86d50638 & 0x007ffffffffffff8
(long) $13 = 0x00007fff86d50638
(lldb) po 0x00007fff86d50638
NSObject
Copy the code
  • Breakpoint Process summary
  1. The metaclassIsa pointingA metaclass
  2. Root metaclass isa pointing tooneself

MetaClass and rootMetaClass are the same as objc -> class -> metaClass -> rootMetaClass -> rootMetaClass in isa bitmap.

5. Class inheritance

    Class tMetaClass = object_getClass(NBTeacher.class);/ / NBTeacher metaclass
    Class tMetaSuperClass = class_getSuperclass(tMetaClass);// Superclass of the metaclass of NBTeacher
    
    Class pMetaClass = object_getClass(NBPerson.class); / / NBPerson metaclass
    Class pMeatSuperClass = class_getSuperclass(pMetaClass);// The parent class of the metaclass NBPerson
   
    Class nMetaClass = object_getClass(NSObject.class);/ / NSObject metaclass
    Class nSuperClass = class_getSuperclass(NSObject.class);/ / parent class NSObject
    Class nMetaSuperClass = class_getSuperclass(nMetaClass);// Superclass of NSObject's metaclass
    
    NSLog(@"NBTeacher-%p",NBTeacher.class);
    NSLog(@"NBPerson-%p",NBPerson.class);
    NSLog(@"NSObject-%p".NSObject.class);
 
    NSLog(@"%@ - %p - %@ - %p",tMetaClass,tMetaClass,tMetaSuperClass,tMetaSuperClass);
    NSLog(@"%@ - %p - %@ - %p",pMetaClass,pMetaClass,pMeatSuperClass,pMeatSuperClass);
    NSLog(@"%@ - %p - %@ - %p",nMetaClass,nMetaClass,nMetaSuperClass,nMetaSuperClass);
    NSLog(@"%@ - %p",nSuperClass,nSuperClass);
    
Copy the code
  • The output
202107 -27 - 16:59:36.204223+0800Memory offset [29797:756093] NBTeacher-0x10f015620
202107 -27 - 16:59:36.204689+0800Memory offset [29797:756093] NBPerson-0x10f0155d0
202107 -27 - 16:59:36.204782+0800Memory offset [29797:756093] NSObject-0x7fff86d50660
202107 -27 - 16:59:36.204917+0800Memory offset [29797:756093] NBTeacher - 0x10f0155f8 - NBPerson - 0x10f0155a8
202107 -27 - 16:59:36.205001+0800Memory offset [29797:756093] NBPerson - 0x10f0155a8 - NSObject - 0x7fff86d50638
202107 -27 - 16:59:36.205082+0800Memory offset [29797:756093] NSObject - 0x7fff86d50638 - NSObject - 0x7fff86d50660
202107 -27 - 16:59:36.205176+0800Memory offset [29797:756093] (null) - 0x0

Copy the code
  • NBTeacher is the parent class of the metaclassandNBPerson metaclassIs the same
  • The parent class of the NBPerson metaclassandNSObject metaclassIs the same
  • NBTeacherinheritanceNBPerson.NBPersoninheritanceNSObject.NSObjectIs the parent classnil
  • NBTeacherYuan class inheritanceNBPersonMetaclasses,NBPersoninheritanceA metaclass.A metaclassinheritanceNSObject

Third, class structure analysis

Look at objc4(version 818) source, objc-Runtimenew.h, and find objc_class structure as follows:

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 flags

    Class getSuperclass() const {
#if __has_feature(ptrauth_calls)
#   if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
        if (superclass == Nil)
            return Nil;

#if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
        void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
        if ((void *)superclass == stripped) {
            void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
            if ((void*)superclass ! = resigned)return Nil;
        }
#endif
            
        void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
        return (Class)result;

#   else
        return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
#   endif
#else
        return superclass;
#endif
    }
Copy the code
  • Source code analysisobjc_classinheritanceobjc_object.objc_objectThere’s only one member variableisa
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};
Copy the code
  • There is also a hidden ISA in the structure of the class, which takes 8 bytes

  • Class superClass is the parent Class of the Class. The pointer to the structure takes 8 bytes

  • Cache_t cache is the cache space of the class and takes up 16 bytes

  • Class_data_bits_t stores class data, such as attributes, methods, and so on.

1, explore the size of cache_t

  • Search for struct cache_t and find it
struct cache_t {
private:
    explicit_atomic<uintptr_t> _bucketsAndMaybeMask;/ / 8 bytes
    union {
        struct {
            explicit_atomic<mask_t>    _maybeMask;/ / 4 bytes
#if __LP64__
            uint16_t                   _flags;//2 bytes objc2 go this way
#endif
            uint16_t                   _occupied;/ / 2 bytes
        };
        explicit_atomic<preopt_cache_t *> _originalPreoptCache;/ / 8 bytes
    };

#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    // _bucketsAndMaybeMask is a buckets_t pointer
    // _maybeMask is the buckets mask

    static constexpr uintptr_t bucketsMask = ~0ul; static_assert(! CONFIG_USE_PREOPT_CACHES,"preoptimized caches not supported");
    / /... Ignore code that has nothing to do with the structure
  // The source code is located on lines 338-550 of the objc-runtime-new.h file
Copy the code
  • typedef unsigned long uintptr_tIt is an unsigned integer of 8 bytes.
  • preopt_cache_t *Is a pointer to a structure and takes 8 bytes.
  • uint16_tIt is an unsigned 16-bit integer, occupying 2 bytes.
  • Mask_t isuint32_tType, takes 4 bytes.
  • Cache_t has the following memory size:Uintptr_t Memory size 8 bytes+The union memory size is 8 bytes = 16 bytes

so

  • isaThe memory address isThe first address
  • superclassAddress isThe first address+0x08
  • cache_tAddress isThe first address+0x10
  • bitsAddress isThe first address+0x20

2. Class_data_bits_t bits structure

The class_datA_BITS_t bits structure records the attributes, member variables, and methods of a class. So you have to know what’s in the structure, class_data_bits

struct class_data_bits_t {
    friend objc_class;

    // Values are the FAST_ flags above.
    uintptr_t bits;
private:
    bool getBit(uintptr_t bit) const
    {
        return bits & bit;
    }

    // Atomically set the bits in `set` and clear the bits in `clear`.
    // set and clear must not overlap.
    void setAndClearBits(uintptr_t set, uintptr_t clear)
    {
        ASSERT((set & clear) == 0);
        uintptr_t newBits, oldBits = LoadExclusive(&bits);
      // Omit part of the code here
public:

    class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    void setData(class_rw_t *newData)
    {
   // Omit part of the code here
Copy the code
  • Class_rw_t source
struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint16_t witness; #if SUPPORT_INDEXED_ISA uint16_t index; #endif explicit_atomic<uintptr_t> ro_or_rw_ext; Class firstSubclass; Class nextSiblingClass; private: using ro_or_rw_ext_t = objc::PointerUnion<const class_ro_t, class_rw_ext_t, PTRAUTH_STR("class_ro_t"), PTRAUTH_STR("class_rw_ext_t")>; const ro_or_rw_ext_t get_ro_or_rwe() const { return ro_or_rw_ext_t{ro_or_rw_ext}; } void set_ro_or_rwe(const class_ro_t *ro) { ro_or_rw_ext_t{ro, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_relaxed); } void set_ro_or_rwe(class_rw_ext_t *rwe, const class_ro_t *ro) { // the release barrier is so that the class_rw_ext_t::ro initialization // is visible to lockless readers rwe->ro = ro; ro_or_rw_ext_t{rwe, &ro_or_rw_ext}.storeAt(ro_or_rw_ext, memory_order_release); } class_rw_ext_t *extAlloc(const class_ro_t *ro, bool deep = false); public: void setFlags(uint32_t set) { __c11_atomic_fetch_or((_Atomic(uint32_t) *)&flags, set, __ATOMIC_RELAXED); } void clearFlags(uint32_t clear) { __c11_atomic_fetch_and((_Atomic(uint32_t) *)&flags, ~clear, __ATOMIC_RELAXED); } // set and clear must not overlap void changeFlags(uint32_t set, uint32_t clear) { ASSERT((set & clear) == 0); uint32_t oldf, newf; do { oldf = flags; newf = (oldf | set) & ~clear; } while (! OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags)); } class_rw_ext_t *ext() const { return get_ro_or_rwe().dyn_cast<class_rw_ext_t *>(&ro_or_rw_ext); } class_rw_ext_t *extAllocIfNeeded() { auto v = get_ro_or_rwe(); if (fastpath(v.is<class_rw_ext_t *>())) { return v.get<class_rw_ext_t *>(&ro_or_rw_ext); } else { return extAlloc(v.get<const class_ro_t *>(&ro_or_rw_ext)); } } class_rw_ext_t *deepCopy(const class_ro_t *ro) { return extAlloc(ro, true); } 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); } void set_ro(const class_ro_t *ro) { auto v = get_ro_or_rwe(); if (v.is<class_rw_ext_t *>()) { v.get<class_rw_ext_t *>(&ro_or_rw_ext)->ro = ro; } else { set_ro_or_rwe(ro); } } 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<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()}; } } 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<const class_ro_t *>(&ro_or_rw_ext)->baseProperties}; } } const protocol_array_t protocols() 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)->protocols; } else { return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols}; }}};Copy the code
  • class_rw_tIs a structure type that providesGet the property list.Methods list.Agreement listMethods. Verify methods, properties, and variables by instanceclass_rw_tTo add attributes and methods and member variables to the class, follow the validation process.

3. Obtain member variables and class methods

  • New NBPerson
@interface NBPerson : NSObject{
    double height;
}

@property(nonatomic.copy)NSString *name;
@property(nonatomic.copy)NSString*nickName; - (void)sayHello; + (void)sayNB;


@end

@implementation NBPerson- (void)sayHello{
    NSLog(@"hello----"); } + (void)sayNB{
    NSLog(@"NB----");
}
@end

Copy the code
  • run
        NBPerson *nb = [NBPerson alloc];
        nb.name = @"nb";
        nb.nickName = @"nickeName";
        
Copy the code
  • Breakpoint debugging

(lldb) p/x NBPerson.class / / the current class
(Class) $4 = 0x0000000100008268 NBPerson
(lldb) p/x 0x0000000100008268 + 0x20 / / address bits
(long) $5 = 0x0000000100008288
(lldb) p (class_data_bits_t *)0x0000000100008288
(class_data_bits_t *) $6 = 0x0000000100008288
(lldb) p $6->data() // Get class_ro_t
(class_rw_t *) $7 = 0x0000000101315fb0
(lldb) p $7->properties() / / to find
(const property_array_t) $8 = {
  list_array_tt<property_t, property_list_t, RawPtr> = {
     = {
      list = {
        ptr = 0x00000001000081e8
      }
      arrayAndFlag = 4295000552
    }
  }
}
(lldb) p $8.list 
(const RawPtr<property_list_t>) $9 = {
  ptr = 0x00000001000081e8
}
(lldb) p $9.ptr // Find the property list address
(property_list_t *const) $10 = 0x00000001000081e8

(lldb) p *$10 // Get the property list data
(property_list_t) $11 = {
  entsize_list_tt<property_t, property_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 16, count = 2)
}
(lldb) p $11.get(0)// Find the first attribute
(property_t) $12 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb) p $11.get(1)// Find the second attribute
(property_t) $13 = (name = "nickName", attributes = "T@\"NSString\",C,N,V_nickName")
(lldb) p $11.get(2)// No third attribute array is out of boundsAn Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb) 

Copy the code
  • You can find the name attribute and nickname attribute

  • Height member variable not found

  • Where did the height go? Then find a

  • In addition to properties, methods, and protocols in class_rw_t, there is also a class_ro_t structure pointer type ro(),

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    union {
        const uint8_t * ivarLayout;
        Class nonMetaclass;
    };

    explicit_atomic<const char *> name;
    // With ptrauth, this is signed if it points to a small list, but
    // may be unsigned if it points to a big list.
    void *baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
Copy the code
  • Follow the debugging above
lldb) p $7->ro()
(const class_ro_t *) $18 = 0x00000001000080a0
(lldb) p $18.ivars
(const ivar_list_t *const) $19 = 0x0000000100008180
  Fix-it applied, fixed expression was: 
    $18->ivars
(lldb) p *$19
(const ivar_list_t) $20 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 3)
}
(lldb) p $20.get(0)
(ivar_t) $21 = {
  offset = 0x0000000100008228
  name = 0x0000000100003ecf "height"
  type = 0x0000000100003f29 "d"
  alignment_raw = 3
  size = 8
}
(lldb) p $20.get(1)
(ivar_t) $22 = {
  offset = 0x0000000100008230
  name = 0x0000000100003ed6 "_name"
  type = 0x0000000100003f2b "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) p $20.get(2)
(ivar_t) $23 = {
  offset = 0x0000000100008238
  name = 0x0000000100003edc "_nickName"
  type = 0x0000000100003f2b "@\"NSString\""
  alignment_raw = 3
  size = 8
}

(lldb) p $20.get(3)// The array is out of boundsAn Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb) 

Copy the code
conclusion
  • Find the height member variable and the _name,_nickNmae member variable

  • The underlying implementation of member variables is iVAR_t, which is stored in the class_ro_t member variable list

  • The system automatically adds _ attribute name variables to the attributes, stored in the class_ro_t member variable list

  • Methods to explore

(lldb) p $7->methods()
(const method_array_t) $24 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x00000001000080e8
      }
      arrayAndFlag = 4295000296
    }
  }
}
(lldb) p $24.list
(const method_list_t_authed_ptr<method_list_t>) $25 = {
  ptr = 0x00000001000080e8
}
(lldb) p $25.ptr
(method_list_t *const) $26 = 0x00000001000080e8
(lldb) p *$26
(method_list_t) $27 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 6)
}
(lldb) p $27.get(0).big()
(method_t::big) $28 = {
  name = "sayHello"
  types = 0x0000000100003f21 "v16@0:8"
  imp = 0x0000000100003c90 (KCObjcBuild`-[NBPerson sayHello] at main.m:31)
}
(lldb) p $27.get(1).big()
(method_t::big) $29 = {
  name = "name"
  types = 0x0000000100003f37 "@ @ 0:8 16"
  imp = 0x0000000100003cc0 (KCObjcBuild`-[NBPerson name] at main.m:20)}Copy the code
  • Object methods are stored in the method list method_list_t in the NBPerson class

  • The class method is not in the method list of NBPerson, method_list_t. Where are the class methods?

Found usingget(index)The way is not available to useget(index).big()To get it. Why is that?

Explore property_t and method_t

struct property_t { const char *name; const char *attributes; }; struct method_t { struct big { SEL name; const char *types; MethodListIMP imp; }; big &big() const { ASSERT(! isSmall()); return *(struct big *)this; } SEL name() const { if (isSmall()) { return (small().inSharedCache() ? (SEL)small().name.get() : *(SEL *)small().name.get()); } else { return big().name; } } const char *types() const { return isSmall() ? small().types.get() : big().types; } IMP imp(bool needsLock) const { if (isSmall()) { IMP imp = remappedImp(needsLock); if (! imp) imp = ptrauth_sign_unauthenticated(small().imp.get(), ptrauth_key_function_pointer, 0); return imp; } return big().imp; }Copy the code
  • attributeThe underlying implementation isproperty_tIn theproperty_tStructure is defined innameVariables such as
  • methodsThe underlying implementation ismethod_tIn themethod_tStructure defined in thebig()Through thebig()To obtainSELandIMP
Continue to find methods
(lldb)  p $27.get(2).big()
(method_t::big) $31 = {
  name = ".cxx_destruct"
  types = 0x0000000100003f21 "v16@0:8"
  imp = 0x0000000100003d80 (KCObjcBuild`-[NBPerson .cxx_destruct] at main.m:29)
}
(lldb) p $27.get(3).big()
(method_t::big) $32 = {
  name = "setName:"
  types = 0x0000000100003f3f "v24@0:8@16"
  imp = 0x0000000100003cf0 (KCObjcBuild`-[NBPerson setName:] at main.m:20)
}
(lldb) p $27.get(4).big()
(method_t::big) $33 = {
  name = "nickName"
  types = 0x0000000100003f37 "@ @ 0:8 16"
  imp = 0x0000000100003d20 (KCObjcBuild`-[NBPerson nickName] at main.m:21)
}
(lldb) p $27.get(5).big()
(method_t::big) $34 = {
  name = "setNickName:"
  types = 0x0000000100003f3f "v24@0:8@16"
  imp = 0x0000000100003d50 (KCObjcBuild`-[NBPerson setNickName:] at main.m:21)
}
(lldb) p $27.get(6). The big () an Assertion failed: (I < count), the function of get the file/Users/xiaozhongwang/Desktop/file summary/iOS/objc4_debug - master/objc4818.2/runtime/objc-runtime-new.h, line 624.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
(lldb) 
Copy the code
  • method_list_tThere areObject methods, the properties of theA setter methodandGetter method
  • method_list_tIs not obtained inClass method
To explore the metaclass
(lldb) p/x object_getClass(NBPerson.class)
(Class) $0 = 0x0000000100008240
(lldb) p/x 0x0000000100008240 + 0x20 
(long) $1 = 0x0000000100008260
(lldb) p (class_data_bits_t*)0x0000000100008260
(class_data_bits_t *) $2 = 0x0000000100008260
(lldb) p $2->data()
(class_rw_t *) $3 = 0x0000000100627d70
(lldb) p $3->methods()
(const method_array_t) $4 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x0000000100008080
      }
      arrayAndFlag = 4295000192
    }
  }
}
(lldb) p $4.list.ptr
(method_list_t *const) $5 = 0x0000000100008080
(lldb) p * $5
(method_list_t) $6 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 27, count = 1)
}
(lldb) p $6.get(0).big()
(method_t::big) $7 = {
  name = "sayNB"
  types = 0x0000000100003f21 "v16@0:8"
  imp = 0x0000000100003c60 (KCObjcBuild`+[NBPerson sayNB] at main.m:34)}Copy the code
  • Find sayNB in the metaclass

  • Object_getClass gets the metaclass of JCPerson

  • Class methods are stored in the metaclasses method_list_t

Conclusion:
  • Class structure is mainly composed of isa, superclass, cache, composed of bits

  • Bits store attributes, methods, and protocols

  • Properties are stored in property_list_t, and member variables are stored in class_ro_t–> iVAR_list_T. The _ property name variable automatically generated by the system for the property is also stored in class_ro_t–> iVAR_list_t

  • Methods are stored in method_list_t, which mainly stores object methods, setter and getter methods for properties, and class methods are stored in the metaclass method_list_t