Why dyld_stub_binder crashes on iOS?

It is widely known that dynamic link libraries are not allowed in iOS apps, they can only link to dynamic system libraries. But I am running into some pretty convoluted 3rd frame crashes, from the top of the stack is dyld_stub_binder.

Hard information is hard to find, but my guess is that dyld_stub_binder is actually doing late linking of the dynamic system library.

I usually run into crashes where the exception is EXC_BREAKPOINT UNKNOWN and the crash always occurs in the context of dyld_stub_binder.

The dyld_stub_binder implementation is on Apple's open source website. I don't quite understand the assembly, but maybe someone who does this can understand why this error occurs or not, something that goes outside the application directly. The assembly code may not be very helpful as I am talking about the iOS implementation (arm) and this code is i386 and x86_64.

EDIT: The interesting piece of information is that I think I started seeing this crash during my arm64 porting efforts. Is it possible that a runtime exception like this is due to some kind of misalignment?


source to share

1 answer

As you said, asm is not available for the ARM case, but quite easy to understand as you can decompile quite easily. What dyld_stub_binder does (on all architectures) to handle lazy characters in binary. For example, consider the following:

   $ cat a.c
void main(int argc, char **argv)

    printf("%s", argv[1]);

$ gcc-iphone a.c -o a 
$ jtool -d a
Disassembling from file offset 0x7f44, Address 0x100007f44 
   100007f44    STP    X29, X30, [X31,#-16]!    
   100007f48    ADD    x29, x31, #0x0   ; ..R29 = R31 (0x0) + 0x0 = 0x1f 
   100007f4c    SUB    X31, X31, #32    
   100007f50    STUR   X0, X29, #-4     ; *((1) + 0x0) = ???
   100007f54    STR    X1, [ X31, #2]   ; *((2) + 0x0) = ???
   100007f58    LDR    X1, [X31, #0x10] ; R1 = *(10) = 0x100000cfeedfacf
   100007f5c    LDR    X1, [X1, #0x8]   ; R1 = *(100000cfeedfad7) = 0x100000cfeedfacf
   100007f60    ADD    x8, x31, #0x0    ; ..R8 = R31 (0x0) + 0x0 = 0x1f 
   100007f64    STR    X1, [ X8, #0]    ; *(0x0) = 0xfeedfacf
   100007f68    ADRP   x0, 0            ; ->R0 = 0x100007000 
   100007f6c    ADD    x0, x0, #0xfb4   ; ..R0 = R0 (0x100007000) + 0xfb4 = 0x100007fb4 "%s"
   100007f70    BL     _printf  ; 0x100007f84
; _printf("%s",arg..);

   100007f74    STR    X0, [ X31, #3]   ; *((254) + 0x0) = ???
   100007f78    ADD    x31, x29, #0x0   ; ..R31 = R29 (0x1f) + 0x0 = 0x1d 
   100007f7c    LDP    X29, X30, [X31],#16  
   100007f80    RET    


see printf in there? 0x100007f84? Let's see what it is (the built-in otool cannot decompile this part, but jtool can :)

   100007f84    NOP                     
   100007f88    LDR    X16, #34         ; R16 = *(100008010) = 0x100007fa8

   100007f8c    BR     X16   


So you're just down to 0x100007fa8. Using jtool again:

$ jtool -d 0x100007fa8 a
Disassembling from file offset 0x7fa8, Address 0x100007fa8 
   100007fa8    LDR    X16, #2          
   100007fac    B      0x100007f90


And now we have 0x100007f90, which ...

   100007f90    ADR    x17, 120         ; ->R17 = 0x100008008 
   100007f94    NOP                     
   100007f98    STP    X16, X17, [X31,#-16]!    
   100007f9c    NOP                     
   100007fa0    LDR    X16, #24         ; R16 = *(100008000) dyld_stub_binder
   100007fa4    BR     X16              


Now back to the fact that 0x ... 8010 is being loaded - this will be the address of printf (), but it is bound only after the first "hit" or access. You can check this with dyldinfo or jtool -lazy_bind:

$ jtool -lazy_bind a
bind information:
segment section          address        type    addend dylib            symbol
__DATA  __la_symbol_ptr  0x100008010    ...     0 libSystem.B.dylib    _printf


Meaning, on first access, stub_binder finds the printf address in the lib system and inserts it there.

If the symbol cannot be bound, you get an exception. Although this can be for many reasons. You might want to add a crash log. If it is a breakpoint, then a voluntary dyld crash, which usually occurs when a character is not found. If a debugger (lldb) is connected, it will break there and then. Else - no debugger - it will crash.



All Articles