preface

  • IOS low-level exploration — Alloc, init, new exploration
  • IOS Low-level Exploration – Memory byte alignment analysis
  • IOS Low-level Exploration – The nature of objects
  • IOS Low-level Exploration – Isa initialization & Pointing Analysis

Continuous pointer memory offset

An int array [] = {1, 4-trichlorobenzene}; int *b = array; NSLog(@"%p-%p-%p-%p",&array,&array[0],&array[1],&array[2]);
NSLog(@"%p-%p-%p",b,b+1,b+2);
        
for (int i = 0; i < 3; i++) {
      int value = *(b+i);
     NSLog(@"value-%d",value); } 2019-12-21 21:06:11.914923+0800 XDTest[2663:291951] 0x7ffeefbff5bc-0x7ffeefbff5c0-0x7ffeefbff5C4 2019-12-21 21:06:11.915605+0800 XDTest[2663:291951] 0x7ffeefbff5bc-0x7ffeefbff5c0-0x7ffeefbff5c4 2019-12-21 21:06:11.915673+0800 XDTest[2663:291951] value-1 2019-12-21 21:06:11.915729+0800 XDTest[2663:291951] value-2 2019-12-21 21:06:11. 915756 + 0800 XDTest [2663-291951] value - 4Copy the code
  • Pointer to thebThe address ofarrayThe first address of the array.
  • The next contiguous memory address can be found by pointer offset.

Class structure analysis

1. Everything is an object

typedef struct objc_class *Class;
struct objc_class : objc_object{};
Copy the code
  • From the source code we can know the classClassThe essence ofobjc_class.
  • objc_classInherited fromobjc_objectVerify that everything is an object.

Q1: Objc_class is related to NSObject.

NSObject is a class, essentially objc_class.

Q2: The relationship between objC_Object and NSObject?

NSObject is of type OC, objc_Object is of type C. NSObject is a wrapper around objc_Object.

2. Class structure

struct objc_class : objc_object {
    // Class ISA;           //8
    Class superclass;       //8
    cache_t cache;          //16        // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() { 
        returnbits.data(); }... Omit other information... };Copy the code

3. Class structure member analysis

3.1 Class ISA

An annotated member, representing inherited from the parent class, takes 8 bytes.

struct objc_object { private: isa_t isa; . Omit other information... };Copy the code

3.2 Class superclass

A pointer to the parent Class, which is itself a pointer, takes 8 bytes.

3.3 cache_t cache

As the name implies, it is an object that stores the cache and takes up 16 bytes

truct cache_t { struct bucket_t *_buckets; // Pointer takes up 8 bytes mask_t _mask; Mask_t _occupied; // Take up 4 bytes... Omit other information... };Copy the code

3.4 class_data_bits_t bits

A structure, we find that some of the relevant information of the class is not seen in the first three members, with this we can analyze, class related attributes, member variables, methods are in this structure.

4. class_data_bits_tin-depth

By analyzing the structure of class isa, superclass, cache and other attributes, there is no relationship with our custom attributes, so we explore bits.

  1. We also see the following line of code in the class structure
 class_rw_t *data() { 
        return bits.data();
    }
Copy the code

The bits function can be used to retrieve the class_rw_t structure directly.

  1. To observe theclass_rw_tThe structure of the body
struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint32_t version; const class_ro_t *ro; method_array_t methods; property_array_t properties; protocol_array_t protocols; . Omit other information... };Copy the code

We seem to see familiar data types associated with properties, methods, proxies, and so on. Note, however, that the properties and methods of our class do not have properties of the method_array_t or property_array_t type (which is described in a later section). It’s stored in a structure called class_ro_t, and we can see that it’s const, which means that it’s defined at compile time, and it can’t be changed later.

  1. To observe theclass_ro_tThe structure of the body
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endifconst uint8_t * ivarLayout; const char * name; method_list_t * baseMethodList; protocol_list_t * baseProtocols; const ivar_list_t * ivars; const uint8_t * weakIvarLayout; property_list_t *baseProperties; . Omit other information...Copy the code
  • Member variable storageconst ivar_list_t * ivars.
  • Attribute to depositproperty_list_t *baseProperties.
  • Methods to depositmethod_list_t * baseMethodList.

5. Attribute-method attribution exploration

5.1 Preparations

Define member variables, properties, object methods, and class methods.

