I read a couple of articles including question here in SO Why does the ARM PC register point to the instruction after the next one to be executed?, that pc register value is
The PC offset is always 4 bytes in Thumb state. The reason being that it's two instruction fetches ahead, and a Thumb instruction fetch is (conceptually) always a halfword - hence why 32-bit encodings still have the funny byte order of two little-endian halfwords, rather than one little-endian word.
The one "32-bit" encoding in the original Thumb instruction set, bl
, had the operation of each halfword defined separately as "prefix" and "suffix" instructions, the neat trick being that whilst executing the first part, the return address is taken directly from the PC, since at that stage it's pointing to the instruction after the second part. By the time Thumb-2 technology came along and made 32-bit encodings a formal thing (including bl
retroactively), the PC offset had borne no relation to the actual microarchitecture for several generations*, so changing its defined behaviour to be variable dependent on the instruction stream would have had virtually no benefit and introduced massive compatibility problems.
To further complicate matters, when the PC is used as a base register for addressing operations (i.e. adr
/ldr
/str
/etc.) it is always the word-aligned value that is used, even in Thumb state. So, whilst executing a load instruction at 0x159a, the PC register will read as 0x159e, but the base address of ldr...[pc]
is Align(0x159e, 4)
, i.e. 0x159c. Since PC-relative addressing is normally written by specifying a label rather than calculating offsets manually, this detail can be easy to miss.
* In terms of ARM's own designs, ARM7 was the last microarchitecture based around the original 3-stage pipeline.