I was examining a vector table for the ARM Cortex A9 and stumbled accross two types of instructions:
B _boot
and
LDR PC, _boot
Can someone explain to me the difference in using B or LDR? Both code should do the same but apparently there must be a difference. Has it something to do with the link register?
Thanks for your time!
ldr reg, symbol
loads data from memory at that address, into the register. Loading into PC is a memory-indirect jump.
It will only assemble and link if _boot
is near enough for a PC-relative addressing mode to reach it, but that's likely if both are in the .text
section.
b symbol
sets PC = the address of the symbol. It's direct relative jump.
The link register is no involved in either case because you use b
not bl
or blx
.
ldr pc, _boot
Another way to do what ldr pc, _boot
does:
ldr r0, =_boot @ "global variable" address into register
ldr r0, [r0] @ load 4 bytes from that symbol address
br r0 @ and set PC = that load result
Assuming your _boot:
label is in front of some code, rather than a .word another_symbol
, this is not what you want. You'd be loading some bytes of machine code and using it as an address. (Setting PC to somewhere probably invalid.)
But if you do have _boot: .word foobar
or something, then it is what you want.
b _boot
Or the equivalent of b _boot
in terms of ldr
would be to load the address from memory into PC. That would mean you'd need a word in memory holding that address, instead of just the immediate relative displacement in the b
encoding.
But ARM assemblers have a pseudo-instruction to do that:
ldr pc, =_boot
will load that label address into PC, using a PC-relative addressing mode to load from a nearby literal pool. Or instead of into PC directly, you could set up for a br
.
ldr r0, =_boot @ symbol address into register
br r0 @ jump to that symbol
This is not exactly equivalent: it's not position-independent because it's using absolute addresses, not just a relative branch.