This is ARM RISC code, and the preferred programming mode for ARM is relative -- don't use absolute addresses, always use "IP+/-offset". Here, the called address was out of range for a direct call or jump, and the compiler used the nearest he could find. It adds an extra jump (or more than 1!) but it's position-independent. (*)
The compiler cannot construct a jump to the target address with a simple instruction, because you cannot immediately load every possible 2^32 number with RISC assembly.
If the routine
objc_msgSend
returns of its own, then this is equivalent tocall objc_msgSend; return
-- only shorter. Both forms do a single 'return', from the point of view of the current function.
(*) You can see in the disassembly screenshot (?? why not text?) that R12 gets loaded with the difference between the target and the current address. This difference is calculated by the compiler; it does not appear as a subtraction in the original binary, that's IDA's work. Then the difference is added to the current address -- whatever this is! The immediate value objc_msgSend - 0x1AE030
uses a small enough amount of bits to be loaded into R12 in a single instruction (an ARM RISC 'feature' you ought to be familiar with).
In case you are wondering about the j__label
syntax: that's just IDA, telling you this is a direct jump to a known label. Presumably, if your code is long enough, you might find the distance to this label is too big again, and so you might find j__j__objc_msgSend
.