为 arm64 生成代码时,为什么 gcc + clang 使用 adrp+add 而不是 adr 来寻址附近的变量?
When generating code for arm64, why do gcc + clang use adrp+add rather than adr for addressing nearby variables?
对于 arm64,可以使用 adr 指令将附近地址的文字加载到寄存器中。根据 ARM-V8 Architecture Reference Manual adr 指令:
ADR <Xd>, <label> Address of label at a PC-relative offset
可以引用 +/-1MB 以内的标签。有一个设置了 bit-31 的页面版本,adrp,用于构造更大的偏移量。
我不明白的是为什么 ARM64 的 gcc 8.2 nor clang 7.0 都不使用 adr 而不是 adrp 和 add 对附近的变量。优化级别不会改变这一点。
int write(int fd, const void *buf, int count);
void xyz(void)
{
write(2, "abc", 4);
}
xyz(): // @xyz()
adrp x1, .L.str
add x1, x1, :lo12:.L.str
orr w0, wzr, #0x2
orr w2, wzr, #0x4
b write(int, void const*, int)
.L.str:
.asciz "abc"
他们不能推断出这个字符串文字在 +/-1MB 以内吗?有编译器 attribute/switch 告诉他们这个吗?
GCC 将生成这样的代码 -mcmodel=tiny
:
.global xyz
.type xyz, %function
xyz:
.LFB0:
.cfi_startproc
mov w2, 4
adr x1, .LC0
mov w0, 2
b write
.cfi_endproc
.LFE0:
.size xyz, .-xyz
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "abc"
对于 arm64,可以使用 adr 指令将附近地址的文字加载到寄存器中。根据 ARM-V8 Architecture Reference Manual adr 指令:
ADR <Xd>, <label> Address of label at a PC-relative offset
可以引用 +/-1MB 以内的标签。有一个设置了 bit-31 的页面版本,adrp,用于构造更大的偏移量。
我不明白的是为什么 ARM64 的 gcc 8.2 nor clang 7.0 都不使用 adr 而不是 adrp 和 add 对附近的变量。优化级别不会改变这一点。
int write(int fd, const void *buf, int count);
void xyz(void)
{
write(2, "abc", 4);
}
xyz(): // @xyz()
adrp x1, .L.str
add x1, x1, :lo12:.L.str
orr w0, wzr, #0x2
orr w2, wzr, #0x4
b write(int, void const*, int)
.L.str:
.asciz "abc"
他们不能推断出这个字符串文字在 +/-1MB 以内吗?有编译器 attribute/switch 告诉他们这个吗?
GCC 将生成这样的代码 -mcmodel=tiny
:
.global xyz
.type xyz, %function
xyz:
.LFB0:
.cfi_startproc
mov w2, 4
adr x1, .LC0
mov w0, 2
b write
.cfi_endproc
.LFE0:
.size xyz, .-xyz
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "abc"