It's widely known that dynamic link libraries aren't allowed in iOS apps, they may only link to dynamic system libraries. But I do run into some pretty confusing crashes with the 3rd frame from the top of the stack being dyld_stub_binder.
It's tough to find some solid information, but I'm guessing that dyld_stub_binder actually performs late linking of a dynamic system library.
I tend to run into crashes where the exception is EXC_BREAKPOINT UNKNOWN and the crash always seems to occur in the context of dyld_stub_binder.
The implementation of dyld_stub_binder is on the apple open source website. I don't quite understand the assembly, but perhaps someone who does could interpret why this error happens or whether or not it's something that is out of the application's direct control. The assembly code may not be useful though, as I'm talking about the iOS (arm) implementation and this code is i386 and x86_64.
EDIT: An interesting piece of information is that I think I started seeing this crash during efforts for porting to arm64. Is it possible that a runtime exception like this is due to some kind of misalignment?
Best How To :
First, plenty of information can be found in J Levin's "Mac OS X and iOS Internals" (Wiley, 2012), and specifically , an article on said book's website (http://newosxbook.com/articles/DYLD.html).
As you've stated, the asm for the ARM case is not available, but it's fairly straightforward to figure out since you can decompile fairly easily. What dyld_stub_binder does (on all architectures) is to handle the lazy symbols in a binary. For example, consider the following:
$ cat a.c
void main(int argc, char **argv)
$ 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
100007f74 STR X0, [ X31, #3] ; *((254) + 0x0) = ???
100007f78 ADD x31, x29, #0x0 ; ..R31 = R29 (0x1f) + 0x0 = 0x1d
100007f7c LDP X29, X30, [X31],#16
see that printf up there? 0x100007f84? Let's see what that is (The built-in otool can't decompile that part, but jtool can:)
100007f88 LDR X16, #34 ; R16 = *(100008010) = 0x100007fa8
100007f8c BR X16
So you just to 0x100007fa8. Once again applying jtool:
$ jtool -d 0x100007fa8 a
Disassembling from file offset 0x7fa8, Address 0x100007fa8
100007fa8 LDR X16, #2
100007fac B 0x100007f90
And now we have 0x100007f90, which is ...
100007f90 ADR x17, 120 ; ->R17 = 0x100008008
100007f98 STP X16, X17, [X31,#-16]!
100007fa0 LDR X16, #24 ; R16 = *(100008000) dyld_stub_binder
100007fa4 BR X16
Now, go back to that 0x...8010 which gets loaded - that will be the address of printf(), but it is only bound after the first "hit" or access. You can verify that with dyldinfo, or jtool -lazy_bind:
$ jtool -lazy_bind a
segment section address type addend dylib symbol
__DATA __la_symbol_ptr 0x100008010 ... 0 libSystem.B.dylib _printf
Meaning, on first access, the stub_binder finds the address of printf in lib system, and embeds it there.
If the symbol cannot be bound, you get an exception. Though that can be for oh-so-many-reasons. You might want to add the crash log here. If it's a breakpoint, that's a voluntary crash by dyld which usually occurs when symbol was not found. If a debugger (lldb) is attached, it will break there and then. Else - with no debugger - it crashes.