Session 406 of WWDC 2016 is great! It explains clearly how the iOS application is settled in memory before running, with ASLR and code-signing. The key point is the indirect pointers in __DATA avoid patching the __TEXT, which is required by ASLR but impossible because of code-signing.
There is this one point confusing me, __TEXT still needs to encode address pointing to __DATA segment, though __DATA page address is randomised now.
The answer is quite simple indeed: the offset between __TEXT and __DATA is not changing between runs, the offset is encoded in __TEXT.
In 64bit Mac OS X, it implements as:
movl 0xae(%rip), %edi
iOS ARMv7 generates:
0000bf9c f240037c movw r3, #0x7c 0000bfa0 f2c00300 movt r3, #0x0 0000bfa4 447b add r3, pc ;$pc(0xbfa8) + 0x7c -> global_var in __DATA
iOS ARMv8 (64) generates:
0000000100007f2c adrp x8, 1 ; 0x100007000 + 4k*1 0000000100007f30 add x8, x8, #64 ; +0x40 -> 0x100008040 ;-> global_var in __DATA * adrp xd label mask out lower 12bits of pc then add label<<12 to generate an address.