This is the third day of my participation in the August More text Challenge. For details, see: August More Text Challenge

I. Analysis of the principle of the class

The principle analysis of the class is mainly to analyze ISA and inheritance relationship.

Starting with ISA – THE ISA locus chain

First we get the isa mask 0x00007FFFFFFFF8ULL, then we get the address of the object, and get the ISA of the object.

At this point, we get the ISA mask: 0x00007FFFFFFFF8ULL and the ISA for the object: 0x011d800100008365, and we’ll get the address of our class 0x0000000100008360, and we’ll Po the address to prove that it is indeed LGPerson.

So let’s guess, can we have the address of the class x/4gx? Let’s try it out.

As you can see from the image, classes also have corresponding memory structures. Is 0x0000000100008338 isa for a class? Let’s try 0x0000000100008338 and the mask.

You can see from the picture that we’re still getting the LGPerson class, so let’s try to print out the address of the two

The address of the LGPerson class is 0x0000000100008360, so why is 0x0000000100008338 LGPerson class? Is there more than one class in memory because classes are as infinite as objects? So let’s verify that.

Here we create multiple LGPerson classes, and we print their addresses to see if their addresses are the same.

This means that only 0x100008360 is our LGPerson class, and 0x0000000100008338 is not. It is a new thing, which is the metaclass.

The metaclass

  • The object of the isaIt points to a class, which is actually an object, so it can be calledClass object, whose ISA bit field points to the Apple-definedThe metaclass, a metaclass is the class of a class object.
  • Metaclasses do not exist in code. Metaclasses aresystemTo itdefineandcreateAre made ofThe compilerIn this process, the class attribution comes from the metaclass.
  • The existence of metaclasses isnecessaryBecause it stores all of a classClass method. The metaclasses of every class areuniqueBecause each class has a unique set of class methods.
  • Metaclasses themselves areThere is no nameIs used because of its association with the classSame name as same nameThe name of the

Explore metaclasses with MachOView(Rotten Apple)

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

It’s just LGPerson, LGTeacher and NSObject. Let’s open Section64 (_DATA_CONST,_objc, classList).

Still only LGTeacher: 0000001000008310 and LGPerson: 0000001000008360. Next we go to the symbols table and look for the symbols class.

There’s one more thing, _OBJC_METACLASS_$_LGTeacher, and _OBJC_METACLASS_$_LGPerson, which means we have one more thing, which is metaclasses, and metaclasses are generated and compiled by the system.

Having explored this, we know that isa for objects points to classes, isa for classes points to metaclasses, so where does ISA for metaclasses point to? Let’s explore.

We use 0x00007FFf80715FE0 to and the mask, and the Po outputs the resulting address to see what it is.

So we can see that isa for the metaclass refers to NSObject, which is the root metaclass. So where does isa for the root metaclass point to?

As you can see from the picture, the root metaclass’s ISA points to itself.

So let’s continue our explorationNSObject.class.

As you can see from the figure above, our NSObject is different from the address above, so let’s print the address that we got.

As you can see from the figure above, the ISA for NSObject is 0x00007FFF80715FE0, and we will sum this address with the mask.

It will then print 0x00007FFF80715FE0 again.

We find that we get the same root metaclass as we did before, and that ISA also points to itself. There are three steps from the OBJECT’s ISA to the root metaclass. Object isa➡️ class isa➡️ metaclass isa➡️ Root metaclass. From an NSObject to the root metaclass, it takes only two steps. The root object isa ➡️ root class isa ➡️ root metaclass this gives a very classic isa bitmap:

Inheritance chain

The inheritance relationship between classes

We use a LGTeacher class that inherits from the LGPerson class to explore the inheritance relationships between classes.

As you can see from the picture above, LGTeacher inherits from LGPerson, LGPerson inherits from NSObject, and NSObject inherits from Nil.

From this we can derive the inheritance relationship between classes:

  • Class (ttf_subclass) inherited fromSuperClass (superClass).
  • SuperClass (superClass)Inherited fromRootClassIn this case, the root class isNSObject.
  • The root classInherited fromnil, so the root class isNSObjectBe understood asOrigin of all thingsOut of thin air.

Inheritance relationships between metaclasses

Having explored the inheritance relationships between classes, we continue to explore the inheritance relationships between metaclasses.

So let’s look at the metaclass of LGTeacher, and you can see from the output that it inherits from LGPerson, so does it inherit from LGPerson or does it inherit from metaclass? Let’s verify that.

As you can see from the figure above,LGTeacher metaclassIs inherited fromLGPerson metaclass.

So where does the LGPerson metaclass come from? Let’s take a look:

As you can see from the figure above, the LGPerson metaclass inherits from the NSObject metaclass.

Let’s explore where the NSObject metaclass inherits from:

We got it firstRoot metaclass (NSObject)Then print out the superclass of the root metaclass, as shown by LLDB,A metaclassInherited fromRoot class (NSObject).

Let’s take a final look at the root class NSObject inheritance:

As you can see from the output, the root class inherits from null.

From the above exploration process, we can get: Metaclasses also have inheritance, and the inheritance relationship between metaclasses is as follows:

  • Metal SubClass metaclassInherited fromThe metal SuperClass of the metal SuperClass
  • The metal SuperClass of the metal SuperClassInherited fromRoot Metal Class Root Metal Class
  • Root Metal Class Root Metal ClassInheritance inRoot classIn this case the root class is NSObject
  • The root classInheritance innull

Inheritance chain diagram:

Combining the ISA bitmap with the inheritance chain, we can prove a map from an official Apple document.

Ii. Structural analysis of class

First look at the contents of our LGPerson class.

