ARM64汇编06 - 基本整型运算指令

ADD (immediate)

将 Xn 与 imm 相加,结果赋值给 Xd,imm 是无符号数,范围为 0 - 4095。

shift 是对 imm 进行移位,shift 为 0 的时候,表示左移 0 位,即不变。shift 为 1 的时候,表示左移12 位:

由于 imm 有效位只有 12 位,所以无法表示 0x1234 之类的数,但是可以表示 0x123。且有左移操作,所以也可以表示 0x123000 之类的数。

那么,add指令的立即数,可以描述负数么,也是可以的,但是就有点奇怪了,这本是减法指令做的事情:

可以看到,与整数指令相比,只是  op 位发生了变化:

00 8c 04 91
00 8c 04 d1

9 -> 1001
d -> 1101

所以,我们也可以猜测, sub 指令与 add 的指令的区别只在  op 位:

这样,我们只需要学习 add 指令,sub指令是对应的。

ADD (shifted register)

将 Xn 与 Xm 相加,结果放到 Xd 里面。

shift 是移位的方式:

移动的位数由 imm6 决定。

例子一:

00 00 01 8B                   ADD             X0, X0, X1

汇编指令展开:

8B 01 00 00 ->
10001011 00000001 00000000 00000000 ->
1 0 0 01011 00 0 00001 000000 00000 00000

Xd 是 0, Xm 是1 ,Xn 是0,shift 是 0,imm6 是 0。

例子二:

20 FC 02 8B                   ADD             X0, X1, X2,LSL#63

这个指令表示在相加前,需要将 X2 的值逻辑左移63 位。 imm6 是 6 位,刚刚好表示 0 ~ 63 的移位。

汇编指令展开:

8B 02 FC 20 ->
10001011 00000010 11111100 00100000 ->
1 0 0 01011 00 0 00010 111111 00001 00000

Xd 是 0,Xn 是 1,Xm 是 2,shift 是 0,imm6 是 0x3F(63)。

ADD (extended register)

这个指令稍微要复杂一点,它根据 option 的类型,来决定如何对 Xm 寄存器做扩展。

option 有8种取值类型,每种都有不同的意思,有遇到可去查资料了解。

举个简单的例子:

add w0, w1, w2,sxtw#2

SXTW/SXTH/SXTB:Sign-extend single-word / half-word / byte。

将 w2 寄存器按”单字“做符号位扩展。后面的 #2,只有在 LSL 模式下才有用,所以可以忽略,猜测一般编译器不会生成这种指令,应该会是  add w0, w1, w2,sxtw 这样的。

ADD还有加S的指令,表示会影响标志位,就不介绍了。

ADR

adr指令根据PC的偏移地址计算目标地址。偏移地址是一个21位(immhi:immlo)的有符号数,加上当前的PC地址得到目标地址。adr可以获取当前PC地址±1MB范围内的地址。

看一个例子,ADR X0, 4 生成汇编指令如下:

.text:0000000000000878 20 00 00 10                   ADR             X0, loc_87C             ; Keypatch modified this from:
.text:0000000000000878                                                                       ;   MOV W1, W19
.text:0000000000000878
.text:000000000000087C
.text:000000000000087C                               loc_87C                                 ; DATA XREF: main+44↑o
.text:000000000000087C E2 03 14 2A                   MOV             W2, W20

ADR 就是将标号 loc_87C 的地址赋值给 X0 寄存器。

在 IDA 中,我们可能会经常看到一个伪指令:

00 00 00 90 00 60 23 91       ADRL            X0, aADBD

该指令用于获取基于PC相对偏移+/- 4 GB内的符号地址,毕竟有时候可能 1M 不够用。

ADRP

ADRP 在 plt 表中会经常看到。

.plt:0000000000000760                               ; int rand(void)
.plt:0000000000000760                               .rand                                   ; CODE XREF: main+2C↓p
.plt:0000000000000760 10 00 00 B0                   ADRP            X16, #rand_ptr@PAGE
.plt:0000000000000764 11 DA 47 F9                   LDR             X17, [X16,#rand_ptr@PAGEOFF]
.plt:0000000000000768 10 C2 3E 91                   ADD             X16, X16, #rand_ptr@PAGEOFF
.plt:000000000000076C 20 02 1F D6                   BR              X17

首先adrp将一个21位有符号立即数左移12位,得到一个33位的有符号数(最高位为符号位),接着将PC地址的低12位清零,这样就得到了当前PC地址所在页的地址,然后将当前PC地址所在页的地址加上33位的有符号数,就得到了目标页地址,最后将目标页地址写入通用寄存器。

在 ida 中,就是将 rand_ptr@PAGE 的值赋值给 X16,rand_ptr@PAGE 的值已经做过地址对齐了。

SUB 系列

这个与ADD是一样的,就一个 op 位不一样。

SUB 也有 S 后缀,而且带 S 后缀的话,就等同于 CMP 指令。

AND

按位与,将第二个操作数与立即数按位与的结果放到第一个操作数里面。

说起来很简单,但是实际上它支持的 mask 是有限的,而生成 mask 的规则相当的难懂。

立即数的描述由3部分构成。

有篇文章,有兴趣的去研究:

https://dinfuehr.github.io/blog/encoding-of-immediate-values-on-aarch64/

AND 也可以加 S 后缀,等同于 TST 指令。

BIC (shifted register)

格式:

BIC <Xd>, <Xn>, <Xm>{, <shift> #<amount>}

BIC 其实与 AND 的作用是一样的,只不过,它会将 Xm 的值按位取反,取反后再与 Xn 做 and 操作,将结果放到 Xd 中。

那为啥有了 and 指令,还需要 bic 指令呢?是因为 and 指令支持的 mask 有限,所以 bic 相当于是一个扩展。

BIC 也支持 S 后缀。

ORR

与AND差不多,不过是按位或。

EOR

与AND差不多,异或。

移位指令

LSL:逻辑左移

40 00 41 D3                   LSL             X0, X2, #0x3F

11010011 01000001 00000000 01000000 ->
1 10 100110 1 000001 000000 00010 00000

注意,imms 不用关心,LSL是UBFM 指令的一种特殊形式,UBFM会用到imms。

在例子中,immr 的值算出来是 1,是因为最终计算的时候还需要使用#(-<shift> MOD 64) 这个表达式来计算,所以算出来的值是 63。

LSR:逻辑右移

ASR:算数右移

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值