Reputation: 8105
so I know questions for ldr/str on arm are countless. Perhaps this is another twist (not probable) or I'm just missing something (more probable.)
So this is bare metal and I want to load/store some variable in memory. And because I insist I want to give it a name. Naively I could write:
.section .bss
var: .word 0
.section .text
str r0, var
(having a custom linker script which puts .bss in ram and .text in flash)
Of cause this doesn't work because instructions are 32bit and only have place for some smaller immediate. And the instructions I'm talking about live in flash which is 0x8000000+x and the variable is to be stored in memory which is somewhere in the 0x20000000+y.
Manually I know quite some ways to solve this:
varaddr: .word 0x2001234; ldr r1, [pc,#varaddr]; str r0, [r1]
)ldr r1, #0x20000000; str r0, [r1,#varoffset]
)mov r1, #0x2000000; add r1, #offset / orr / movw / movt something
)Every of these variants work but neither of these variants let me use the label which I really want to use.
So what am I missing here. Is my idea for the linker script and labels bogus? Is there some assembler feature I didn't see? Something completely different?
Upvotes: 2
Views: 655
Reputation: 92966
One way you could use symbolic names for variables in static storage is to define a structure for your variables. This allows you to load the base address of your structure into a register and then access structure members using symbolic names relative to the base address. For example, you could do:
.struct 0 @ start a new structure
foo: .skip 4 @ length of foo
bar: .skip 4 @ length of bar
baz: .skip 4 @ length of baz
len: @ total length of the structure
.section .bss @ switch to the BSS (uninitialised data) section
.balign 4 @ align to 4 bytes
variables:
.space len @ reserve space for your variables
.section .text @ switch to the text (code) section
...
ldr r0, =variables @ load r0 with the base address of your variables
ldr r1, [r0+#foo] @ access foo
str r2, [r0+#bar] @ access bar
ldr r3, [r0+#baz] @ access baz
This is pretty much the closest you can get to symbolic names for variables in static storage. If the variables are on the stack, you can use a similar approach using the frame pointer (or stack pointer) as the base address. The operand to .struct
is the base address of the structure for which you can chose any value you like.
As for movw
and movt
. These offer a tiny performance advantage on some microarchitectures over ldr ..., =...
as they do not require data fetches to the text section. This makes no difference on armv7-m targets as far as I know; also, movw
and movt
consume two extra bytes versus ldr
with an =
operand. I thus recommend you to stick with ldr
and an =
operand. The usage of movw
and movt
is like this:
movw r0, :lower16:foo @ load lower 16 bit of foo's address into r0
movt r0, :upper16:foo @ or higher 16 bit of foo's address into r0
These two have to be issued in this specific order as movw
clears the upper 16 bit. The prefixes :lower16:
and :upper16:
select appropriate relocation types referring to just the lower and upper 16 bit of the symbol's address. You can make a macro to make this easier to type:
.macro addr reg, sym
movw \reg, :lower16:\sym
movt \reg, :upper16:\sym
.endm
This allows you to write
addr r0, foo
to generate the aforementioned movw
and movt
pair.
Upvotes: 2