问题描述
如何编写将标签引用的地址放入寄存器的指令?
How do I write an instruction which will have the address a label is referencing put into a register?
推荐答案
有四种方法,三种在 Sourceware 的 Gnu 汇编器手册.我猜标签是这样的,
There are four ways, three are documented at Sourceware's Gnu Assembler manual. I guess the label is something like,
target:
.long 0xfeadbeef
adr r0,target
adrl r0,target
ldr r0,=target
sub r0,pc,#(.+8-target)
前两个非常相似,生成sub r0,pc,#offset
.3 将 long 放入 literal pool 并通过 ldr r0,[pc,#offset2]
加载它,或者它可以使用 mov
如果汇编器发现它可以(通常是对齐的标签,如 0x8000).最后一个版本是手动计算的.
The first two are very similar and generate sub r0,pc,#offset
. The 3 puts a long in a literal pool and loads this via ldr r0,[pc,#offset2]
or it may use a mov
if the assembler finds it can (usually an aligned label, like at 0x8000). The last version is to manually calculated it.
adr
和 adrl
的区别在于直接操作数.它们以 2 的倍数旋转 8 位.因此,如果地址很远,您可能需要执行两条指令,这通常比 3 ldr
变体更快,后者通过 数据缓存或内存.
The difference between adr
and adrl
comes from immediate operands. They are 8bits rotated by a multiple of two. So if the address is far, you may need to perform two instructions, which will usually be faster than the 3 ldr
variant which get a full 32-bits via the data cache or memory.
另请参阅:汇编器中的重定位
Thumb2 添加了 movw
和 movt
的组合.例如,
Thumb2 adds the combination movw
and movt
. For example,
label:
; data
...
movw r0, :lower16:label - .
movt r0, :upper16:label - .
这会将偏移量放在 r0
中.它对 PC 相对值没那么有用,但对绝对值或直接加载常量很有用.
This will put the offset in r0
. It is not as useful for PC relative but useful for absolutes or direct loads of constants.
参见:关于常量的 ARM 博客
这篇关于将标签地址获取到 ARM 上的寄存器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!