This is the 30th day of my participation in the August Challenge

Assembles and analyzes block processes

In the last article, we analyzed the underlying structure of blocks. In the next article, we will analyze the execution flow of blocks.

Let’s create a new iOS project and write the following code:

Create a breakpoint at the block and run the project to open the assembly screen:

In assembly code, we locate the objc_retainBlock symbol; We add the symbolic breakpoint objc_retainBlock and continue with the code:

Next, _Block_copy is called, and the symbolic breakpoint _Block_copy is added to execute the code down:

_Block_copy comes from libsystem_blocks. Dylib. The same call can be found in objc source code:

After _Block_copy is located, we can’t go any further because libsystem_blocks is not open source; But you can find an implementation of _Block_copy in libclosure’s source code:

Struct Block_layout *aBlock; struct Block_layout *aBlock; , its structure is as follows:

  • I have one of these structuresisaMember variable of, (pointing toStack blockorHeap block)
  • flagsIdentification code, which can store some data information;
  • invokeIs to call a function;
  • descriptorRelevant description information (such as whether there is a destructor, etc.)

At this point, we print the data in the register:

  • x0Is the message receiver, which is a__NSGlobalBlock__Because at present ourblockNo external variables are captured;

Next we modify the block code as follows:

To continue executing the code to the _Block_copy symbol breakpoint, let’s print out the x0 register data:

  • Because at this timeblockExternal variables are captured, so it is now a__NSStackBlock__That is aStack block; But based on our previous analysis,blockExternal variables are captured and areStrong referenceIt should be oneHeap blockThat’s right. Why is this placeStack blockInconsistent??

But it should be noted that at this point in our program breakpoint process, _Block_copy has not finished execution!

_Block_copy = x0; _Block_copy = x0;

  • _Block_copyWhen a method starts execution, and after executionreturnWhen,x0The register address has changed and is changed from__NSStackBlock__Turned out to be__NSMallocBlock__;
  • _Block_copyMethod takes aStack blockTurned out to beHeap block;

Now that we’ve analyzed the block changes from the assembly point of view, let’s examine them from the source code.

Source code analysis block process

The source code for _Block_copy is as follows:

Resolution:

  • (aBlock->flags & BLOCK_NEEDS_FREE)ifblockIs marked as released, so directreturn;
  • (aBlock->flags & BLOCK_IS_GLOBAL)ifblockIdentified as global, so directreturn;
  • size_t size = Block_size(aBlock);To obtainblockThe size of the;
  • struct Block_layout *result = (struct Block_layout *)malloc(size)Open up memory space according to size;
  • memmove(result, aBlock, size)Copy aBlock to result;
  • result->isa = _NSConcreteMallocBlockwillblockRelabel asHeap block;

Only stack blocks can be generated at compile time, because there is no alloc or memory at compile time, so only stack blocks can be marked, and then stack blocks can be re-marked as heap blocks at run time.

When we look at the console print, we see that in addition to the above print, we also print the signature: “v8@? 0” and invoke, copy, dispose; So what are they?

  • signatureIs our currentblockThe signature;

We can view the signature information in the following way:

  • parsing

    • number of arguments = 1: pass the1The parameters;
    • is special struct return? NO: has no return value;
    • argument 0:: the parameters from0# position start;
    • flags {isObject, isBlock}: is ablock, is also aobjectThat’s oneblockObject of type;
  • Invoke is a pointer to the caller of a function;

So what do copy and dispose do to blocks? We’ll continue next time at……