use*_*812 0 assembly arm arm64
我需要将 32 位绝对地址放入 AArch64 上的寄存器中。(例如,MMIO 地址,与 PC 无关)。
在 ARM32 上,可以使用lower16&upper16将地址加载到寄存器中
movw r0, #:lower16:my_addr
movt r0, #:upper16:my_addr
Run Code Online (Sandbox Code Playgroud)
有没有办法通过使用在 AArch64 上做类似的事情movk?
如果代码重定位,我仍然想要相同的绝对地址,所以adr不合适。
ldr 从附近的文字池中可以使用,但我宁愿避免这种情况。
如果您的地址是汇编时间常数,而不是链接时间,则这非常容易。它只是一个整数,您可以手动拆分它。
我要求 gcc 和 clang 编译unsigned abs_addr() { return 0x12345678; }(Godbolt)
// gcc8.2 -O3
abs_addr():
mov w0, 0x5678 // low half
movk w0, 0x1234, lsl 16 // high half
ret
Run Code Online (Sandbox Code Playgroud)
(写入w0 隐式零扩展为 64-bitx0,与 x86-64 相同)。
或者,如果您的常量只是链接时常量,并且您需要.o在链接器中生成重定位以供链接器填写,则 GAS 手册在 AArch64 机器特定部分中记录了您可以做什么:
'MOVZ' 和 'MOVK' 指令的重定位可以通过在标签前加上
#:abs_g2:etc来生成。例如将 48 位绝对地址加载foo到x0:Run Code Online (Sandbox Code Playgroud)movz x0, #:abs_g2:foo // bits 32-47, overflow check movk x0, #:abs_g1_nc:foo // bits 16-31, no overflow check movk x0, #:abs_g0_nc:foo // bits 0-15, no overflow check
GAS 手册的示例不是最佳的;至少在某些 AArch64 CPU 上,从低到高的效率更高(见下文)。 对于 32 位常量,遵循 gcc 用于数字文字的相同模式。
movz x0, #:abs_g0_nc:foo // bits 0-15, no overflow check
movk x0, #:abs_g1:foo // bits 16-31, overflow check
Run Code Online (Sandbox Code Playgroud)
#:abs_g1:foo已知 will 的可能设置位在 16-31 范围内,因此汇编程序知道lsl 16在编码时使用 a movk。你不应该lsl 16在这里使用显式。
我选择x0而不是w0因为这就是 gcc 所做的unsigned long long。可能所有 CPU 的性能都相同,代码大小也相同。
.text
func:
// efficient
movz x0, #:abs_g0_nc:foo // bits 0-15, no overflow check
movk x0, #:abs_g1:foo // bits 16-31, overflow check
// inefficient but does assemble + link
// movz x1, #:abs_g1:foo // bits 16-31, overflow check
// movk x1, #:abs_g0_nc:foo // bits 0-15, no overflow check
.data
foo: .word 123 // .data will be in a different page than .text
Run Code Online (Sandbox Code Playgroud)
使用 GCC: aarch64-linux-gnu-gcc -nostdlib aarch-reloc.s来构建和链接(只是为了证明我们可以,如果你真的运行它就会崩溃),然后aarch64-linux-gnu-objdump -drwC a.out:
a.out: file format elf64-littleaarch64
Disassembly of section .text:
000000000040010c <func>:
40010c: d2802280 mov x0, #0x114 // #276
400110: f2a00820 movk x0, #0x41, lsl #16
Run Code Online (Sandbox Code Playgroud)
Clang 似乎在这里有一个错误,使其无法使用:它只组装#:abs_g1_nc:foo(不检查高半部分)和#:abs_g0:foo(检查低半部分的溢出)。这是向后的,并且在foo具有 32 位地址时会导致链接器错误(g0 溢出)。我在 x86-64 Arch Linux 上使用 clang 7.0.1 版。
$ clang -target aarch64 -c aarch-reloc.s
aarch-reloc.s:5:15: error: immediate must be an integer in range [0, 65535].
movz x0, #:abs_g0_nc:foo
^
Run Code Online (Sandbox Code Playgroud)
作为一种解决方法g1_nc而不是g1很好,您可以在没有溢出检查的情况下生活。但是你需要 g0_nc,除非你有一个可以禁用检查的链接器。(或者,也许某些 clang 安装带有与 clang 发出的重定位错误兼容的链接器?)我正在使用 GNU ld (GNU Binutils) 2.31.1 和 GNU gold (GNU Binutils 2.31.1) 1.16 进行测试
$ aarch64-linux-gnu-ld.bfd aarch-reloc.o
aarch64-linux-gnu-ld.bfd: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
aarch64-linux-gnu-ld.bfd: aarch-reloc.o: in function `func':
(.text+0x0): relocation truncated to fit: R_AARCH64_MOVW_UABS_G0 against `.data'
$ aarch64-linux-gnu-ld.gold aarch-reloc.o
aarch-reloc.o(.text+0x0): error: relocation overflow in R_AARCH64_MOVW_UABS_G0
Run Code Online (Sandbox Code Playgroud)
movz= move-zero将 16 位立即数放入左移 0、16、32 或 48(并清除其余位)的寄存器中。 你总是想用 a 开始一个这样的序列movz,然后movk是其余的位。( movk= move-keep。将 16 位立即数移入寄存器,保持其他位不变。)
mov是一种可以选择 的伪指令movz,但我刚刚用 GNU binutils 和 clang 进行了测试,并且您需要一个显式的movz(不是mov),直接像#:abs_g0:foo. 显然movz,与数字文字不同,汇编器不会推断它需要那里。
对于窄立即数,例如0xFF000,在两个对齐的 16 位值块中具有非零位,mov w0, #0x18000将选择 的位掩码立即形式mov,这实际上是ORR-immediate 与零寄存器的别名。AArch64 bitmask-immediates 使用强大的编码方案来处理位范围的重复模式。(因此,例如and x0, x1, 0x5555555555555555(仅保留偶数位)可以在单个 32 位宽指令中编码,非常适合位黑客。)
还有movn(move not) 翻转位。这对于负值很有用,允许您将所有高位设置为1。根据AArch64 重定位前缀,它甚至还有一个重定位。
movz low16; movk high16按此顺序4.14 快速文字生成
Cortex-A57 r1p0 及更高版本支持针对 32 位和 64 位代码的优化文字生成
Run Code Online (Sandbox Code Playgroud)MOV wX, #bottom_16_bits MOVK wX, #top_16_bits, lsl #16[和其他例子]
...如果这些序列中的任何一个在程序代码中按所述顺序出现,则这两条指令可以比它们在程序代码中不按顺序出现时以更低的延迟和更高的带宽执行,从而使 32 位文字成为可能在一个周期内生成, 64 位文字将在两个周期内生成。
序列包括movz low16+movk high16到 x 或 w 寄存器,按顺序。(也背靠背movk设置高32,再次低,高的顺序。)根据手册,两个指令都必须使用w,或者都必须使用x寄存器。
如果没有特殊支持,则movk必须等待movz结果准备好作为 ALU 操作的输入来替换该 16 位块。大概在管道中的某个时刻,这 2 条指令合并为一个 32 位立即数 movz 或 movk,从而删除了依赖链。
| 归档时间: |
|
| 查看次数: |
1294 次 |
| 最近记录: |