@interface XDPerson : NSObject
{
    NSString *otherName;
}
@property (nonatomic, copy) NSString *nickName;

- (void)sayHello;

+ (void)sayHappy;
@end
Copy the code

5.2 LLDB debugging

At the beginning of this article, we learned that we can find the memory segment in contiguity by pointer offset.

  1. See the classXDPersonMemory information of
(lldb) x/4gx XDPerson.class
0x100001318: 0x001d8001000012f1 0x0000000100aff140
0x100001328: 0x000000010203ce00 0x0000000200000003
Copy the code
  1. We know the information is thereobjc_classStructure of thebitsProperty, found by memory address offsetbitsWe’ll go straight to the memory address of0x100001318+32 bytes =0x100001338
(lldb) p (class_data_bits_t *)0x100001338
(class_data_bits_t *) The $1 = 0x0000000100001338
Copy the code
  1. Looking forclass_rw_tthroughbits.data()
(lldb) p The $1->data()
(class_rw_t *) $2 = 0x000000010203cd50
Copy the code
  1. To viewclass_rw_tMemory data information
(lldb) p *$2
(class_rw_t) $3 = {
  flags = 2148139008
  version = 0
  ro = 0x00000001000011f0
  methods = {
    list_array_tt<method_t, method_list_t> = {
       = {
        list = 0x0000000100001128
        arrayAndFlag = 4294971688
      }
    }
  }
  properties = {
    list_array_tt<property_t, property_list_t> = {
       = {
        list = 0x00000001000011d8
        arrayAndFlag = 4294971864
      }
    }
  }
  protocols = {
    list_array_tt<unsigned long, protocol_list_t> = {
       = {
        list = 0x0000000000000000
        arrayAndFlag = 0
      }
    }
  }
  firstSubclass = nil
  nextSiblingClass = NSDate
  demangledName = 0x0000000000000000 <no value available>
}
Copy the code
  1. Check the targetro
(lldb) p $3.ro
(const class_ro_t *) $4 = 0x00000001000011f0
Copy the code
  1. To viewclass_ro_tMemory data information
(lldb) p *$4
(const class_ro_t) A $5 = {
  flags = 388
  instanceStart = 8
  instanceSize = 24
  reserved = 0
  ivarLayout = 0x0000000100000f80 "\x02"
  name = 0x0000000100000f77 "XDPerson"
  baseMethodList = 0x0000000100001128
  baseProtocols = 0x0000000000000000
  ivars = 0x0000000100001190
  weakIvarLayout = 0x0000000000000000 <no value available>
  baseProperties = 0x00000001000011d8
  _swiftMetadataInitializer_NEVER_USE = {}
}
Copy the code
  1. To viewbaseProperties
(lldb) p A $5.baseProperties
(property_list_t *const) $6 = 0x00000001000011d8
(lldb) p *$6
(property_list_t) $7 = {
  entsize_list_tt<property_t, property_list_t, 0> = {
    entsizeAndFlags = 16
    count = 1
    first = (name = "nickName", attributes = "T@"NSString",C,N,V_nickName")}}Copy the code

There is one and only one element nickName that is the same as what we defined.

  1. To viewivars
(lldb) p A $5.ivars
(const ivar_list_t *const) $8 = 0x0000000100001190
(lldb) p *$8
(const ivar_list_t) $9 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0> = {
    entsizeAndFlags = 32
    count = 2
    first = {
      offset = 0x00000001000012e8
      name = 0x0000000100000f20 "otherName"
      type = 0x0000000100000fa7 "@"NSString""
      alignment_raw = 3
      size = 8
    }
  }
}
(lldb) p $9.get(0)
(ivar_t) $10 = {
  offset = 0x00000001000012e8
  name = 0x0000000100000f20 "otherName"
  type = 0x0000000100000fa7 "@"NSString""
  alignment_raw = 3
  size = 8
}
(lldb) p $9.get(1)
(ivar_t) $11 = {
  offset = 0x00000001000012e0
  name = 0x0000000100000f2a "_nickName"
  type = 0x0000000100000fa7 "@"NSString""
  alignment_raw = 3
  size = 8
}
Copy the code

There are two elements, one is the member variable otherName and the other is the compile-generated member variable _nickName.

  1. To viewbaseMothedList
