I could not find an answer to this question. Can you tell me when the ARM architecture switches from arm mode to thumb mode ? Explain all the ways in which the switching works.
-
Why do you need to know? – Carl Norum Nov 30 '10 at 00:27
-
6Is this homework? Also, in the 2 lines you wrote, there are about 15 spelling & grammatical errors. If you are expecting folks here to "explain in detail", at least put forth a little effort. – Dan Nov 30 '10 at 02:21
-
1It could have been a homework question. But an interesting question nonetheless. – viv Aug 15 '17 at 06:45
1 Answers
The answers are in the ARM ARM (ARM Architectural Reference Manual). Look at BX both in the ARM instructions and Thumb instructions, for example. There are more instructions in case this is a homework question.
Also look at the pseudo code for what happens when an exception occurs:
R14_ = return link SPSR_ = CPSR CPSR[4:0] = exception mode number CPSR[5] = 0 if == Reset or FIQ then CPSR[6] = 1 CPSR[7] = 1 if != UNDEF or SWI then CPSR[8] = 1 CPSR[9] = CP15_reg1_EEbit PC = exception vector address
The comments for the pseudo code above (in the ARM ARM) describe another answer to your question.
Now what is not obvious, and possibly misleading in the BX and other instruction descriptions is bx rm does not always switch states. The thumb BX description says "branches between ARM code and Thumb code". As if thumb using it would take you to arm code all the time. The pseudo code paints a slightly better picture though, the lsbit of the address in the register tells you if you are branching to thumb or arm code. The PC pseudo code in the thumb description is misleading though. Thumb instructions are 16 bits and the pc moves forward 16 bits at a time 0x00, 0x02, 0x04, etc. In arm mode the instructions are 32 bits and the pc goes 0x00, 0x04, 0x08, etc. (look at the branch instructions ARM the branch is signed_immed<<2, 0,4,8, etc. thumb branch is signed_immed<<1, 0,2,4,6, etc)
Basically if you have a mixed mode program you want to use BX instead of B, in particular when returning bx lr instead of mov pc,lr. So both thumb and arm functions would use bx lr to return. All four cases are covered, arm calling arm, arm calling thumb, thumb calling arm and thumb calling thumb.
So look for instructions that affect the T bit of the cpsr and/or affect the program counter in a way that causes the program counter to branch somewhere. Also be careful to limit yourself to the specific family/core you are interested in (when reading the ARM ARM), armv4t, armv6, armv6, etc. You probably want to get the TRM (Technical Reference Manual) for the specific core you are using as well. The ARM ARM is very generic and as the number of cores increases over time the specific differences are not clear in the ARM ARM. You need the TRM.
I have many revs of the ARM ARM and all of them contain bugs/errors. Intentional or not I don't know, so some hacking is always required to find out how the core you are using really works.
Edit in 2018
I am not going to make a list for every core, etc, etc. That is what the arm documentation is for.
But, again the answer lies in the architectural reference manuals available at ARM's website. You may have to sacrifice an email address, but well worth it.
The key word you are looking for is interwork
or interworking. The old/original arm arm is now called the armv5 architectural reference manual
you look for a T Flag
and see what instructions change that flag. For the armv7-m and maybe armv8-m ARM you can look for interworking support or interworking address. And it shows a list of instructions that affect the PC but do or do not support interworking.
For the armv7-a/r, I am still looking for interworking branch, so far I don't see a section. Look for changing between Thumb state
and ARM state
and there is a section that shows a list of instructions to get from thumb state to arm state and a list to get from arm state to thumb state.
ARMv6(not -M) is straddles the armv5 and armv7 ARMs, but each instruction/encoding shows the architecture that supports it, so you may have to walk through each of the interworking branch instructions and see if they have armv6 support (armv4 and armv5 are also shown). The armv7 manuals are not the whole story though there is a blx
thumb encoding in armv4T/armv5T that is not part of armv6-m/armv7-m what used to be that blx
encoding is now part of the thumb2 extensions.
The primary instruction supported across all of this is BX
, other instructions vary based on architecture as to whether or not you can use them to switch states. If you are writing an emulator, good luck, if you are programming you can try to tune for architecture, but when it doubt just use bx
. Note there is an undocumented bug in the arm11-mpcore (not the older arm11s like the one in the Raspberry Pi) that does a prefetch on data after a pop pc
or ldr pc
if that data resembles a branch instruction.
My recommendation is not to use those instructions on an arm11 mpcore, but to instead do an armv4t style pop or load to a volatile register and bx with that. pop {r3}; bx r3
rather than pop {pc}
. The side effects are hard to see, a read cycle can happen against a peripheral that acts on a read, reading from the data register on a uart and losing a character for example. Just FYI, took us a while to find and confirm this.
-
2I could have written that answer better, I made it too hard to read. Anyway, short answer: look for instructions that affect the T bit in the CPSR. – old_timer Dec 01 '10 at 20:19
-
An update to this answer would have been lovely. Perhaps showing with real arm assembly how this is done? – not2qubit Oct 30 '18 at 03:58
-
@not2qubit the question was too vague and a number of new cores and architectures have come along since. Should have been closed and deleted a long time ago. I should really delete this answer. The ARM documentation for each core has a section and a small paragraph or even one statement that lists the instructions that have this ability to switch modes, so depending on your core you have to look at that document and then those instructions and choose one. they are pretty easy to use and figure out as the program counter is a or the destination. – old_timer Oct 30 '18 at 17:41
-
I guess nothing prevents you from answering twice. I would ask the same question if it was not already here. I need a list of ways that this is done for each core. I'm working on a RE project where where the exact ARM core is unknown, but where mode switching is part of some code obfuscation scheme. – not2qubit Oct 31 '18 at 15:19
-
I would then go back to the armv4t solution in that case and pop the lr either into lr if possible or r0-r3 and then bx. for returns for general branching into the unknown just use bx. IMO. If/when you look at the docs starting with armv4t which is in the armv5 manual because there was only one ARM ARM up to that point (that covered all of the architectures armv4 and armv5, during armv6 to armv7 they started splitting up the manuals) you can see how few instructions will work, and then up to armv7 where many will work, it should likely boil down to just go with the lowest numbered – old_timer Oct 31 '18 at 18:02
-
architecture you support, armv4 I think pop pc doesnt work (relying on my memory check the docs yourself) but somewhere after that it does so if you dont need to go all the way back to the ARM7TDMI but instead say support ARM11 or newer or only the Cortex-somethings then you can pick from those common instructions. BX has always been on the list and I assume always will – old_timer Oct 31 '18 at 18:04