Xiaogu iOS low-level blog collection
- When we want to understand something, we often have a question, so today we look at the legend
isa
And, of course, with questions:isa
What 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 consortium
All members share a memory, pull a whole body! Members are mutually exclusive! Modifying one member affects other members!A domain
The simple understanding is thatposition
I 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 one
isa
We 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 find
isa
. However,isa
What 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 is
objc_object::initIsa
That’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 class
nonpointer
. This is where you can test it. So the first thing we have to determine is thiscls
Is the class we will explore:
initIsa
Method I draw a flow chart, we first observe how he is running!
2.3 isa structure analysis
- We already know that
isa
Create assignment process. So we have another question:isa
isisa_t
The structure of the. thenisa_t
What 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 know
isa
The structure,isa
What’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 the
isa
But 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 if
shiftcls
That’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 above
isa
Structure: 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 this
shiftcls
! - Because I’m doing this in
x86
So I’m going to put,obj
theisa
–> 3 places to the right, 20 places to the left, 17 places to the rightisa
In theshiftcls
All 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.