I'm analyzing some functions I see in Machos binaries and I see that whenever there's bl instruction to an objective-c stub function that resides in the __objc_stubs section and in that function there's eventually a call with br instruction to the _objc_msgSend symbol that resides in the _got section that will eventually get resolved when the libobjc.dylib will get loaded by the dyld, for example:

adrp x1, 0x24e000
ldr x1, [x1, #0x670] => some selector pointer
adrp x16, 0x1fc000
ldr x16, [x16, #0xd48] => _objc_msgSend stub location
br x16

Now I wonder why there isnt any ret instruction at the end of these stubs to return to the code flow of the original function that called this stub? Will the ret instruction just be present in the _objc_msgSend from libobjc.dylib and it will eventually call it by itself?

1 Answer 1


This is an example of optimizing a tail call - a call to another function which is done as the last statement of the current function. Because the LR (link register) has not been modified, the ret/blr of the destination function will directly return to the caller of the stub.

  • Can I ask what is a way to detect tail call compared to just a branch in a function? Is the presence of unconditional branch without any other flow paths in the function indicated a tail call 100%? Or are there edge cases where it's not true somehow? Maybe it can be identified by counting references to the branch target from other already identified functions and if it's more than 1 then we can conclude the branch target is a new function rather than just a label in some function?
    – Jorayen
    Commented Oct 28, 2023 at 17:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.