(lldb) p A $5.baseMethodList
(method_list_t *const) $12 = 0x0000000100001128
(lldb) p *$12
(method_list_t) $13 = {
  entsize_list_tt<method_t, method_list_t, 3> = {
    entsizeAndFlags = 26
    count = 4
    first = {
      name = "sayHello"
      types = 0x0000000100000f8c "v16@0:8"
      imp = 0x0000000100000d70 (XDTest`-[XDPerson sayHello] at XDPerson.m:11)
    }
  }
}
(lldb) p $13.get(0)
(method_t) $14 = {
  name = "sayHello"
  types = 0x0000000100000f8c "v16@0:8"
  imp = 0x0000000100000d70 (XDTest`-[XDPerson sayHello] at XDPerson.m:11)
}
(lldb) p $13.get(1)
(method_t) $15 = {
  name = "nickName"
  types = 0x0000000100000f94 "@ @ 0:8 16"
  imp = 0x0000000100000d90 (XDTest`-[XDPerson nickName] at XDPerson.h:16)
}
(lldb) p $13.get(2)
(method_t) $16 = {
  name = "setNickName:"
  types = 0x0000000100000f9c "v24@0:8@16"
  imp = 0x0000000100000dc0 (XDTest`-[XDPerson setNickName:] at XDPerson.h:16)
}
(lldb) p $13.get(3)
(method_t) $17 = {
  name = ".cxx_destruct"
  types = 0x0000000100000f8c "v16@0:8"
  imp = 0x0000000100000e00 (XDTest`-[XDPerson .cxx_destruct] at XDPerson.m:10)
}
Copy the code
  • sayHelloObject method defined.
  • nickNamebottom-generatedgetterMethods.
  • setNickName:bottom-generatedsetterMethods.
  • .cxx_destructsystemc++Destructor of.

It is also verified that the property generates ivar+getter+setter underneath.

  1. sayHappyWhere did the class method go?

Through the analysis of this article, we can know that the class in the metaclass is also equivalent to an object. Will the class method of that class be stored in the metaclass like an object method?

. Omit debugging to find information about metaclasses... (lldb) p$25.baseMethodList
(method_list_t *const) $26 = 0x00000001000010c0
(lldb) p *$26
(method_list_t) $27 = {
  entsize_list_tt<method_t, method_list_t, 3> = {
    entsizeAndFlags = 26
    count = 1
    first = {
    name = "sayHappy"
    types = 0x0000000100000f8c "v16@0:8"
    imp = 0x0000000100000d80 (XDTest`+[XDPerson sayHappy] at XDPerson.m:15)
    }
  }
}
Copy the code

The sayHappy class method is found in the metaclass.

Verify that our member traversal, properties, and methods are found in the body of class_ro_t.

In fact, THE author also went to look for the agreement, but unfortunately did not find it, I will study the agreement separately later, limited forgiveness ability, please point out the shortcomings.

Analysis of other structures

In the above analysis we saw property_t, ivar_t, method_t. Now let’s do a simple analysis.

1. property_t

struct property_t {
    const char *name;
    const char *attributes;
};
Copy the code
  • nameThe name of the property;
  • attributesDescription field;

2. ivar_t

struct ivar_t {
#if __x86_64__
    // *offset was originally 64-bit on some x86_64 platforms.
    // We read and write only 32 bits of it.
    // Some metadata provides all 64 bits. This is harmless for unsigned 
    // little-endian values.
    // Some code uses all 64 bits. class_addIvar() over-allocates the 
    // offset for their benefit.
#endif
    int32_t *offset;
    const char *name;
    const char *type;
    // alignment is sometimes -1; use alignment() instead
    uint32_t alignment_raw;
    uint32_t size;

    uint32_t alignment() const {
        if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
        return1 << alignment_raw; }};Copy the code
  • offsetOffset memory address;
  • nameThe name;
  • typeType;
  • alignment_rawAlignment information;
  • sizeBytes occupied;

3. method_t

struct method_t {
    SEL name;
    const char *types;
    MethodListIMP imp;  //using MethodListIMP = IMP;

    struct SortBySELAddress :
        public std::binary_function<const method_t&,
                                    const method_t&, bool>
    {
        bool operator() (const method_t& lhs,
                         const method_t& rhs)
        { returnlhs.name < rhs.name; }}; };Copy the code
  • nameThe method name;
  • typesMethod before;
  • impMethod implementation;

The road of learning, forge ahead

The shortcomings can be pointed out in the comments section