The Arm architecture includes two important branch and link instructions – BL and BLX. These instructions allow you to branch or jump to a different part of your program, while also storing the return address so you can later return back to where you came from. In this article, we will demystify these instructions and explain how they work in detail.
What is a Branch Instruction?
A branch instruction allows you to alter the flow of your program by jumping to a new instruction address. For example, a BEQ (Branch if Equal) instruction will jump to a new address if a condition is met (in this case, if two registers are equal). A B (Branch) instruction will always jump to the new address unconditionally.
Branch instructions are essential in programming as they allow implementing loops, if-else statements, and other complex control flows. Without branches, a program would simply execute linearly instruction by instruction.
What is a Link Instruction?
A link instruction works together with a branch to store away the return address before jumping. This return address is usually stored in a designated register such as LR (Link Register).
This allows you to later return to the original point where you branched from. The link instruction “links” the branch source and destination addresses together, allowing bi-directional flow.
ARM BL Instruction
The BL instruction stands for Branch with Link. It performs two key functions:
- Branches or jumps to a new instruction address
- Stores the return address in the LR (Link Register)
This allows you to execute a subroutine or function call. The BL jumps to the subroutine code, while storing the next instruction’s address in LR. The subroutine can later execute a BX LR to return to the caller.
Here is the basic flow when using a BL instruction:
- BL jumps to and executes the subroutine code
- Inside the subroutine, LR holds the return address
- BX LR returns to the calling code
BL Assembly Syntax
Here is the syntax for the BL instruction: BL target_address
For example: BL 0x1234
This branches to address 0x1234, storing the next instruction’s address in LR.
How BL Works
Here is a step-by-step explanation of what happens when executing a BL instruction:
- PC (Program Counter) contains the current instruction address
- BL encodes an offset to the target branch address
- The offset is added to the PC to calculate the target address
- PC is updated to this new target address, executing the branch
- The PC + 4 (next instruction) is stored in LR
So in summary, BL branches to a new address based on an encoded offset, and stores the next sequential address in the LR.
ARM BLX Instruction
BLX is very similar to BL, but with one key difference – it can switch between Arm and Thumb instruction sets.
Arm vs Thumb Instructions
Most Arm Cortex CPUs support two instruction sets:
- Arm – 32-bit instructions
- Thumb – 16-bit compressed instructions
Thumb code is more compact, reducing code size. Arm code executes faster.
BLX allows branching between these two instruction sets. For example, you can branch from Thumb code to a Arm subroutine, and back.
BLX Assembly Syntax
Here is the syntax for BLX: BLX target_address
This is identical to BL. The difference is BLX detects and handles switching instruction sets automatically.
How BLX Works
Here is how BLX works:
- If current instruction set is Thumb, switch to Arm
- Execute BL as normal (branch and link)
- If return address in LR is Thumb, switch back to Thumb
So BLX will swap instruction sets on branch and return automatically. The target address and return address determine which mode it should be in.
Using BL and BLX
Here are some examples of how to use the BL and BLX instructions:
Calling a Subroutine
BL subroutine ; Subroutine code SUB: … BX LR
BL branches to the subroutine label, storing return address in LR. BX LR returns.
Calling Thumb Code from Arm
BLX thumb_func ; Thumb function THUMB_FUNC: … BX LR
BLX switches to Thumb mode to execute the function, returning to Arm after.
Calling From Thumb to Arm and Back
BLX arm_func ; Arm function ARM_FUNC: … BX LR ; Return switches back to Thumb
This shows how seamlessly BLX handles switching instruction sets.
To summarize, BL and BLX are invaluable branch and link instructions in Arm:
- BL branches and stores return address in LR
- BLX does the same, handling switching between Arm/Thumb
- Used to call subroutines and functions
- Return with BX LR instruction
- Enable complex program control flows
So in summary, use BL/BLX to branch to subroutines and functions, returning with BX LR. BLX enables intermixing Arm and Thumb code.
Frequently Asked Questions
What is stored in the LR register after BL?
BL stores the address of the next instruction after the BL in the LR register. This is the return address that allows jumping back after the subroutine.
What happens if I forget to store LR before using it?
If you fail to store LR before branching again or overwriting it, you will lose the return address. This will lead to a crash or executing the wrong code after the subroutine finishes.
How much faster is Arm vs Thumb code?
As a rough estimate, Arm code is about 65% faster in terms of instructions per clock cycle. But Thumb code size is about 65% smaller. There are also some more complex trade-offs.
What if I BLX to an invalid address?
If you branch to an invalid address, the processor will fault and execution will halt. Make sure to branch to valid code within the executable memory space.
Can I nest BL calls infinitely?
Yes, you can nest BL subroutine calls as deeply as you wish. Each call will store its own return address in LR independently. Just make sure to save LR before overwriting it if nesting calls more than 1 level deep.
Here is some example Arm assembly code using BL and BLX to call subroutines and functions: MAIN: BL sum_squares ; Call Arm subroutine BLX power_func ; Call Thumb function BX LR ; Return ; Arm subroutine SUM_SQUARES: … BX LR ; Thumb function POWER_FUNC: … BX LR
This shows branching between Arm and Thumb code using BLX. BL handles branching within the same instruction set. BX LR returns to the caller.
BL and BLX are key instructions that enable calling subroutines and functions in Arm assembly. They allow changing code flow as needed, while storing return addresses to jump back. BLX provides the additional ability to switch between Arm and Thumb instruction sets automatically.
Using these branch and link instructions is crucial for structured assembly programming. They underpin function calls, conditional evaluation, loops, and more. Understanding BL and BLX will enable you to produce robust and modular Arm code.