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
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
_main:
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 :)
_printf:
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.
source to share