[英]armv7-m bare metal ldr/str symbolic memory
所以我知道 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]
)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 ..., =...
提供了微小的性能優勢ldr ..., =...
因為它們不需要將數據提取到文本部分。 據我所知,這對 armv7-m 目標沒有影響; 此外,與帶有=
操作數的ldr
相比, movw
和movt
消耗了兩個額外的字節。 因此,我建議您堅持使用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
對。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.