I can't seem to get my head around what bx lr
does and how it differs from bl (label)
. I know that bl (label)
stores the return address of that function in the link register but I don't know what bx lr
does.

- 4,543
- 5
- 22
- 49

- 711
- 2
- 10
- 20
2 Answers
It's almost always returning from a function, like ret
in some other ISAs like AArch64.
bx
stands for branch and exchange instruction set Which means that according to the lsb (least significant bit) of the address to branch to, the processor will treat the next instruction as ARM or as thumb.
As lr
usually holds the return address, it means that this is a return from a function, and if the lsb of lr
is 1, it will treat the code at that address as thumb, otherwise, it will treat it as ARM.

- 328,167
- 45
- 605
- 847

- 135,866
- 28
- 264
- 277
-
3Could you possibly simplify this explanation, my knowledge of ARM architecture isn't that advanced. – Thahleel al-Aleem Nov 23 '14 at 02:21
-
11@user2177940 Part 1: Mode Switch. An ARMv7 CPU operates in one of two modes (Called ARM or Thumb), that differ in the instruction encoding (chiefly in "complete" but large 4-byte instructions vs. "restricted" but small 2-byte instructions). Which mode to switch to next is determined **at call time with `bx/blx`** by whether the address to jump to is even or odd (this causes a switch to, respectively, ARM or Thumb mode). – Iwillnotexist Idonotexist Nov 23 '14 at 02:38
-
14@user2177940 Part 2: Calls and Call Returns. On ARMv7, the instruction `bl nameOfFunction` is what generally gets used to call a subroutine. The `bl` instruction saves into the link register (`lr`) the address of the next instruction atfer itself, and the current mode, then jumps to the subroutine requested. Naturally, when that subroutine wishes to return, it knows where to return to by jumping to the address in `lr`, and since `lr` also saves the mode of the calling function, that can be restored as well. The instruction that does this job is `bx`. – Iwillnotexist Idonotexist Nov 23 '14 at 02:54
-
5@IwillnotexistIdonotexist - I think it's better if you put your comments as an answer. – MByD Nov 23 '14 at 13:22
-
1What is the intention behind this specification? What is the relation between even/odd and ARM (A32) respectively Thumb (T32)? If I only want to return from a subroutine without changing the mode, should I better use ````MOV pc, lr````? – Niklas Peter Apr 25 '18 at 12:06
-
4I can answer my comment myself: "Note that the lowest bit is never actually used as part of the address as all instructions are either 4-byte aligned (as in Arm) or 2-byte aligned (as in Thumb)." (https://community.arm.com/processors/b/blog/posts/branch-and-call-sequences-explained) – Niklas Peter Apr 25 '18 at 12:19
-
Should you always do "bx lr" even if you're not switching from arm to thumb? Should you do "b lr" instead? – JobHunter69 Sep 15 '18 at 21:36
In a nutshell, some ARM processors can execute either ARM or Thumb instruction sets with a tradeoff between code density and performance. BX is a special form of the branch instruction capable of switching between the two1.
It does it by detecting the instruction set (ARM or Thumb) at the branch address. If it's different from the current one, it switches the processor over to it before branching to the address.
.global _main ; our main code is ARM
_main:
ADR r2, .ThumbProg + 1 ; r2 now points to Thumb code address
BX r2 ; BX detects its Thumb and switches
; processor state to execute it
; execute it.
There's nothing magical or complicated about detecting the instruction set at the destination address.
The ARM instruction set is word-aligned, meaning the least two significant bits 0, and 1 are ignored because they refer to the half-word and byte portion of the address. Likewise, the Thumb instruction set is halfword-aligned, meaning bit 0 is ignored because it refers to the byte portion of the address.
Since Bit 0 is ignored in both cases, it is exploited to easily determine whether code at an address contains ARM or Thumb code. The BX uses Bit 0 to:
- execute the branch address in the Thumb state if it's set to 1
- execute the branch address in the ARM state if it's set to 0
1 ARM uses the term exchanges in the name of the instruction to mean changing the execution state. Unfortunately, this creates confusion. The two instruction sets are not being exchanged any more than when a train switches from one set of tracks to another.

- 9,256
- 11
- 60
- 102