AS汇编器源码剖析-第1章-Arm操作码

来源:互联网 发布:深圳有名的公司 知乎 编辑:程序博客网 时间:2024/06/08 16:52

AS汇编器源码剖析-Arm操作码

 

 

Arm opcode定义

 

arm的全部指令定义在aarch64-tbl.h的aarch64_opcode_table,超过1000个。指令以struct aarch64_opcode的格式定义。以下代码是Add/subtract (with carry)部分的指令集定义。

 

structaarch64_opcodeaarch64_opcode_table[] =

{

  /* Add/subtract (with carry). */

  {"adc", 0x1a000000,0x7fe0fc00,addsub_carry, 0, CORE,OP3 (Rd, Rn, Rm), QL_I3SAMER,F_SF},

  {"adcs", 0x3a000000,0x7fe0fc00,addsub_carry, 0, CORE,OP3 (Rd, Rn, Rm), QL_I3SAMER,F_SF},

  {"sbc", 0x5a000000,0x7fe0fc00,addsub_carry, 0, CORE,OP3 (Rd, Rn, Rm), QL_I3SAMER,F_HAS_ALIAS |F_SF},

  {"ngc", 0x5a0003e0,0x7fe0ffe0,addsub_carry, 0, CORE,OP2 (Rd, Rm), QL_I2SAME,F_ALIAS |F_SF},

  {"sbcs", 0x7a000000,0x7fe0fc00,addsub_carry, 0, CORE,OP3 (Rd, Rn, Rm), QL_I3SAMER,F_HAS_ALIAS |F_SF},

  {"ngcs", 0x7a0003e0, 0x7fe0ffe0,addsub_carry, 0, CORE,OP2 (Rd, Rm),QL_I2SAME, F_ALIAS |F_SF},

…}

 

 

structaarch64_opcode 定义在aarch64.h

 

structaarch64_opcode

{

/* 助记符 */

constchar *name;

 

/* 操作码,不包含操作数 */

aarch64_insnopcode;

 

/*opcode mask.掩码相当于操作码中所有有效位都置1的值*/

aarch64_insnmask;

 

/* 指令集类别,参见armv8 reference manual C4小节对指令的分类 */

enumaarch64_insn_class iclass;

 

/*Enumerator identifier. */

enumaarch64_op op;

 

/* 提供这个指令的组件 */

constaarch64_feature_set *avariant;

 

/* 操作数列表*/

enumaarch64_opnd operands[AARCH64_MAX_OPND_NUM];

 

/*操作数的限定序列,用来检查操作数是否符合约束*/

aarch64_opnd_qualifier_seq_tqualifiers_list[AARCH64_MAX_QLF_SEQ_NUM];

 

/* 指令相关的flag */

uint32_tflags;

};

 

先分析adc指令,对照结构体定义,每个成员相关对应信息如下:

"adc",

助记符

0x1a000000

操作码

0x7fe0fc00

操作码掩码

addsub_carry,

指令所属类

0

opcode枚举

CORE

提供这种指令的组件

OP3 (Rd, Rn, Rm)

操作数编码数组

QL_I3SAMER,

操作数的限定序列

 

Adc指令定义

 

armv8 reference manual里的C4: A64Instruction Set encoding里,对指令集的编码进行的说明。Adc定义在C6.6.1,属于addsubtract(with carry)小节C4.5.3,信息如下:

 

ADC操作码opcode

0x1a000000

操作码

 

根据操作码的定义,有效部分不考虑操作数和其他部分,所以从bit21-30,bit10-15,都是属于这个class的有效bit。其他bit按照0来填充,所以操作码的21-30bit为0001 1010 000,bit10-15也是全0,就是0x1a000000。

     特别注意的是bit31,这一位表示的是32/64位的区别,但是不管这一位是0/1,都是adc指令。所以,在时间的汇编器实现里,是通过sfflag来控制设置bit31,而不是直接把bit31作为opcode。

 

