morpheus@Zephyr(~)$ jtool -dA __TEXT.__stub_helper ~/Documents/RE/ScreenShotr # note -dA, to disassebmle ARM, not Thumb
Disassembling from file offset 0x18d4, Address 0x28d4
28d4 e52dc004 PUSH IP ; STR IP, [ SP, #-4 ]! # PUSHes R12 onto the stack
28d8 e59fc010 LDR IP, [PC, 16] ; R12 = *(28f0) = 0x7f8 # Load
28dc e08fc00c ADD IP, PC, IP ; R12 = 0x30dc # Correct R12 for PC-relative addressing
28e0 e52dc004 PUSH IP ; STR IP, [ SP, #-4 ]! # PUSHes R12 (0x30dc) onto the stack
28e4 e59fc008 LDR IP, [PC, 8] ; R12 = *(28f4) = 0x7e8 # Load
28e8 e08fc00c ADD IP, PC, IP ; R12 = 0x30d8 # Correct R12 for PC-relative addressing
28ec e59cf000 LDR PC, [IP, 0] ; R15 = *(30d8) dyld_stub_binder # goto dyld_stub_binder
28f0 7f8 DCD 0x7f8 # Offset of 0x30dc, PC-relative
28f4 7e8 DCD 0x7e8 # Offset of dyld_stub_binder, PC-relative
---------------------------------------------
28f8 e59fc000 LDR IP, [PC, 0] ; R12 = *(2900) = 0x0 # Lazy binding opcode@0x0 (_IOSurfaceCreate)
28fc eafffff4 B 0xffffffd0 ; 0x28d4 # Jump to stub_handler
2900 0 DCD 0
---------------------------------------------
2904 e59fc000 LDR IP, [PC, 0] ; R12 = *(290c) = 0x17 # Lazy binding opcode@0x17 (_IOSurfaceGetBaseAddress)
2908 eafffff1 B 0xffffffc4 ; 0x28d4 # Jump to stub_handler
290c 17 DCD 0x17
---------------------------------------------
...
morpheus@Zephyr(~)$ jtool -opcodes ~/Documents/RE/ScreenShotr # Can also use dyldinfo -opcodes, same output
..
lazy binding opcodes:
0x0000 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000000)
0x0002 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(2)
0x0003 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _IOSurfaceCreate)
0x0015 BIND_OPCODE_DO_BIND()
0x0016 BIND_OPCODE_DONE
0x0017 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000004)
0x0019 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(2)
0x001A BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _IOSurfaceGetBaseAddress)
0x0034 BIND_OPCODE_DO_BIND()
0x0035 BIND_OPCODE_DONE
0x0036 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000008)
0x0038 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(2)
0x0039 BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _IOSurfaceLock)
0x0049 BIND_OPCODE_DO_BIND()
0x004A BIND_OPCODE_DONE
0x004B BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x0000000C)
0x004D BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(2)
0x004E BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x00, _IOSurfaceUnlock)
0x0060 BIND_OPCODE_DO_BIND()
dyld_stub_binder is exported by libSystem.B.dylib, though in actuality it is a re-export from /usr/lib/system/libdyld.dylib. Using Jtool again, we can see:morpheus@Zephyr(~)$ ARCH=armv7s jtool -dA dyld_stub_binder /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/usr/lib/system/libdyld.dylib
dyld_stub_binder:
# coming into this function, we have two arguments on the stack:
# *SP = Offset into bind information
# *(SP+4) = 0x30c4 - Address of image loader cache
10cc e92d408f PUSH {R0,R1,R2,R3,R7,LR} ; SP -= 24 # save registers
10d0 e28d7010 ADD R7, SP, #0x10 ; R7 = SP + 0x10 (point to previous R7)
10d4 e59d0018 LDR R0, [SP, 24] ; R0 = *(SP + 0x18) = *(Initial_SP)
10d8 e59d101c LDR R1, [SP, 28] ; R1 = *(SP + 0x1c) = *(Initial_SP + 4)
10dc fa0001ef BLX 0x7bc ; 0x18a0 __Z21_dyld_fast_stub_entryPvl
10e0 e1a0c000 MOV IP, R0 ;
; IP = dyld_fast_sub_entry (void *, long)
10e4 e8bd408f POP {R0,R1,R2,R3,R7,LR} # restore registers
10e8 e28dd008 ADD SP, SP, #0x8 ; SP = 0x8 # Clear stack
10ec e12fff1c BX IP # Jump to bound symbol
Jtool's disassembly is corroborated by DYLD's source, which surprisingly enough contains an #if __arm__ statement for iOS 5 which Apple has not removed. If you're following with x86_64 (e.g. with /bin/ls), the 0x100004040 from the lldb example is the trampoline to dyld_stub_binder. In other words, the code will look something like this when you break on 0x100004040:* thread #1: tid = 0x185f7, 0x0000000100004040 ls, queue = 'com.apple.main-thread, stop reason = breakpoint 1.1
frame #0: 0x0000000100004040 ls
# stack already contains the offset into the LINKEDIT bind information, which is different per symbol.
# When we get here, this is common code, and we further push the address of the cache:
-> 0x100004040: leaq 4073(%rip), %r11 ; (void *)0x0000000000000000
0x100004047: pushq %r11
0x100004049: jmpq *4057(%rip) ; (void *)0x00007fff8c80e878: dyld_stub_binder
0x10000404f: nop
Hopefully, this fills in the missing pieces, showing you not just what symbols are bound, but HOW they are bound. I hope to provide more information about LINKEDIT (specifically, the juicy parts of codesigning. You are always welcome to go online at the Book Forum and comment, ask questions, etc.