• 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 位发生了变化:

    1. 00 8c 04 91
    2. 00 8c 04 d1
    3. 9 -> 1001
    4. d -> 1101

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

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

    ADD (shifted register)

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

    shift 是移位的方式:

    移动的位数由 imm6 决定。

    例子一:

    00 00 01 8B                   ADD             X0, X0, X1
    

    汇编指令展开:

    1. 8B 01 00 00 ->
    2. 10001011 00000001 00000000 00000000 ->
    3. 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 的移位。

    汇编指令展开:

    1. 8B 02 FC 20 ->
    2. 10001011 00000010 11111100 00100000 ->
    3. 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 生成汇编指令如下:

    1. .text:0000000000000878 20 00 00 10 ADR X0, loc_87C ; Keypatch modified this from:
    2. .text:0000000000000878 ; MOV W1, W19
    3. .text:0000000000000878
    4. .text:000000000000087C
    5. .text:000000000000087C loc_87C ; DATA XREF: main+44↑o
    6. .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 表中会经常看到。

    1. .plt:0000000000000760 ; int rand(void)
    2. .plt:0000000000000760 .rand ; CODE XREF: main+2C↓p
    3. .plt:0000000000000760 10 00 00 B0 ADRP X16, #rand_ptr@PAGE
    4. .plt:0000000000000764 11 DA 47 F9 LDR X17, [X16,#rand_ptr@PAGEOFF]
    5. .plt:0000000000000768 10 C2 3E 91 ADD X16, X16, #rand_ptr@PAGEOFF
    6. .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:逻辑左移

    1. 40 00 41 D3 LSL X0, X2, #0x3F
    2. 11010011 01000001 00000000 01000000 ->
    3. 1 10 100110 1 000001 000000 00010 00000

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

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

    LSR:逻辑右移

    ASR:算数右移

  • 相关阅读:
    【LeetCode】不同的子序列 [H](动态规划)
    gitlab+docker+harbor+k8s+jenkins部署简单应用
    CRM系统开发
    Hive经典面试题(三)——间隔连续问题
    蓝桥杯打卡Day13天
    机器学习基础篇(4)滤波器
    结合Docker从零搭建服务器Java开发环境
    ③. GPT错误:python控制台运行pip list列出安装库,列出:pip install 库1 库2库3...,方便一次性安装错误
    基于springboot的校园店铺系统
    vue3 吸顶搜索框在页面滚动时改变样式
  • 原文地址:https://blog.csdn.net/a5right/article/details/136649192