ADC操作码掩码

0x7fe0fc00

操作码掩码

 

操作码掩码包括21-30bit,bit10-15,全部为1表示就是0x7fe0fc00。同opcode解释,sf不占掩码。

 

指令的类class

addsub_carry,

指令所属类

 

很明显,根据rfm定义就是addsub_carry,见C4.5.3定义。所有的分类都可以在C4里找到说明。在代码里定义如下,一共70类。

enum aarch64_insn_class

{

 addsub_carry,

  addsub_ext,

  addsub_imm,

 addsub_shift,

  asimdall,

  asimddiff,

  asimdelem,

  asimdext,

  asimdimm,

  asimdins,

  asimdmisc,

  asimdperm,

  asimdsame,

  asimdshf,

  asimdtbl,

  asisddiff,

  asisdelem,

  asisdlse,

  asisdlsep,

  asisdlso,

  asisdlsop,

  asisdmisc,

  asisdone,

  asisdpair,

  asisdsame,

  asisdshf,

  bitfield,

  branch_imm,

  branch_reg,

  compbranch,

  condbranch,

 condcmp_imm,

 condcmp_reg,

  condsel,

  cryptoaes,

  cryptosha2,

  cryptosha3,

  dp_1src,

  dp_2src,

  dp_3src,

  exception,

  extract,

  float2fix,

  float2int,

  floatccmp,

  floatcmp,

  floatdp1,

  floatdp2,

  floatdp3,

  floatimm,

  floatsel,

 ldst_immpost,

 ldst_immpre,

  ldst_imm9, /* immpost or immpre */

  ldst_pos,

  ldst_regoff,

 ldst_unpriv,

 ldst_unscaled,

  ldstexcl,

 ldstnapair_offs,

 ldstpair_off,

 ldstpair_indexed,

  loadlit,

  log_imm,

  log_shift,

  lse_atomic,

  movewide,

  pcreladdr,

  ic_system,

  testbranch,

}

 

 

Enumerator identifier

/*Enumerator identifier. */

enumaarch64_op op;    绝大部分指令的op都是0,这个域主要用来区分一些特殊的指令。普通指令里,只有add立即数使用了非0.

 

  {"add", 0x11000000, 0x7f000000,addsub_imm, OP_ADD, CORE, OP3 (Rd_SP, Rn_SP, AIMM), QL_R2NIL, F_HAS_ALIAS |F_SF},

 

在parse_operands函数里使用了一次,代码如下。

 

case AARCH64_OPND_AIMM:

  if(opcode->op == OP_ADD)

    /* ADDmay have relocation types.  */

   po_misc_or_fail (parse_shifter_operand_reloc (&str, info,

                          SHIFTED_ARITH_IMM));

  else

   po_misc_or_fail (parse_shifter_operand (&str, info,

                        SHIFTED_ARITH_IMM));

 

 

提供指令的组件

CORE

提供指令的组件

 

这个指令是CORE支持的,所以avariant是CORE枚举类型。有的指令是浮点单元支持的,所以是FP,有的是加密加速单元提供的,所以是CRYPTO。

 

arm有如下类型的组件提供指令

#defineCORE &aarch64_feature_v8

#defineFP &aarch64_feature_fp

#defineSIMD &aarch64_feature_simd

#defineCRYPTO &aarch64_feature_crypto

#defineCRC &aarch64_feature_crc

#defineLSE &aarch64_feature_lse

#defineLOR &aarch64_feature_lor

#defineRDMA &aarch64_feature_rdma

#defineFP_F16 &aarch64_feature_fp_f16

#defineSIMD_F16 &aarch64_feature_simd_f16

#defineRAS &aarch64_feature_ras

#defineSTAT_PROFILE &aarch64_feature_stat_profile

#defineARMV8_2 &aarch64_feature_v8_2

 

操作数

OP3 (Rd, Rn, Rm)

