Assembly 使用GAS从标签加载单个字节到arm64中的寄存器
我想使用Assembly 使用GAS从标签加载单个字节到arm64中的寄存器,assembly,arm64,gnu-assembler,Assembly,Arm64,Gnu Assembler,我想使用ldrb指令将单个字节从内存加载到寄存器中。但是,如果第二个操作数是一个标签,这似乎是不可能的。完整的最小可重复性注释示例: // GNU Assembly, aarch64 Linux .data .equ SYS_EXIT, 93 .equ SUCCESS, 0 CHAR: .byte 1 .text .global _start _start: // none of these work, but why? // ldrb w19, CHAR
ldrb
指令将单个字节从内存加载到寄存器中。但是,如果第二个操作数是一个标签,这似乎是不可能的。完整的最小可重复性注释示例:
// GNU Assembly, aarch64 Linux
.data
.equ SYS_EXIT, 93
.equ SUCCESS, 0
CHAR:
.byte 1
.text
.global _start
_start:
// none of these work, but why?
// ldrb w19, CHAR // invalid addressing mode at operand 2
// ldrb w19, =CHAR // invalid addressing mode at operand 2
// ldrb w19, [CHAR] // 64-bit integer or SP register expected at operand 2
// ldr w19, CHAR // loads 4 bytes instead of 1 byte
// I have to do this but it's verbose and clunky
ldr x20, =CHAR
ldrb w19, [x20]
// is there any way to coalesce the above 2 instructions into 1?
mov x8, SYS_EXIT
mov x0, SUCCESS
svc 0
理想情况下,我希望编写ldrb,
,例如ldrbw19,CHAR
,并让它像我预期的那样从CHAR
的内存地址加载一个字节,而不是抛出汇编程序错误
这些都不管用,但为什么
因为采用PC相对文字的加载指令只有ldr
和ldrsw
:
如Siguza所说,CPU根本没有任何此类指令,请参见中的表C3-16。
LDRB
支持的唯一寻址模式是寄存器基址+寄存器或立即偏移,如您在《体系结构参考手册》(任何汇编程序员的必读)中所见。汇编程序拒绝汇编不存在的指令是完全正确的
因此,你不能在一个单一的指令中实现你想要的;你需要两个。然而,这两条指令可能比您选择的更有效。标准的习语似乎是:
adrp x19, CHAR
ldrb w19, [x19, #:lo12:CHAR]
这里,adrp
将加载x19
,地址的前52位为CHAR
;指令编码CHAR
所在页面相对于当前指令页面的偏移量(该偏移量由链接器或加载器计算和填充),以便生成位置无关的代码。然后在寻址模式下通过偏移量添加地址的低12位(限制为12位);此偏移量在链接时已知,因为加载时重新定位仅以页面或更多页面为单位。请注意,我们可以使用与加载目标相同的寄存器进行地址计算;我们不需要第二个
与您的方法相比,这避免了使用文字池的需要,节省了内存的额外负载和池中8字节的空间
如果你仍然觉得它太“冗长”,你可以将它包装在宏中。这不是汇编程序的错误,显然
LDRB
没有PC相对偏移量。