Xiaogu iOS low-level blog collection

  • When we want to understand something, we often have a question, so today we look at the legendisaAnd, of course, with questions:isaWhat is? Saved? What structure?
  • OK, so here we go!

1. Preparation

Before exploring ISA. Let me start a wave of God perspective: first know the union and bitfield (ISA useful).

  • In everyday iOS development, it’s almost never used. So most people don’t understand. It also makes it difficult to explore the ground floor.

I will briefly explain, if you want to know more about, I wrote another blog post: unions and bitfields. I hope it will be helpful

1.1. Union and bitfield

  • A consortiumAll members share a memory, pull a whole body! Members are mutually exclusive! Modifying one member affects other members!
  • A domainThe simple understanding is thatpositionI have limited literary ability. You’ll see what it means if you read it slowly. Can you also read itUnion and bitfield )

1.2. Requirements

  • Prepare a copy of the underlying Source code (not to find Apple Source! There is also a second hand: I also have a blog 😆 objC4 source compilation debugging)

2. Start exploring

  • Once you’ve done your homework — start digging!

2.1. Find out the isa

  • Every class object has oneisaWe don’t know what this is right now. So let’s write some code to get this thing wrong:

  • The essence of each object is also a structure (as I’ll prove in the extensions below) that we can findisa. However,isaWhat on earth is stored in. How does he relate classes? How do you save it? Then begin the exploration process.

2.2. Trace where ISA was created

  • We set a breakpoint. Step by step exploration is shown in Figure 3:

  • The final way to go isobjc_object::initIsaThat’s what we’re working on.
  • The code looks like this:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ ASSERT(! isTaggedPointer());if(! nonpointer) { isa =isa_t((uintptr_t)cls);
    } else{ ASSERT(! DisableNonpointerIsa); ASSERT(! cls->instancesRequireRawIsa());isa_t newisa(0);

#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // This write must be performed in a single store in some cases
        // (for example when realizing a class because other threads
        // may simultaneously try to use the class).
        // fixme use atomics here to guarantee single-store and to
        // guarantee memory order w.r.t. the class index table
        / /... but not too atomic because we don't want to hurt instantiationisa = newisa; }}Copy the code
  • All but the system classnonpointer. This is where you can test it. So the first thing we have to determine is thisclsIs the class we will explore:

  • initIsaMethod I draw a flow chart, we first observe how he is running!

2.3 isa structure analysis

  • We already know thatisaCreate assignment process. So we have another question:isaisisa_tThe structure of the. thenisa_tWhat is? No hurry, let’s click in and have a look

  • Brothers! God’s perspective is pretty cool. It’s just union and bitfield.

  • Of course! Again, the question is: what is assigned? How does it get assigned?

  • All right! I made another graph (this graph may not make any sense {I think everyone knows!! })

  • And then, we knowisaThe structure,isaWhat’s in it
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
Copy the code
  • This is theisaBut what are these things?

2.4 Structure Explanation

  • Nonpointer: indicates whether to enable pointer optimization for the ISA pointer. 0: indicates the pure ISA pointer. 1: Indicates that the ISA contains not only the address of the class object but also the class information and reference count of the object.

  • Has_assoc: flag bit of the associated object. 0 does not exist and 1 exists

  • Has_cxx_dtor: does the object have a destructor for C++ or Objc? If it has a destructor, the destructor logic needs to be done. If not, the object can be freed faster

  • Shiftcls: Stores the value of the class pointer. With pointer optimization turned on, 33 bits are used to store class Pointers in the ARM64 architecture.

  • Magic: Used by the debugger to determine whether the current object is a real object or has no space to initialize

  • Weakly_referenced: Weak variable of whether a zhi object is or has been pointed to an ARC,

Objects without weak references can be released faster

  • Deallocating: Indicates whether the object is freeing memory

  • Has_sidetable_rc: When the object reference count is greater than 10, it needs to borrow this variable to store carry

  • Extra_rc: When representing the reference count of this object, the reference count is actually subtracted by 1. For example, if the object’s reference count is 10, the extra_rc is 9. If the reference count is greater than 10, the following has_sideTABLE_rc is used.

  • We all understand the bitfield, there is a more graphic image (I stole! :

Since I’m running on a Mac, I’m running on x86, and an iPhone is running on ARM64, which is pretty much the same.

2.4. Assignment code

  • Let’s look at the assignment code
newisa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.shiftcls = (uintptr_t)cls >> 3;
Copy the code
  • As ifshiftclsThat’s the key. Don’t we have to see what it is. And why did we move it three places to the right?
  • First of all, we po (uintptr_t)cls --> XGPerson
  • This. This is the class we want.
  • Why did I move 3 places to the right? Explanation: It says aboveisaStructure: The first three havenonpointer.has_assoc.has_cxx_dtor, occupied 3 places!!

2.5. Reverse (don’t think 😜)

  • Continue with breakpoint debugging! .
  • So once we’re done with the assignment, let’s look at thisshiftcls!
  • Because I’m doing this inx86So I’m going to put,objtheisa–> 3 places to the right, 20 places to the left, 17 places to the rightisaIn theshiftclsAll others are cleared.)

Don't bother with this shift, it's actually 3 to the right, 3 to the left, 17 to the left, 17 to the right.

Results:

Reverse push done!!

3. Expand the clang

  • Clang. Should be familiar to most iOS developers. But blogging. I must say all of a sudden (because I am strange ah. 😭)

  • Clang is a lightweight compiler for C, C++, and Objective-C. Source code is published under the BSD protocol. Clang will support its normal lambda expressions, simplified handling of return types, and better handling of constEXPr keywords

  • 2.Clang is an Apple-led C/C++/Objective-C compiler based on LLVM

  • 3. How to use it directly is more reliable!! I stole another wave chart:

Generate main.cpp! With the first command. The object is a structure.