OC method

Now that we have seen the basic instructions for assembly in the previous articles, let’s look at how OC assembly is implemented.

Objc_msgSend (id self, SEL _cmd) is called by default with two arguments. Let’s look at a simple assembly implementation of the OC method:

The assembly code for the main function looks like this:

ZZZ`main:
    0x102e798b0 <+0>:   sub    sp, sp, #0x30             ; =0x30 
    0x102e798b4 <+4>:   stp    x29, x30, [sp, #0x20]
    0x102e798b8 <+8>:   add    x29, sp, #0x20            ; =0x20 
    0x102e798bc <+12>:  stur   wzr, [x29, #-0x4]
    0x102e798c0 <+16>:  stur   w0, [x29, #-0x8]
    0x102e798c4 <+20>:  str    x1, [sp, #0x10]
    0x102e798c8 <+24>:  adrp   x8, 4
    0x102e798cc <+28>:  add    x8, x8, #0xc40            ; =0xc40 
->  0x102e798d0 <+32>:  ldr    x0, [x8]
    0x102e798d4 <+36>:  adrp   x8, 4
    0x102e798d8 <+40>:  add    x8, x8, #0xc00            ; =0xc00 
    0x102e798dc <+44>:  ldr    x1, [x8]
    0x102e798e0 <+48>:  bl     0x102e79c84               ; symbol stub for: objc_msgSend
    0x102e798e4 <+52>:  mov    x29, x29
    0x102e798e8 <+56>:  bl     0x102e79cc0               ; symbol stub for: objc_retainAutoreleasedReturnValue
    0x102e798ec <+60>:  add    x8, sp, #0x8              ; =0x8 
    0x102e798f0 <+64>:  str    x0, [sp, #0x8]
    0x102e798f4 <+68>:  stur   wzr, [x29, #-0x4]
    0x102e798f8 <+72>:  mov    x0, x8
    0x102e798fc <+76>:  mov    x8, #0x0
    0x102e79900 <+80>:  mov    x1, x8
    0x102e79904 <+84>:  bl     0x102e79cd8               ; symbol stub for: objc_storeStrong
    0x102e79908 <+88>:  ldur   w0, [x29, #-0x4]
    0x102e7990c <+92>:  ldp    x29, x30, [sp, #0x20]
    0x102e79910 <+96>:  add    sp, sp, #0x30             ; =0x30 
    0x102e79914 <+100>: ret  
Copy the code

So in this code, we see objc_msgSend, we hit a breakpoint here, we read x0 and x1, what are they

Through LLDB debugging, we can see that x0 is Person and x1 is instance SEL, which verifies that the OC method is objc_msgSend at the bottom.

When we see a piece of assembly code, we go to objc_msgSend and read it to x0 and x1 to see which object or class method is being called.

objc_storeStrong

In line 5 from the bottom of the main function code, we see that the objc_storeStrong method is called. This method should only be called on objects that are modified by strong, because the p we define is local and is modified by strong by default

In the figure above, the LLDB reads the values in x0, which holds the pointer address of the p object, and x1=nil.

In the OC source, find objc_storeStrong and plug x0 and x1 into the function

objc_storeStrong(id *location, id obj) { id prev = *location; //prev = *location = p object, obj = nil if (obj == prev) {return; } objc_retain(obj); *location = obj; //p = nil objc_release(prev); //objc_release(p) }Copy the code

So by analysis, what we’re doing here is we’re pointing p to nil, freeing up the heap where the P object is. Since p is a local variable, the function is released when it completes execution.

Block

The underlying Block is also a structure, which is also an object. Most of the time we use blocks as arguments to implement result callbacks, so our main object of study will be the contents of the Block, invoke.

struct Block_layout {
    void *isa;
    volatile int32_t flags; // contains ref count
    int32_t reserved;
    BlockInvokeFunction invoke;
    struct Block_descriptor_1 *descriptor;
    // imported variables
};
Copy the code

Let’s look at a simple block:

We can see objc_retainBlock at line 10 of the assembly code, when we read the X0 register, we can see that this is a globalBlock, invoke at 0x1005C58C0. Further down, we can see that there is a jump instruction in line 17, read the jump address, Ei!! Invoke is the address of Invoke and tells us that it is the invoke block on line 74 of main. Click on it and see the assembly implementation of Invoke.

ZZZ`__main_block_invoke:
->  0x1005c58c0 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x1005c58c4 <+4>:  stp    x29, x30, [sp, #0x10]
    0x1005c58c8 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x1005c58cc <+12>: str    x0, [sp, #0x8]
    0x1005c58d0 <+16>: str    x0, [sp]
    0x1005c58d4 <+20>: adrp   x0, 3
    0x1005c58d8 <+24>: add    x0, x0, #0x2f8            ; =0x2f8 
    0x1005c58dc <+28>: bl     0x1005c5bf8               ; symbol stub for: NSLog
    0x1005c58e0 <+32>: ldp    x29, x30, [sp, #0x10]
    0x1005c58e4 <+36>: add    sp, sp, #0x20             ; =0x20 
    0x1005c58e8 <+40>: ret    
Copy the code