Ignoring specific optimisations, the general solution is to have a "stack" in memory, and to push the old link-register value onto the stack before making another call. Arbitrary depth calls can then be made until memory is exhausted. Example code might be:myfunc PUSH {LR}; store old return address onto the stack BL myfunc; call myfunc again / another procedure POP {LR} ; restore old return address from stack BX LR ; return from myfunchths.
myfunc PUSH {LR}; store old return address onto the stack BL myfunc; call myfunc again / another procedure POP {LR} ; restore old return address from stack BX LR ; return from myfunc
myfunc PUSH {LR} ; store old return address onto the stack BL myfunc ; call myfunc again / another procedure POP {LR} ; restore old return address from stack BX LR ; return from myfunc
For exception handling, the hardware automatically pushes the link-register, along with over relevant state, onto the stack before it starts executing the interrupt handler code.