This is the 30th day of my participation in the August Challenge
In the last blog post, I explored the essence of a block that the structure (__main_block_IMPL_0) inherits from __block_impl, that blocks can capture external variables, and that __block decorates the interior to change the value of external variables. This blog will examine the underlying principles for continuing to work with blocks.
IOS Basic Block Exploration (1) — Getting to know Blocks (How many blocks do you know?)
IOS Basic Exploration Block(2) — How to solve the Block circular reference problem?
IOS Basic Exploration of Blocks (iii) — The nature of blocks
1. Block tracing the source
In the past analysis is to find the source of the analysis object, and then look at the corresponding source code for analysis, so the block is from which library, it is not known, we are trying to find out.
Assembly view process
Through simple
block
Code to see the assembly call, whether there will be a different discovery!
As you can see from the process compiled above at 👆, one is called
objc_retainBlock
.objc
That’s what it starts withlibobjc.A.dylib
Source code library! So I’m going to verify that again, using the sign breakpoint to see if that’s truelibobjc.A.dylib
。
Sign breakpoint validation
Through the symbol breakpoint, it is also verified that it is from the familiar libobjc.a.dylib source library, as shown below:
Running through the code again, I did go to the symbol breakpoint below, and also found that it was from
libobjc.A.dylib
, tested the above conjecture, andjmp
Jump to_Block_copy
, the source code can also be verified:
It is known from the source that calling objc_retainBlock returns _Block_copy, but the implementation of the _Block_copy method is not found in the source code.
Since there is no source
_Block_copy
The realization of a bold guess, is not inlibobjc.A.dylib
The inside? Then go down_Block_copy
Symbol breakpoint look not to know ah! As follows:
Through the
_Block_copy
Symbol breakpoint trace, found_Block_copy
Comes from thelibsystem_blocks.dylib
This library, but this onelibsystem_blocks.dylib
Without open source, this wave of operations is annoying. So what to do? There are two ways that we already know fromlibsystem_blocks.dylib
Can disassemble, there is a way is to findlibclosure
Instead, it’s ok.
Search libclosure-79 for _Block_copy, which comes from the Block_layout structure in the block_private. h file.
Block_layout
It’s in the structureisa
, markflags
,invoke
The function,descriptor
Description, etc.
inclang
To obtain thecpp
You can see it in the fileblock
Source code source, fromBlock_private.h
, as shown in the figure below:
By comparison, it can also be found that the structure __block_impl defined by block in the CPP file is consistent with the structure of Block_layout in the source code, as shown in the following figure:
summary
: through assembly debugging, under the symbol breakpoint, finally trace back to the sourceblock
Comes from thelibsystem_blocks.dylib
, but it is not open source and can be used through thelibsystem_blocks.dylib
Disassemble or passlibclosure
To do source analysis instead of source engineering.
2. Assemble to see block capture variable changes before and after
A block captures an external variable, which is a stack block at compile time, and is copied to the heap area at run time, becoming a heap block.
Before the change
Let’s analyze when this memory change occurs, as shown in the following figure:
Through assembly debugging, read register, found that when calling objc_retainBlock, read register X0 here is the simulator is rax, analyze the block data state is still in the stack area, so continue to go down the process, see what changes are made after calling _Block_copy.
After the change
Moving on, when _Block_copy is called, the following changes:
When _Block_copy is called, the change changes from NSStackBlock to NSMallocBlock, and the address changes and is copied from stack to heap.
This verifies that a block captures an external variable, is a stack block at compile time, and is copied to the heap by _Block_copy at run time, becoming a heap block.
_Block_copy source code analysis
The source code of the block has been located above, so take a look at the source code
- Block_layout
truct Block_layout {
void * __ptrauth_objc_isa_pointer isa;
volatile int32_t flags; // contains ref count
int32_t reserved;
BlockInvokeFunction invoke;
struct Block_descriptor_1 *descriptor;
// imported variables
};
Copy the code
isa isa
To determine theblock
typeflags
Identification codereserved
Keep fieldinvoke
The delta function, which is thetaFuncPtr
descriptor
Related Additional information
- flags
- _Block_copy source code analysis
- right
flags
Which is reference counting to determine if it isBLOCK_NEEDS_FREE
It’s released. Go straight backaBlock
- Global or not
block
Is also a direct returnaBlock
- If it’s not global then it’s a stack
block
Or a pile ofblock
, but this is compile time and cannot be the heap areablock
If memory is opened at compile time, the compiler is too stressed. So the compiler marks it as a stack block, when the compiler knows you’ve caught an external variable, toThe runtime
To perform the associated memory clearing operation (malloc
), in progressmemmove
Copy a - For some other information, including
invoke
, signature (ptrauth_signed_block_descriptors
) Information is also packaged inresult
- The last
isa = _NSConcreteMallocBlock
Returns a heap of extentsblock
In the assembly view above, the before and after changes of captured variables are printed,lldb
The debugging information is displayedsignature
,invoke
,copy
,dispose
And so on. What are these?
NSMethodSignature signatureWithObjCTypes:”v8@?0″; NSMethodSignature signatureWithObjCTypes:”v8@?0″ The code?
This is Type Encodings, Type code. IOS provides a directive called @encode that can represent specific types as string encodings! This was introduced when we analyzed the structure of the class.
v
saidviod
, no return value8
Said the8
bytes@
Said parametersid self
?
Unknown type (for function Pointers)0
saidid
from0
On the start
This information can also be seen in the following figure:
On the console, you can print Po [NSMethodSignature signatureWithObjCTypes:”v8@?0″] to view signature information.
Remember that extra information about flags and Descriptor up there
#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
uintptr_t reserved;
uintptr_t size;
};
Copy the code
In Block_descriptor_1 reserved is reserved field, size is the size of the block.
If #define BLOCK_DESCRIPTOR_2 1, that is, BLOCK_DESCRIPTOR_2, then copy and dispose are printed at the console above.
#define BLOCK_DESCRIPTOR_2 1
struct Block_descriptor_2 {
// requires BLOCK_HAS_COPY_DISPOSE
BlockCopyFunction copy;
BlockDisposeFunction dispose;
};
Copy the code
Block_descriptor_3 is optional. The flag field is used to determine whether the block contains the Block_descriptor_3 attribute
#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {
// requires BLOCK_HAS_SIGNATURE
const char *signature;
const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};
Copy the code
- through
Block_descriptor
theget
The method can be found,Block_descriptor_2
Can be achieved byBlock_descriptor_1
Address translation method to obtain - To obtain
Block_descriptor_3
When the judgeBlock_descriptor_2
If yes, you do not need to add itBlock_descriptor_2
Address space of.
LLDB debugging verification, as follows
More content continues to be updated
🌹 if you like, give it a thumbs up 👍🌹
🌹 feel harvest, can come to a wave, collection + attention, comment + forward, so as not to find me next time 😁🌹
🌹 welcome everyone to leave a message exchange, criticism and correction, learn from each other 😁, improve themselves 🌹