操作数编码数组

 

 

OP3(Rd, Rn, Rm) 逐个展开如下

{AARCH64_OPND_Rd,AARCH64_OPND_Rn, AARCH64_OPND_Rm }

 

辅助宏定义如下

#defineOPND(x) AARCH64_OPND_##x

#defineOP0() {}

#defineOP1(a) {OPND(a)}

#defineOP2(a,b) {OPND(a), OPND(b)}

#defineOP3(a,b,c) {OPND(a), OPND(b), OPND(c)}

#defineOP4(a,b,c,d) {OPND(a), OPND(b), OPND(c), OPND(d)}

#defineOP5(a,b,c,d,e) {OPND(a), OPND(b), OPND(c), OPND(d), OPND(e)}

 

 

在enum aarch64_opnd里定义了arm支持的所有的操作数,其中有如下定义

{

AARCH64_OPND_Rd,/* Integer register as destination. */

AARCH64_OPND_Rn,/* Integer register as source. */

AARCH64_OPND_Rm,/* Integer register as source. */

}

 

操作数的限定序列

OP3 (Rd, Rn, Rm)

操作数编码数组

 

QL_I3SAMER展开实际上是

{

{AARCH64_OPND_QLF_W,AARCH64_OPND_QLF_W, AARCH64_OPND_QLF_W }

{AARCH64_OPND_QLF_X,AARCH64_OPND_QLF_X,AARCH64_OPND_QLF_X }

}

 

 

具体的辅助宏定义如下

/*e.g. UDIV <Xd>, <Xn>, <Xm>. */

#defineQL_I3SAMER \

{ \

QLF3(W,W,W),\

QLF3(X,X,X),\

}

#defineQLF3(a,b,c) {QLF(a), QLF(b), QLF(c)}

#defineQLF(x) AARCH64_OPND_QLF_##x

 

 

操作数限定符定义全部在enum aarch64_opnd_qualifier

{

/* Indicating no further qualification on anoperand. */

AARCH64_OPND_QLF_NIL,

 

/* Qualifying an operand which is a general purpose(integer) register;

indicating the operand data size or a specificregister. */

AARCH64_OPND_QLF_W, /* Wn, WZR or WSP. */

AARCH64_OPND_QLF_X, /* Xn, XZR or XSP. */

 

 

 

其中,W表示word,32bit变量,X表示64bit变量。这里可以看出,sf不是固定的部分,也不能作为判断是否adc指令的依据,所以指令掩码不能包含sf位。根据手册上的说明可以清楚看出。

 

 

指令标志

F_SF标志的解释如下:

/* Instruction has the field of'sf'. */

#define F_SF (1 << 5)

很明显,这个说的是bit31,表明是32位还是64位。

 

 

F_HAS_ALIAS和F_ALIAS标志

 

adcs和adcs类似。sbc和sbcs差异是最后的标志不相同F_HAS_ALIAS| F_SF,

#define F_HAS_ALIAS (1 << 1)

这个指的是,当rn==‘11111’的时候,可以用NGC助记符代替。这个也就是NGC的来历。

 

再看NGC的定义

{"sbc", 0x5a000000, 0x7fe0fc00,addsub_carry, 0, CORE, OP3 (Rd, Rn, Rm), QL_I3SAMER, F_HAS_ALIAS | F_SF},

{"ngc", 0x5a0003e0, 0x7fe0ffe0,addsub_carry, 0, CORE, OP2 (Rd, Rm), QL_I2SAME, F_ALIAS | F_SF},

差别在于,Rn对应的bit变成了3e,也就是全1,操作数从OP3变成了OP2。另外,ngc的flga是F_ALIAS,表明这是个alias指令助记符,而sbc是F_HAS_ALIAS,可见sbc是真正的指令。

 

这个class一共4条指令,ADC, ADCS,SBC,SBCS ,最后一个s实际上是表示sign,影响S bit。

1 0
原创粉丝点击