

Objc_msgSend(), instruction by instruction - coob
http://www.friday.com/bbum/2009/12/18/objc_msgsend-part-1-the-road-map/

======
0x0
Would be interesting to see an updated writeup with focus on iOS on ARM.

~~~
pmjordan
Here's the disassembly for objc_msgSend on ARMv6, iOS4.2.1 (sorry no ARMv7
devices on my desk at the moment). I'll try to annotate it:

    
    
      0x32d98f0c <objc_msgSend+0>:	teq	r0, #0	; 0x0
      0x32d98f10 <objc_msgSend+4>:	moveq	r1, #0	; 0x0
      0x32d98f14 <objc_msgSend+8>:	bxeq	lr
    

Tests if r0 (the receiver) is nil, and if so, sets r1 selector to 0x0 and
returns. I guess there's no nil handler on ARM. Simple function return values
are in registers r0-r3, so I guess r1 is set to 0 in case the caller is
expecting a long long.

If receiver is non-nil:

    
    
      0x32d98f18 <objc_msgSend+12>:	push	{r3, r4, r5, r6}
      0x32d98f1c <objc_msgSend+16>:	ldr	r4, [r0]
    

^ this loads the class pointer ( _isa_ ) into r4

This looks similar to the bit twiddling x86 cache lookup in the class; it's
somewhat harder to read than the x86 due to ARM's bit packing shortcuts[1]:

    
    
      0x32d98f20 <objc_msgSend+20>:	ldr	r5, [r4, #8]
      0x32d98f24 <objc_msgSend+24>:	ldr	r6, [r5]
      0x32d98f28 <objc_msgSend+28>:	add	r3, r5, #8	; 0x8
      0x32d98f2c <objc_msgSend+32>:	and	r5, r6, r1, lsr #2
      0x32d98f30 <objc_msgSend+36>:	ldr	r4, [r3, r5, lsl #2]
    

Check if the method is NULL, and if so, jump to the cache miss at the end:

    
    
      0x32d98f34 <objc_msgSend+40>:	teq	r4, #0	; 0x0
      0x32d98f38 <objc_msgSend+44>:	add	r5, r5, #1	; 0x1
      0x32d98f3c <objc_msgSend+48>:	beq	0x32d98f60 <objc_msgSend+84>
    

This would appear to be the part checking if this is the cache entry we're
looking for:

    
    
      0x32d98f40 <objc_msgSend+52>:	ldr	r12, [r4]
      0x32d98f44 <objc_msgSend+56>:	teq	r1, r12
      0x32d98f48 <objc_msgSend+60>:	and	r5, r5, r6
    

If it isn't, loop:

    
    
      0x32d98f4c <objc_msgSend+64>:	bne	0x32d98f30 <objc_msgSend+36>
    

If it is, restore the registers and do an indirect jump into the method we
found (I'm not sure what the teq r4,r4 is for):

    
    
      0x32d98f50 <objc_msgSend+68>:	ldr	r12, [r4, #8]
      0x32d98f54 <objc_msgSend+72>:	teq	r4, r4
      0x32d98f58 <objc_msgSend+76>:	pop	{r3, r4, r5, r6}
      0x32d98f5c <objc_msgSend+80>:	bx	r12
    
    

Tail call into the slow version with full lookup (after restoring the
clobbered registers and the stack pointer):

    
    
      0x32d98f60 <objc_msgSend+84>:	pop	{r3, r4, r5, r6}
      0x32d98f64 <objc_msgSend+88>:	b	0x32d98f68 <objc_msgSend_uncached>
    
    

[1] A lazy excuse of course. I just haven't read or written anywhere near as
much ARM assembly as x86.

~~~
0xced
The source code of the Objective-C runtime is actually open source. See
[http://opensource.apple.com/source/objc4/objc4-493.11/runtim...](http://opensource.apple.com/source/objc4/objc4-493.11/runtime/Messengers.subproj/objc-
msg-arm.s) for another commented version of objc_msgSend on ARM.

