I'm using an ST32F401RE (ARM Cortex -M4 32-bit RISC) and was curious about the following.
Normally instructions on a 32 bit ARM can be 2 byte or 4 byte long. I accidentally jumped in-between a 2 byte instruction and the Microprocessor instantly went into an infinite Error Handler loop afterwards.
I later tested this and jumped on purpose in-between a 4 byte and 2 byte instruction and the Microprocessor would always go into the Error Handler.
I used the following c code to jump into Memory Adresses.
void (*foo)(void) = (void (*)())0x80002e8;
foo( ) ;
The Adresses for functions and instructions are from the Disassembly. The Compiler used the following assembler instruction after storing the adress in r3.
blx r3
Question: How exactly can the Microprocessor tell that it didn't start at the beginning of an instruction but actually started in-between one?
Especially in case of the 16 bit thumb instructions which are already pretty cramped.
I have multiple guesses but want to know what exactly is going on.
void (*foo)(void) = (void (*)())0x80002e8; foo ();
this will always crash on a Cortex-M, as the address is even, indicating that the target instruction set is ARM (A32), which the Cortex-M don't support; but theblx
instruction (x
= exchange) requests the switch to ARM. You have to set the lowest bit in the address to indicate a jump to a Thumb instruction, or use thebl
instruction (without exchange). - Erlkoenigorr.w r3, r3, #1
line. - negatic__asm__ volatile ("blx %[fun]" : : [fun]"r"(0x80002e9) : "memory");
so you can directly control how the call/jump works. The address can be any C expression that yields a 32bit value. - Erlkoenig