I am trying to learn ARM by debugging a simple piece of ARM assembly.
.global start, stack_top
start:
ldr sp, =stack_top
bl main
b .
The linker script looks like below:
ENTRY(start)
SECTIONS
{
. = 0x10000;
.text : {*(.text)}
.data : {*(.data)}
.bss : {*(.bss)}
. = ALIGN(8);
. = . +0x1000;
stack_top = .;
}
I run this on qemu arm emulator. The binary is loaded at 0x10000
. So I put a breakpoint there. As soon as the bp is hit. I checked the pc
register. It's value is 0x10000
. Then I disassemble the instruction at 0x10000
.
I see a strange comment ; 0x1000c <start+12>
. What does it mean? Where does it come from?
Breakpoint 1, 0x00010000 in start ()
(gdb) i r pc
pc 0x10000 0x10000 <start>
(gdb) x /i 0x10000
=> 0x10000 <start>: ldr sp, [pc, #4] ; 0x1000c <start+12> <========= HERE
(gdb) x /i 0x10004
0x10004 <start+4>: bl 0x102b0 <main>
Then I continued to debug:
I want to see the effect of the ldr sp, [pc, #4]
at 0x10000
on the sp
register. So I debug as below.
From the above disassembly, I expected the value of sp
to be [pc + 4]
, which should be the content located at 0x10000 + 4 = 0x10004
. But the sp
turns out to be 0x11520
.
(gdb) i r sp
sp 0x0 0x0
(gdb) si
0x00010004 in start ()
(gdb) x /i $pc
=> 0x10004 <start+4>: bl 0x102b0 <main>
(gdb) i r sp
sp 0x11520 0x11520 <=================== HERE
(gdb) x /x &stack_top
0x11520: 0x00000000
So the 0x11520 value does come from the linker script symbol stack_top
. But how is it related to the ldr sp, [pc,#4]
instruction at 0x10000
?
ADD 1 - 9:29 AM 12/20/2019
Many thanks for the detailed answer by @old_timer.
I was reading the book Embedded and Real-Time Operating Systems by K. C. Wang. I learned about the pipeline thing from this book. Quoted as below:
So, if the pipeline thing is no longer relevant today. What reason makes the pc
value 2 ahead of the currently executed instruction?
I just found below thread addressing this issue:
Why does the ARM PC register point to the instruction after the next one to be executed?
Basically, it just another case that people keep making mistakes/flaws/pitfalls for themselves as they advance the technologies.
So back to this question:
- In my assembly, it is pc-relative addressing being used.
- ARM's PC pointer is 2 ahead of the currently executed instruction. (And deal with that!)