在解码 arm64 时丢失“add x1, sp, x2, lsl #1”

问题描述 投票:0回答:2

add x1, sp, x2, lsl #1
指令应该是“添加(移位寄存器)”,但我在使用 SP 和 XZR 时区分编码时遇到问题。我对结果感到惊讶。

这是“ADD(移位寄存器)”的编码:

31:1, 30:0, 29:0, 28:0, 27:1, 26:0, 25:1, 24:1, 23..22:shift, 21:0, 20..16:Rm, 15..10:imm6, 9..5:Rn, 4..0:Rd 

如果我组装

add x1, xzr, x2, lsl #1
,它匹配上面的编码。只是要说明重要的一点:

E1 07 02 8B     add x1, xzr, x2, lsl #1

bit 21 = 0; 
shift = 0 (lsl); 
imm6 = 1  

但是如果我组装

add x1, sp, x2, lsl #1
,编码会有奇怪的变化。变化是:

E1 67 22 8B     add x1, sp, x2, lsl #1

bit 21 = 1; 
shift = 0;
imm6 = 011001  (lsl 25)

所以,我猜第 21 位表示 SP 而不是 XZR。但为什么 imm6 = 25?那是“lsl 25”!

我是不是看错了指令编码?

assembly arm64 instruction-set instruction-encoding
2个回答
1
投票

如果您在操作数中使用

SP
,则编码的指令从“ADD(移位寄存器)”(§ C6.2.5)更改为“ADD(扩展寄存器)”(§ C6.2.3)。这是必要的,因为只有后者支持在其第一个或第二个操作数中使用
SP
WSP

我在使用 SP 和 XZR 时区分编码有问题。

说明书上说使用了两者中的哪一个。如果使用

SP
,该字段将显示类似
<Xn|SP>
的内容,文本将显示“通用寄存器或堆栈指针”。当使用
XZR
时,该字段显示类似
<Xn>
的内容,文本仅显示“通用寄存器”。你需要知道你正在解码哪条指令才能知道是解码
XZR
还是
SP
。请注意,有时会有多个指令共享相同的助记符。例如,
ADD
助记符由这些共享(忽略可用于同一指令的不同操作数大小):

ADD <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}
ADD <Xd|SP>, <Xn|SP>, #imm{, <shift>}
ADD <Xd>, <Xn>, <Xm>{, <shift> #<amount>}
ADD <V><d>, <V><n>, <V><m>

0
投票

您正确地确定该指令是 ARM64 中的“Add(移位寄存器)”。然而,混淆是由于汇编程序在涉及堆栈指针 (SP) 时使用不同的编码,这不是很明显。

指令

add x1, sp, x2, lsl #1
实际上是使用“Add(扩展寄存器)”编码进行编码的。

Add (extended register) 的编码如下:

31:1, 30:0, 29:0, 28:0, 27:1, 26:1, 25:1, 24:1, 23..22:option, 21:1, 20..16:Rm, 15..13:S, 12..10:type, 9..5:Rn, 4..0:Rd

组装

add x1, sp, x2, lsl #1
时,您会得到:

E1 67 22 8B     add x1, sp, x2, lsl #1

让我们分解一下重要的部分:

  • bit 21 = 1;
  • option = 0;
  • S = 001 (which is the shift amount);
  • type = 001 (which corresponds to LSL).

这个编码变化的原因是因为堆栈指针(SP)被用作基址寄存器。当涉及 SP 时,汇编程序更喜欢“添加(扩展寄存器)”编码,以避免堆栈指针的特殊属性出现潜在问题。

您正在查看“添加(移位寄存器)”情况下的正确指令编码,但是当涉及堆栈指针时,汇编程序改为使用“添加(扩展寄存器)”编码。在这种情况下,移位量的编码不同,这就是为什么您会看到 imm6 = 25.

© www.soinside.com 2019 - 2024. All rights reserved.