ARM64汇编04 - 条件码

文章通过实例解析了如何在C语言代码中利用分支控制结构,以及在汇编层面使用CMP和CSEL指令实现条件判断。着重介绍了ARM64和x86中条件码的区别,特别是C标志位在不同操作下的行为异同。
摘要由CSDN通过智能技术生成

关于分支控制与条件码的作用可以去看 《CSAPP》的第 3.6 节,讲的非常清楚,建议看看,这里就不重复了。

我们直接使用一个例子来简单理解汇编是如何实现分支控制的:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    time_t t;
    srand((unsigned) time(&t));

    int a = rand();
    int b = rand();

    printf("a = %d, b = %d\n", a, b);

    if (a > b)
    {
        printf("a win!!!\n");
    }
    else if (a < b)
    {
        printf("b win!!!\n");
    }
    else
    {
        printf("both win!!!\n");
    }

    return 0;
}

编译后,使用 ida 打开,查看其核心逻辑:

1处的 w19 与 w20 储存着 a 与 b 的值,CMP 会对这两个值做比较。

CSEL 指令介绍:

CSEL <Xd>, <Xn>, <Xm>, <cond>

cond 是有一个表可以查的,我们后面会说。这个指令的意思是,如果 cond == true,Xd = Xn,否则 Xd = Xm。

2 处的 CSEL 指令的意思是如果 LT 的值是 true,那么 x8 = x9,否则 x8 = x8。x9 的值是 b win。结合源代码,可以猜测出  CMP 就是做了一个减法操作。

综合一下,当 w19 < w20,那么输出 x9(b win),否则输出 x8(both win)。

3 处的分析与 2 一样就不展开了,当 w19 > w20,那么输出 x0(a win)

通常,在有分支的位置,会出现 CMP 等指令,它会修改 ZNCV 这些 flags 的值,然后后面会跟一些需要根据 flags 值来决定分支走向的汇编代码,比如 CSEL。

我们编写的程序,肯定是有很多分支的。所以,cond 非常的重要。

Condition code

arm64 的条件码如下,与 arm32 有点区别,但是不大:

我们在上面的例子中看到的 LTGT 这里都是有对应的。

LT 表示有符号的小于,GT 表示有符号的大于。

LT 需要检查 N 与 V 的值,GT 需要检查 Z,N,V的值。

关于 ZCNV 这几个标志位的解释,不太好描述,先简单理解:

  • N:当操作结果为负数时,设置为1,否则为0。

  • Z:当操作结果为0时,设置为1,否则为0。

  • C:当操作结果发生进位或者减法结果无借位时,设置为1,否则设置为0。

  • V:当操作导致溢出时,设置为1,否则设置为0。

实际上,会有相当多的指令会更新这些 flag 的值,比如,一些运算指令等。但是运算指令想要更新 flag,还需要加 S 后缀。比如,ADDS指令。

有符号与无符号

从上面的条件码表中可知:

  • 有符号的大于为:GT(Greater than)

  • 有符号的小于为:LT(Less than)

  • 无符号的大于为:HI(higher)

  • 无符号的小于等于为:LS(lower or same)

由于助记符设计的有符号的小于使用的单词是 Less,无符号的小于采用的 lower,导致它们看起来会比较像。

在汇编中出现了 LT 与 LS 后缀,很难会一下子反应过来,这到底是有符号还是无符号。

x86 中的有符号与无符号区分的比较开,有符号使用greater/less,无符号使用 above/below。

LS后缀

由于 cond 后缀有一个 LS,表示 less or same。而 B 指令也可以接 cond 后缀,所以会出现 BLS 指令。

这很好理解,但是对初学者来说,有一个麻烦的地方,就是还有一个 BL 指令,我们还记得有些指令是可以加 S 后缀的。

所以当我们看到  BLS 指令的时候,它到底表示的是 B + LS ,还是 BL + S 呢?

如果你翻arm手册,就知道,BL 是没有 S 后缀的,也就是说它不设置 flag:

C标志位的奇怪表现

使用 ida 来简单观察一下C flag 的变化情况。

测试加法,0 + 1,单步后,查看 C 位变化:

发现 C 位无变化,很正常。

再测试一个减法,2 - 1

单步后,查看 C 位变化:

发现,C 位居然变成了 1,这个表现就与x86中是相反的,设计的很奇怪。

再测试一个 1 -2

单步后,查看 C 位变化:

C 位无变化,N位变成了 1,因为结果是 -1。

对于C位,需要注意到,在减法中,它与 x86 中的表现是相反的,与直觉也是相反的。

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值