所以我知道关于arm的ldr / str问题不胜枚举。也许这是另一种转折(不太可能),或者我只是缺少了一些东西(更可能。)
所以这是裸机,我想在内存中加载/存储一些变量。而且因为我坚持要给它起个名字。我可以天真地写:
.section .bss
var: .word 0
.section .text
str r0, var
((具有一个自定义链接脚本,该脚本将.bss放在ram中,并将.text放在flash中)
原因这是行不通的,因为指令是32位的,并且只占一些较小的立即数。我正在谈论的指令实时存储在0x8000000 + x的Flash中,变量将存储在0x20000000 + y的内存中。
手动,我知道很多解决方法:
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
)构造地址所有这些变体都可以使用,但是这些变体中的任何一个都不能让我使用我真正想使用的标签。
所以我在这里想念什么。我对链接描述文件和标签的看法是否虚假?我有没有看到的一些汇编器功能?完全不同吗?
可以在静态存储中为变量使用符号名的一种方法是为变量定义结构。这使您可以将结构的基地址加载到寄存器中,然后使用相对于基地址的符号名称访问结构成员。例如,您可以这样做:
.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
这几乎是您在静态存储中最接近变量的符号名称的位置。如果变量在堆栈上,则可以使用类似的方法,将帧指针(或堆栈指针)用作基地址。 .struct
的操作数是该结构的基地址,您可以为其选择任意值。
关于movw
和movt
。与不需要ldr ..., =...
的某些微体系结构相比,它们在性能上有微小的优势,因为它们不需要将数据提取到文本部分。据我所知,这对armv7-m目标没有影响;同样,与movw
和movt
操作数相比,ldr
和=
消耗两个额外的字节。因此,我建议您坚持使用ldr
和=
操作数。 movw
和movt
的用法如下:
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
这两个必须按此特定顺序发出,因为movw
会清除高16位。前缀:lower16:
和:upper16:
选择适当的重定位类型,仅参考符号地址的低16位和高16位。您可以创建一个宏以使其更易于键入:
.macro addr reg, sym
movw \reg, :lower16:\sym
movt \reg, :upper16:\sym
.endm
这可以让您写
addr r0, foo
以生成前述的movw
和movt
对。