【发布时间】:2020-06-22 20:26:45
【问题描述】:
所以我知道关于 ldr/str on arm 的问题数不胜数。也许这是另一个转折(不太可能)或者我只是遗漏了一些东西(更有可能)。
所以这是裸机,我想在内存中加载/存储一些变量。因为我坚持要给它起个名字。我可以天真地写:
.section .bss
var: .word 0
.section .text
str r0, var
(有一个自定义链接器脚本,将 .bss 放在 ram 中,将 .text 放在 flash 中)
这当然行不通,因为指令是 32 位的,并且只能用于一些较小的立即数。我正在谈论的指令存在于闪存中,即 0x8000000+x 并且变量将存储在内存中,该内存位于 0x20000000+y 的某个位置。
手动我知道很多方法可以解决这个问题:
- 将变量地址存储在常量中 (
varaddr: .word 0x2001234; ldr r1, [pc,#varaddr]; str r0, [r1]) - 在寄存器中加载 ram-base 并相对寻址 (
ldr r1, #0x20000000; str r0, [r1,#varoffset]) - 通过算术构造地址 (
mov r1, #0x2000000; add r1, #offset / orr / movw / movt something) - 当然还有更多
这些变体中的每一个都有效,但这些变体都不允许我使用我真正想要使用的标签。
那么我在这里错过了什么。我对链接器脚本和标签的想法是假的吗?是否有一些我没有看到的汇编程序功能?完全不同的东西?
【问题讨论】:
-
使用
ldr r1, =var获取地址,然后使用它。或者,用 C 语言编写相同的程序,看看编译器做了什么,然后做同样的事情。是的,当您实际修改变量时,您将无法使用标签名称。如果您想要一个符号名称,我建议为寄存器号制作一个宏。 -
ARMv7 可以使用
movw(宽立即数)+movk或类似的东西在寄存器中构造任意 32 位值(例如地址)。在针对某些 ARM CPU 进行优化时,编译器有时会使用它而不是来自附近常量池的 PC 相关负载。 -
@Peter:这就是我的第三个要点的意思。
-
@fuz:编译器完成了我在第一个要点中所做的工作。它将内存地址存储在闪存中并使用它。
ldr r1, =var一样。这是最好的吗? -
您可以做的一件事是将所有变量并排放置在一个结构中,并使用该结构的基地址加载一个寄存器。然后,您可以使用符号表示结构开头的偏移量,以符号方式访问所有变量。