thank you for accessing my question. I'm now using STM32F439ZI microcontroller to see how pc works.
Please look at the assembly code below.
int p1, *p2;
p2 = (int *)0x30000008;
__asm volatile("LDR %0, [%1]": "=r"(p1):"r"(p2));
The list file of this code is:
int p1, *p2;
p2 = (int *)0x30000008;
80001f2: 4b03 ldr r3, [pc, #12] ; (8000200 <main+0x14>)
80001f4: 607b str r3, [r7, #4]
__asm volatile("LDR %0, [%1]": "=r"(p1):"r"(p2));
80001f6: 687b ldr r3, [r7, #4]
80001f8: 681b ldr r3, [r3, #0]
80001fa: 603b str r3, [r7, #0]
for(;;);
80001fc: e7fe b.n 80001fc <main+0x10>
80001fe: bf00 nop
8000200: 30000008 .word 0x30000008
I found that in arm cortex-m4 architecture, pc always stores the address of current instruction, not next like x86 or two instructions(because arm cortex-m4 adopts thumb instruction set, and so according to the question, in thumb instruction set, pc always points to the current instruction + 4bytes, which is equivalent to 2 instructions in thumb instruction set) ahead as described here.
Why does the ARM PC register point to the instruction after the next one to be executed?
However, my observation is the pc points to the exact current instruction, not plus 4 bytes.
Is it really true that the pc points to the current instruction + 4 bytes? It is opposed to my observation.
Also, as described in the list file, it seems that the immediate value "0x30000008" is stored at 0x8000200. However, at 0x80001f2, it loads the value of pc + 12 bytes to r3, and if you do simple arithmetic, it is not 0x8000200, but 0x8000fe. According to this, it is reasonable to think that pc is 0x80001f4, when the current instruction is 0x80001f2, because 0x80001f4 + 12 = 0x8000200.
Here I'm faced with some contradictory possibilities that the pc stores the address of the current instruction, or next, or two instructions ahead.
Which one is actually true? My observation is indeed the current instruction though.
And is the memory mapping always like this? I mean the compiler always decides a kind of "base address" (In this example, it is the address pc stores at 0x80001f2), and allocates each instructions based on that base address? The constants (I hard-coded 0x30000008 so of course it is a constant) are always stored in somewhere abound the bottom? Finally when the compiler tells to you where the a specific constant is, it always does in a relative way like the address is base + 12 bytes, instead of telling the absolute address directly?
It would be great if you could give me some insight. Below is the actual disassembly that the microcontroller executes