Print out the LGPerson class

As you can see from the figure above, LGPerson has memory, so what’s in memory. We know that the nature of the class is objc_class. We search objc source code for the definition of objc_class:

We can see that there is a definition of the objc_class structure here, but notice that OBJC2_UNAVAILABLE is below, which means that the structure is invalid in objC2, so this is not what we are looking for. Keep looking in the objc source code:

Finally, we find the definition of the objc_class structure, and we find that objc_class inherits from objc_object, so we look for objc_object in the source code, and see what members objc_object has.

As you can see from the diagram, objc_Object has isa in it, and since objc_class inherits from objc_Object, objc_class also has the ISA property. We also see that objc_class has three members: Class superclass, cache_t cache, and class_data_bits_t bits. We know that superclass is the current superclass, so what is cache and bits?

Memory migration

Ordinary pointer

As you can see from the picture,

  • A and B both point to 10, but the addresses of a and B are different. This is a copy of value copy, also known as deep copy

  • The addresses of A and B differ by four bytes, depending on the type of a and B

The address points to the following figure

Pointer to the object

As you can see from the picture,

  • P1, p2Pointer to the[CJLPerson alloc] (CJLPerson alloc) (CJLPerson alloc)
  • &p1 and &p2 are the addresses of Pointers to objects p1 and p2The secondary pointer.

Pointer to an array

It can be seen from the above figure:

  • &c and&c[0]Is to takeThe first addressThat is, the array name equals the first address
  • &c differs from &C [1]4 bytes, the number of bytes between addresses, depending onThe type of data stored
  • Can be achieved byInitial address + offsetRetrieve the other elements of the array, where the offset is the array’s subscript and the actual number of bytes moved from the first address in memory is equal toOffset * Number of bytes of the data type

Class address translation

Translation address calculation

From the above exploration, we know that a class has four members:

  • isaProperty: isa inherited from objc_object, with8byte
  • superclassProperty: type Class, defined by objc_object, is a pointer, occupied8byte
  • cacheProperties:cache_tType, I don’t know how many bytes
  • bitsProperties:class_data_bits_tI don’t know how many bytes

As you can see from the figure above, 0x00000001000083a8 points to the metaclass of LGPerson, which proves that 0x00000001000083a8 is indeed ISA.

As we can see from the figure above, 0x000000010036A140 points to NSObject, which proves that 0x000000010036A140 is indeed a superclass.

To see how many bytes the cache_t type is, we find the cache_t structure:

Since methods in the method area do not reside in the structure body and static in the global area does not reside in the structure body, the methods and static properties below can be ignored. So all we need to do is look at these variables.

The first is the explicit_atomic

_bucketsAndMaybeMask attribute, how much memory does this attribute take.

We see that explicit_atomic is a paradigm, so it’s the UintPtr_t guy that really determines how much memory is being used, and this guy is actually an unsigned long. Unsigned long is 8 bytes in 64 bits. In other words, explicit_atomic

_bucketsAndMaybeMask is 8 bytes.

Next we have a union. We know that the variables in a union are mutually exclusive, and that all the members occupy a memory equal to the memory occupied by the largest member.

Explicit_atomic <preopt_cache_t *> _originalPreoptCache The maximum memory used by this pointer is 8, so the maximum memory used by this union is 8. So we just shift the first address of our LGPerson class shift 8 + 8 + 16 = 32 bits, and we get the address of our bits.

Class

Here we know that this is the address of class_data_bits_t, so we can convert the address to class_data_bits_t pointer type,

Then we use the data() method provided in the structure to get the data, because it is a pointer, so we use ->, if it is an object, we use dot syntax.

So we see here, firstSubclass is nil, but our LGTeacher is inherited from LGPerson, so why is this nil? Because our class loads are lazy, so if we access this class, LGPerson will have a firstSubclass. Try this:

We get the data, we print it out. Seeing that we don’t have the data we need, we go into the class_rw_t structure and find the following method.

We first get the property array:

And then get the List

Get the PTR for list

Restore the data inside

Get the data in there

So we have the properties name and hobby that we want.

Class

Let’s get the method list of the class. Get the method array first.

Then get the PTR directly

And then restore the data inside

And then we’re going to get the data one by one

So we have all the methods. Here we notice that the fetching method is different from the fetching method of the property. Why is that?

That’s because the structure of property_t is different than the structure of method_t. The member variables for method_t are in BIG, so we need to add big () to call the big method to get the member variables

Class

Declare a protocol, add a method, and then add the protocol for LGPerson.

To achieve the

Continue with the previous process.

So we’ve got protocol list.

We see that the protocols() method returns a protocol () of protocol_array_t. Let’s take a look at what protocol_array_t looks like.

Seeing that we finally get a protocol_ref_t, click in and see what a protocol_ref_t is.

Protocol_ref_t is an unsigned long integer.

Print the $5 value and find that it is of type PROTOCOL_list_T.

Take a look at what protocol_list_t looks like.

There is no place to print protocol_ref_t. So how do I get information from protocol_ref_t? Search the source code for protocol_ref_t.

If you see that it has remapProtocol, whereas before protocol_ref_t it said but unremapped, and here it returns a type protocol_t, is this the required method? Let’s follow this approach and force a protocol_ref_t to type protocol_t *.

In protocol_list_t, protocol_ref_t is a list[0]:

We get the protocol_ref_t from the PROTOCOL_list_t.

Then the protocol_ref_t is forcefully converted to a type protocol_t *

Print it out, and you get the data you want.

Print the method.

That’s what we created before.

The location of the class method

Ivar’s position

Let’s start by adding a few member variables.

Then progressively acquire: