x/arch/arm64: implement arm64 disassembler
- Add support for all basic instructions (except for the following 6 system instructions: AT, DC, HVC, SMC, SYS and TLBI) - Add support for all FP basic instructions - Add support for all SIMD instructions (plan9 syntax refer to CL 41654) - Add cases for testing all instructions and comparing disassembly result with external disassembler (by gnu syntax) Disassembler framework is mainly contributed by Zheng Xu <zheng.xu@arm.com> Testing and bug fixing are mainly contributed by Fannie Zhang <fannie.zhang@arm.com> Other parts (such as decoder table and argument) are mainly contributed by Wei Xiao <wei.xiao@arm.com> Fixes #19157 Change-Id: I76b6b075f487857124c8ca774a12d764d4ee85c7 Reviewed-on: https://go-review.googlesource.com/43651 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Родитель
b19d1a73c7
Коммит
f40095975f
|
@ -0,0 +1,494 @@
|
|||
// Generated by ARM internal tool
|
||||
// DO NOT EDIT
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
// Naming for Go decoder arguments:
|
||||
//
|
||||
// - arg_Wd: a W register encoded in the Rd[4:0] field (31 is wzr)
|
||||
//
|
||||
// - arg_Xd: a X register encoded in the Rd[4:0] field (31 is xzr)
|
||||
//
|
||||
// - arg_Wds: a W register encoded in the Rd[4:0] field (31 is wsp)
|
||||
//
|
||||
// - arg_Xds: a X register encoded in the Rd[4:0] field (31 is sp)
|
||||
//
|
||||
// - arg_Wn: encoded in Rn[9:5]
|
||||
//
|
||||
// - arg_Wm: encoded in Rm[20:16]
|
||||
//
|
||||
// - arg_Wm_extend__UXTB_0__UXTH_1__LSL_UXTW_2__UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4:
|
||||
// a W register encoded in Rm with an extend encoded in option[15:13] and an amount
|
||||
// encoded in imm3[12:10] in the range [0,4].
|
||||
//
|
||||
// - arg_Rm_extend__UXTB_0__UXTH_1__UXTW_2__LSL_UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4:
|
||||
// a W or X register encoded in Rm with an extend encoded in option[15:13] and an
|
||||
// amount encoded in imm3[12:10] in the range [0,4]. If the extend is UXTX or SXTX,
|
||||
// it's an X register else, it's a W register.
|
||||
//
|
||||
// - arg_Wm_shift__LSL_0__LSR_1__ASR_2__0_31:
|
||||
// a W register encoded in Rm with a shift encoded in shift[23:22] and an amount
|
||||
// encoded in imm6[15:10] in the range [0,31].
|
||||
//
|
||||
// - arg_IAddSub:
|
||||
// An immediate for a add/sub instruction encoded in imm12[21:10] with an optional
|
||||
// left shift of 12 encoded in shift[23:22].
|
||||
//
|
||||
// - arg_Rt_31_1__W_0__X_1:
|
||||
// a W or X register encoded in Rt[4:0]. The width specifier is encoded in the field
|
||||
// [31:31] (offset 31, bit count 1) and the register is W for 0 and X for 1.
|
||||
//
|
||||
// - arg_[s|u]label_FIELDS_POWER:
|
||||
// a program label encoded as "FIELDS" times 2^POWER in the range [MIN, MAX] (determined
|
||||
// by signd/unsigned, FIELDS and POWER), e.g.
|
||||
// arg_slabel_imm14_2
|
||||
// arg_slabel_imm19_2
|
||||
// arg_slabel_imm26_2
|
||||
// arg_slabel_immhi_immlo_0
|
||||
// arg_slabel_immhi_immlo_12
|
||||
//
|
||||
// - arg_Xns_mem_post_imm7_8_signed:
|
||||
// addressing mode of post-index with a base register: Xns and a signed offset encoded
|
||||
// in the "imm7" field times 8
|
||||
//
|
||||
// - arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__3_1:
|
||||
// addressing mode of extended register with a base register: Xns, an offset register
|
||||
// (<Wm>|<Xm>) with an extend encoded in option[15:13] and a shift amount encoded in
|
||||
// S[12:12] in the range [0,3] (S=0:0, S=1:3).
|
||||
//
|
||||
// - arg_Xns_mem_optional_imm12_4_unsigned:
|
||||
// addressing mode of unsigned offset with a base register: Xns and an optional unsigned
|
||||
// offset encoded in the "imm12" field times 4
|
||||
//
|
||||
// - arg_Xns_mem_wb_imm7_4_signed:
|
||||
// addressing mode of pre-index with a base register: Xns and the signed offset encoded
|
||||
// in the "imm7" field times 4
|
||||
//
|
||||
// - arg_Xns_mem_post_size_1_8_unsigned__4_0__8_1__16_2__32_3:
|
||||
// a post-index immediate offset, encoded in the "size" field. It can have the following values:
|
||||
// #4 when size = 00
|
||||
// #8 when size = 01
|
||||
// #16 when size = 10
|
||||
// #32 when size = 11
|
||||
//
|
||||
// - arg_immediate_0_127_CRm_op2:
|
||||
// an immediate encoded in "CRm:op2" in the range 0 to 127
|
||||
//
|
||||
// - arg_immediate_bitmask_64_N_imms_immr:
|
||||
// a bitmask immediate for 64-bit variant and encoded in "N:imms:immr"
|
||||
//
|
||||
// - arg_immediate_SBFX_SBFM_64M_bitfield_width_64_imms:
|
||||
// an immediate for the <width> bitfield of SBFX 64-bit variant
|
||||
//
|
||||
// - arg_immediate_shift_32_implicit_inverse_imm16_hw:
|
||||
// a 32-bit immediate of the bitwise inverse of which can be encoded in "imm16:hw"
|
||||
//
|
||||
// - arg_cond_[Not]AllowALNV_[Invert|Normal]:
|
||||
// a standard condition, encoded in the "cond" field, excluding (NotAllow) AL and NV with
|
||||
// its least significant bit [Yes|No] inverted, e.g.
|
||||
// arg_cond_AllowALNV_Normal
|
||||
// arg_cond_NotAllowALNV_Invert
|
||||
//
|
||||
// - arg_immediate_OptLSL_amount_16_0_48:
|
||||
// An immediate for MOV[KNZ] instruction encoded in imm16[20:5] with an optional
|
||||
// left shift of 16 in the range [0, 48] encoded in hw[22, 21]
|
||||
//
|
||||
// - arg_immediate_0_width_m1_immh_immb__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8:
|
||||
// the left shift amount, in the range 0 to the operand width in bits minus 1,
|
||||
// encoded in the "immh:immb" field. It can have the following values:
|
||||
// (UInt(immh:immb)-8) when immh = 0001
|
||||
// (UInt(immh:immb)-16) when immh = 001x
|
||||
// (UInt(immh:immb)-32) when immh = 01xx
|
||||
// (UInt(immh:immb)-64) when immh = 1xxx
|
||||
//
|
||||
// - arg_immediate_1_width_immh_immb__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4:
|
||||
// the right shift amount, in the range 1 to the destination operand width in
|
||||
// bits, encoded in the "immh:immb" field. It can have the following values:
|
||||
// (16-UInt(immh:immb)) when immh = 0001
|
||||
// (32-UInt(immh:immb)) when immh = 001x
|
||||
// (64-UInt(immh:immb)) when immh = 01xx
|
||||
//
|
||||
// - arg_immediate_8x8_a_b_c_d_e_f_g_h:
|
||||
// a 64-bit immediate 'aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh',
|
||||
// encoded in "a:b:c:d:e:f:g:h".
|
||||
//
|
||||
// - arg_immediate_fbits_min_1_max_32_sub_64_scale:
|
||||
// the number of bits after the binary point in the fixed-point destination,
|
||||
// in the range 1 to 32, encoded as 64 minus "scale".
|
||||
//
|
||||
// - arg_immediate_floatzero: #0.0
|
||||
//
|
||||
// - arg_immediate_exp_3_pre_4_a_b_c_d_e_f_g_h:
|
||||
// a signed floating-point constant with 3-bit exponent and normalized 4 bits of precision,
|
||||
// encoded in "a:b:c:d:e:f:g:h"
|
||||
//
|
||||
// - arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__64UIntimmhimmb_4__128UIntimmhimmb_8:
|
||||
// the number of fractional bits, in the range 1 to the operand width, encoded
|
||||
// in the "immh:immb" field. It can have the following values:
|
||||
// (64-UInt(immh:immb)) when immh = 01xx
|
||||
// (128-UInt(immh:immb)) when immh = 1xxx
|
||||
//
|
||||
// - arg_immediate_index_Q_imm4__imm4lt20gt_00__imm4_10:
|
||||
// the lowest numbered byte element to be extracted, encoded in the "Q:imm4" field.
|
||||
// It can have the following values:
|
||||
// imm4<2:0> when Q = 0, imm4<3> = 0
|
||||
// imm4 when Q = 1, imm4<3> = x
|
||||
//
|
||||
// - arg_sysop_AT_SYS_CR_system:
|
||||
// system operation for system instruction: AT encoded in the "op1:CRm<0>:op2" field
|
||||
//
|
||||
// - arg_prfop_Rt:
|
||||
// prefectch operation encoded in the "Rt"
|
||||
//
|
||||
// - arg_sysreg_o0_op1_CRn_CRm_op2:
|
||||
// system register name encoded in the "o0:op1:CRn:CRm:op2"
|
||||
//
|
||||
// - arg_pstatefield_op1_op2__SPSel_05__DAIFSet_36__DAIFClr_37:
|
||||
// PSTATE field name encoded in the "op1:op2" field
|
||||
//
|
||||
// - arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31:
|
||||
// one register with arrangement specifier encoded in the "size:Q" field which can have the following values:
|
||||
// 8B when size = 00, Q = 0
|
||||
// 16B when size = 00, Q = 1
|
||||
// 4H when size = 01, Q = 0
|
||||
// 8H when size = 01, Q = 1
|
||||
// 2S when size = 10, Q = 0
|
||||
// 4S when size = 10, Q = 1
|
||||
// 2D when size = 11, Q = 1
|
||||
// The encoding size = 11, Q = 0 is reserved.
|
||||
//
|
||||
// - arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31:
|
||||
// three registers with arrangement specifier encoded in the "size:Q" field which can have the following values:
|
||||
// 8B when size = 00, Q = 0
|
||||
// 16B when size = 00, Q = 1
|
||||
// 4H when size = 01, Q = 0
|
||||
// 8H when size = 01, Q = 1
|
||||
// 2S when size = 10, Q = 0
|
||||
// 4S when size = 10, Q = 1
|
||||
// 2D when size = 11, Q = 1
|
||||
// The encoding size = 11, Q = 0 is reserved.
|
||||
//
|
||||
// - arg_Vt_1_arrangement_H_index__Q_S_size_1:
|
||||
// one register with arrangement:H and element index encoded in "Q:S:size<1>".
|
||||
|
||||
type instArg uint16
|
||||
|
||||
const (
|
||||
_ instArg = iota
|
||||
arg_Bt
|
||||
arg_Cm
|
||||
arg_Cn
|
||||
arg_cond_AllowALNV_Normal
|
||||
arg_conditional
|
||||
arg_cond_NotAllowALNV_Invert
|
||||
arg_Da
|
||||
arg_Dd
|
||||
arg_Dm
|
||||
arg_Dn
|
||||
arg_Dt
|
||||
arg_Dt2
|
||||
arg_Hd
|
||||
arg_Hn
|
||||
arg_Ht
|
||||
arg_IAddSub
|
||||
arg_immediate_0_127_CRm_op2
|
||||
arg_immediate_0_15_CRm
|
||||
arg_immediate_0_15_nzcv
|
||||
arg_immediate_0_31_imm5
|
||||
arg_immediate_0_31_immr
|
||||
arg_immediate_0_31_imms
|
||||
arg_immediate_0_63_b5_b40
|
||||
arg_immediate_0_63_immh_immb__UIntimmhimmb64_8
|
||||
arg_immediate_0_63_immr
|
||||
arg_immediate_0_63_imms
|
||||
arg_immediate_0_65535_imm16
|
||||
arg_immediate_0_7_op1
|
||||
arg_immediate_0_7_op2
|
||||
arg_immediate_0_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4
|
||||
arg_immediate_0_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8
|
||||
arg_immediate_0_width_m1_immh_immb__UIntimmhimmb8_1__UIntimmhimmb16_2__UIntimmhimmb32_4__UIntimmhimmb64_8
|
||||
arg_immediate_0_width_size__8_0__16_1__32_2
|
||||
arg_immediate_1_64_immh_immb__128UIntimmhimmb_8
|
||||
arg_immediate_1_width_immh_immb__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4
|
||||
arg_immediate_1_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4
|
||||
arg_immediate_1_width_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__16UIntimmhimmb_1__32UIntimmhimmb_2__64UIntimmhimmb_4__128UIntimmhimmb_8
|
||||
arg_immediate_8x8_a_b_c_d_e_f_g_h
|
||||
arg_immediate_ASR_SBFM_32M_bitfield_0_31_immr
|
||||
arg_immediate_ASR_SBFM_64M_bitfield_0_63_immr
|
||||
arg_immediate_BFI_BFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_BFI_BFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_BFI_BFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_BFI_BFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_BFXIL_BFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_BFXIL_BFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_BFXIL_BFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_BFXIL_BFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_bitmask_32_imms_immr
|
||||
arg_immediate_bitmask_64_N_imms_immr
|
||||
arg_immediate_exp_3_pre_4_a_b_c_d_e_f_g_h
|
||||
arg_immediate_exp_3_pre_4_imm8
|
||||
arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__64UIntimmhimmb_4__128UIntimmhimmb_8
|
||||
arg_immediate_fbits_min_1_max_0_sub_0_immh_immb__SEEAdvancedSIMDmodifiedimmediate_0__64UIntimmhimmb_4__128UIntimmhimmb_8
|
||||
arg_immediate_fbits_min_1_max_32_sub_64_scale
|
||||
arg_immediate_fbits_min_1_max_64_sub_64_scale
|
||||
arg_immediate_floatzero
|
||||
arg_immediate_index_Q_imm4__imm4lt20gt_00__imm4_10
|
||||
arg_immediate_LSL_UBFM_32M_bitfield_0_31_immr
|
||||
arg_immediate_LSL_UBFM_64M_bitfield_0_63_immr
|
||||
arg_immediate_LSR_UBFM_32M_bitfield_0_31_immr
|
||||
arg_immediate_LSR_UBFM_64M_bitfield_0_63_immr
|
||||
arg_immediate_MSL__a_b_c_d_e_f_g_h_cmode__8_0__16_1
|
||||
arg_immediate_optional_0_15_CRm
|
||||
arg_immediate_optional_0_65535_imm16
|
||||
arg_immediate_OptLSL__a_b_c_d_e_f_g_h_cmode__0_0__8_1
|
||||
arg_immediate_OptLSL__a_b_c_d_e_f_g_h_cmode__0_0__8_1__16_2__24_3
|
||||
arg_immediate_OptLSL_amount_16_0_16
|
||||
arg_immediate_OptLSL_amount_16_0_48
|
||||
arg_immediate_OptLSLZero__a_b_c_d_e_f_g_h
|
||||
arg_immediate_SBFIZ_SBFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_SBFIZ_SBFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_SBFIZ_SBFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_SBFIZ_SBFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_SBFX_SBFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_SBFX_SBFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_SBFX_SBFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_SBFX_SBFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_shift_32_implicit_imm16_hw
|
||||
arg_immediate_shift_32_implicit_inverse_imm16_hw
|
||||
arg_immediate_shift_64_implicit_imm16_hw
|
||||
arg_immediate_shift_64_implicit_inverse_imm16_hw
|
||||
arg_immediate_UBFIZ_UBFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_UBFIZ_UBFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_UBFIZ_UBFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_UBFIZ_UBFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_UBFX_UBFM_32M_bitfield_lsb_32_immr
|
||||
arg_immediate_UBFX_UBFM_32M_bitfield_width_32_imms
|
||||
arg_immediate_UBFX_UBFM_64M_bitfield_lsb_64_immr
|
||||
arg_immediate_UBFX_UBFM_64M_bitfield_width_64_imms
|
||||
arg_immediate_zero
|
||||
arg_option_DMB_BO_system_CRm
|
||||
arg_option_DSB_BO_system_CRm
|
||||
arg_option_ISB_BI_system_CRm
|
||||
arg_prfop_Rt
|
||||
arg_pstatefield_op1_op2__SPSel_05__DAIFSet_36__DAIFClr_37
|
||||
arg_Qd
|
||||
arg_Qn
|
||||
arg_Qt
|
||||
arg_Qt2
|
||||
arg_Rm_extend__UXTB_0__UXTH_1__UXTW_2__LSL_UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4
|
||||
arg_Rn_16_5__W_1__W_2__W_4__X_8
|
||||
arg_Rt_31_1__W_0__X_1
|
||||
arg_Sa
|
||||
arg_Sd
|
||||
arg_slabel_imm14_2
|
||||
arg_slabel_imm19_2
|
||||
arg_slabel_imm26_2
|
||||
arg_slabel_immhi_immlo_0
|
||||
arg_slabel_immhi_immlo_12
|
||||
arg_Sm
|
||||
arg_Sn
|
||||
arg_St
|
||||
arg_St2
|
||||
arg_sysop_AT_SYS_CR_system
|
||||
arg_sysop_DC_SYS_CR_system
|
||||
arg_sysop_IC_SYS_CR_system
|
||||
arg_sysop_SYS_CR_system
|
||||
arg_sysop_TLBI_SYS_CR_system
|
||||
arg_sysreg_o0_op1_CRn_CRm_op2
|
||||
arg_Vd_16_5__B_1__H_2__S_4__D_8
|
||||
arg_Vd_19_4__B_1__H_2__S_4
|
||||
arg_Vd_19_4__B_1__H_2__S_4__D_8
|
||||
arg_Vd_19_4__D_8
|
||||
arg_Vd_19_4__S_4__D_8
|
||||
arg_Vd_22_1__S_0
|
||||
arg_Vd_22_1__S_0__D_1
|
||||
arg_Vd_22_1__S_1
|
||||
arg_Vd_22_2__B_0__H_1__S_2
|
||||
arg_Vd_22_2__B_0__H_1__S_2__D_3
|
||||
arg_Vd_22_2__D_3
|
||||
arg_Vd_22_2__H_0__S_1__D_2
|
||||
arg_Vd_22_2__H_1__S_2
|
||||
arg_Vd_22_2__S_1__D_2
|
||||
arg_Vd_arrangement_16B
|
||||
arg_Vd_arrangement_2D
|
||||
arg_Vd_arrangement_4S
|
||||
arg_Vd_arrangement_D_index__1
|
||||
arg_Vd_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4__imm5lt4gt_8_1
|
||||
arg_Vd_arrangement_imm5_Q___8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
|
||||
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__2S_40__4S_41__2D_81
|
||||
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41
|
||||
arg_Vd_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
|
||||
arg_Vd_arrangement_immh___SEEAdvancedSIMDmodifiedimmediate_0__8H_1__4S_2__2D_4
|
||||
arg_Vd_arrangement_Q___2S_0__4S_1
|
||||
arg_Vd_arrangement_Q___4H_0__8H_1
|
||||
arg_Vd_arrangement_Q___8B_0__16B_1
|
||||
arg_Vd_arrangement_Q_sz___2S_00__4S_10__2D_11
|
||||
arg_Vd_arrangement_size___4S_1__2D_2
|
||||
arg_Vd_arrangement_size___8H_0__1Q_3
|
||||
arg_Vd_arrangement_size___8H_0__4S_1__2D_2
|
||||
arg_Vd_arrangement_size_Q___4H_00__8H_01__2S_10__4S_11__1D_20__2D_21
|
||||
arg_Vd_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vd_arrangement_size_Q___8B_00__16B_01
|
||||
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11
|
||||
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vd_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Vd_arrangement_sz___4S_0__2D_1
|
||||
arg_Vd_arrangement_sz_Q___2S_00__4S_01
|
||||
arg_Vd_arrangement_sz_Q___2S_00__4S_01__2D_11
|
||||
arg_Vd_arrangement_sz_Q___2S_10__4S_11
|
||||
arg_Vd_arrangement_sz_Q___4H_00__8H_01__2S_10__4S_11
|
||||
arg_Vm_22_1__S_0__D_1
|
||||
arg_Vm_22_2__B_0__H_1__S_2__D_3
|
||||
arg_Vm_22_2__D_3
|
||||
arg_Vm_22_2__H_1__S_2
|
||||
arg_Vm_arrangement_4S
|
||||
arg_Vm_arrangement_Q___8B_0__16B_1
|
||||
arg_Vm_arrangement_size___8H_0__4S_1__2D_2
|
||||
arg_Vm_arrangement_size___H_1__S_2_index__size_L_H_M__HLM_1__HL_2_1
|
||||
arg_Vm_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vm_arrangement_size_Q___8B_00__16B_01
|
||||
arg_Vm_arrangement_size_Q___8B_00__16B_01__1D_30__2D_31
|
||||
arg_Vm_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vm_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Vm_arrangement_sz_Q___2S_00__4S_01__2D_11
|
||||
arg_Vm_arrangement_sz___S_0__D_1_index__sz_L_H__HL_00__H_10_1
|
||||
arg_Vn_19_4__B_1__H_2__S_4__D_8
|
||||
arg_Vn_19_4__D_8
|
||||
arg_Vn_19_4__H_1__S_2__D_4
|
||||
arg_Vn_19_4__S_4__D_8
|
||||
arg_Vn_1_arrangement_16B
|
||||
arg_Vn_22_1__D_1
|
||||
arg_Vn_22_1__S_0__D_1
|
||||
arg_Vn_22_2__B_0__H_1__S_2__D_3
|
||||
arg_Vn_22_2__D_3
|
||||
arg_Vn_22_2__H_0__S_1__D_2
|
||||
arg_Vn_22_2__H_1__S_2
|
||||
arg_Vn_2_arrangement_16B
|
||||
arg_Vn_3_arrangement_16B
|
||||
arg_Vn_4_arrangement_16B
|
||||
arg_Vn_arrangement_16B
|
||||
arg_Vn_arrangement_4S
|
||||
arg_Vn_arrangement_D_index__1
|
||||
arg_Vn_arrangement_D_index__imm5_1
|
||||
arg_Vn_arrangement_imm5___B_1__H_2_index__imm5__imm5lt41gt_1__imm5lt42gt_2_1
|
||||
arg_Vn_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5_imm4__imm4lt30gt_1__imm4lt31gt_2__imm4lt32gt_4__imm4lt3gt_8_1
|
||||
arg_Vn_arrangement_imm5___B_1__H_2__S_4__D_8_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4__imm5lt4gt_8_1
|
||||
arg_Vn_arrangement_imm5___B_1__H_2__S_4_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4_1
|
||||
arg_Vn_arrangement_imm5___D_8_index__imm5_1
|
||||
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__2S_40__4S_41__2D_81
|
||||
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41
|
||||
arg_Vn_arrangement_immh_Q___SEEAdvancedSIMDmodifiedimmediate_00__8B_10__16B_11__4H_20__8H_21__2S_40__4S_41__2D_81
|
||||
arg_Vn_arrangement_immh___SEEAdvancedSIMDmodifiedimmediate_0__8H_1__4S_2__2D_4
|
||||
arg_Vn_arrangement_Q___8B_0__16B_1
|
||||
arg_Vn_arrangement_Q_sz___2S_00__4S_10__2D_11
|
||||
arg_Vn_arrangement_Q_sz___4S_10
|
||||
arg_Vn_arrangement_S_index__imm5__imm5lt41gt_1__imm5lt42gt_2__imm5lt43gt_4_1
|
||||
arg_Vn_arrangement_size___2D_3
|
||||
arg_Vn_arrangement_size___8H_0__4S_1__2D_2
|
||||
arg_Vn_arrangement_size_Q___4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01__1D_30__2D_31
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Vn_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__4S_21
|
||||
arg_Vn_arrangement_sz___2D_1
|
||||
arg_Vn_arrangement_sz___2S_0__2D_1
|
||||
arg_Vn_arrangement_sz___4S_0__2D_1
|
||||
arg_Vn_arrangement_sz_Q___2S_00__4S_01
|
||||
arg_Vn_arrangement_sz_Q___2S_00__4S_01__2D_11
|
||||
arg_Vn_arrangement_sz_Q___4H_00__8H_01__2S_10__4S_11
|
||||
arg_Vt_1_arrangement_B_index__Q_S_size_1
|
||||
arg_Vt_1_arrangement_D_index__Q_1
|
||||
arg_Vt_1_arrangement_H_index__Q_S_size_1
|
||||
arg_Vt_1_arrangement_S_index__Q_S_1
|
||||
arg_Vt_1_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
|
||||
arg_Vt_2_arrangement_B_index__Q_S_size_1
|
||||
arg_Vt_2_arrangement_D_index__Q_1
|
||||
arg_Vt_2_arrangement_H_index__Q_S_size_1
|
||||
arg_Vt_2_arrangement_S_index__Q_S_1
|
||||
arg_Vt_2_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
|
||||
arg_Vt_2_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Vt_3_arrangement_B_index__Q_S_size_1
|
||||
arg_Vt_3_arrangement_D_index__Q_1
|
||||
arg_Vt_3_arrangement_H_index__Q_S_size_1
|
||||
arg_Vt_3_arrangement_S_index__Q_S_1
|
||||
arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
|
||||
arg_Vt_3_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Vt_4_arrangement_B_index__Q_S_size_1
|
||||
arg_Vt_4_arrangement_D_index__Q_1
|
||||
arg_Vt_4_arrangement_H_index__Q_S_size_1
|
||||
arg_Vt_4_arrangement_S_index__Q_S_1
|
||||
arg_Vt_4_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__1D_30__2D_31
|
||||
arg_Vt_4_arrangement_size_Q___8B_00__16B_01__4H_10__8H_11__2S_20__4S_21__2D_31
|
||||
arg_Wa
|
||||
arg_Wd
|
||||
arg_Wds
|
||||
arg_Wm
|
||||
arg_Wm_extend__UXTB_0__UXTH_1__LSL_UXTW_2__UXTX_3__SXTB_4__SXTH_5__SXTW_6__SXTX_7__0_4
|
||||
arg_Wm_shift__LSL_0__LSR_1__ASR_2__0_31
|
||||
arg_Wm_shift__LSL_0__LSR_1__ASR_2__ROR_3__0_31
|
||||
arg_Wn
|
||||
arg_Wns
|
||||
arg_Ws
|
||||
arg_Wt
|
||||
arg_Wt2
|
||||
arg_Xa
|
||||
arg_Xd
|
||||
arg_Xds
|
||||
arg_Xm
|
||||
arg_Xm_shift__LSL_0__LSR_1__ASR_2__0_63
|
||||
arg_Xm_shift__LSL_0__LSR_1__ASR_2__ROR_3__0_63
|
||||
arg_Xn
|
||||
arg_Xns
|
||||
arg_Xns_mem
|
||||
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__1_1
|
||||
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__2_1
|
||||
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__3_1
|
||||
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__0_0__4_1
|
||||
arg_Xns_mem_extend_m__UXTW_2__LSL_3__SXTW_6__SXTX_7__absent_0__0_1
|
||||
arg_Xns_mem_offset
|
||||
arg_Xns_mem_optional_imm12_16_unsigned
|
||||
arg_Xns_mem_optional_imm12_1_unsigned
|
||||
arg_Xns_mem_optional_imm12_2_unsigned
|
||||
arg_Xns_mem_optional_imm12_4_unsigned
|
||||
arg_Xns_mem_optional_imm12_8_unsigned
|
||||
arg_Xns_mem_optional_imm7_16_signed
|
||||
arg_Xns_mem_optional_imm7_4_signed
|
||||
arg_Xns_mem_optional_imm7_8_signed
|
||||
arg_Xns_mem_optional_imm9_1_signed
|
||||
arg_Xns_mem_post_fixedimm_1
|
||||
arg_Xns_mem_post_fixedimm_12
|
||||
arg_Xns_mem_post_fixedimm_16
|
||||
arg_Xns_mem_post_fixedimm_2
|
||||
arg_Xns_mem_post_fixedimm_24
|
||||
arg_Xns_mem_post_fixedimm_3
|
||||
arg_Xns_mem_post_fixedimm_32
|
||||
arg_Xns_mem_post_fixedimm_4
|
||||
arg_Xns_mem_post_fixedimm_6
|
||||
arg_Xns_mem_post_fixedimm_8
|
||||
arg_Xns_mem_post_imm7_16_signed
|
||||
arg_Xns_mem_post_imm7_4_signed
|
||||
arg_Xns_mem_post_imm7_8_signed
|
||||
arg_Xns_mem_post_imm9_1_signed
|
||||
arg_Xns_mem_post_Q__16_0__32_1
|
||||
arg_Xns_mem_post_Q__24_0__48_1
|
||||
arg_Xns_mem_post_Q__32_0__64_1
|
||||
arg_Xns_mem_post_Q__8_0__16_1
|
||||
arg_Xns_mem_post_size__1_0__2_1__4_2__8_3
|
||||
arg_Xns_mem_post_size__2_0__4_1__8_2__16_3
|
||||
arg_Xns_mem_post_size__3_0__6_1__12_2__24_3
|
||||
arg_Xns_mem_post_size__4_0__8_1__16_2__32_3
|
||||
arg_Xns_mem_post_Xm
|
||||
arg_Xns_mem_wb_imm7_16_signed
|
||||
arg_Xns_mem_wb_imm7_4_signed
|
||||
arg_Xns_mem_wb_imm7_8_signed
|
||||
arg_Xns_mem_wb_imm9_1_signed
|
||||
arg_Xs
|
||||
arg_Xt
|
||||
arg_Xt2
|
||||
)
|
|
@ -0,0 +1,329 @@
|
|||
// Generated by ARM internal tool
|
||||
// DO NOT EDIT
|
||||
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
// Following functions are used as the predicator: canDecode of according instruction
|
||||
// Refer to instFormat inside decode.go for more details
|
||||
|
||||
func at_sys_cr_system_cond(instr uint32) bool {
|
||||
return sys_op_4((instr>>16)&0x7, 0x7, 0x8, (instr>>5)&0x7) == Sys_AT
|
||||
}
|
||||
|
||||
func bfi_bfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return (instr>>5)&0x1f != 0x1f && uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func bfi_bfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return (instr>>5)&0x1f != 0x1f && uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func bfxil_bfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) >= uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func bfxil_bfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) >= uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func cinc_csinc_32_condsel_cond(instr uint32) bool {
|
||||
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func cinc_csinc_64_condsel_cond(instr uint32) bool {
|
||||
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func cinv_csinv_32_condsel_cond(instr uint32) bool {
|
||||
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func cinv_csinv_64_condsel_cond(instr uint32) bool {
|
||||
return instr&0x1f0000 != 0x1f0000 && instr&0xe000 != 0xe000 && instr&0x3e0 != 0x3e0 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func cneg_csneg_32_condsel_cond(instr uint32) bool {
|
||||
return instr&0xe000 != 0xe000 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func cneg_csneg_64_condsel_cond(instr uint32) bool {
|
||||
return instr&0xe000 != 0xe000 && (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func csinc_general_cond(instr uint32) bool {
|
||||
return instr&0xe000 != 0xe000
|
||||
}
|
||||
func csinv_general_cond(instr uint32) bool {
|
||||
return instr&0xe000 != 0xe000
|
||||
}
|
||||
func dc_sys_cr_system_cond(instr uint32) bool {
|
||||
return sys_op_4((instr>>16)&0x7, 0x7, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_DC
|
||||
}
|
||||
|
||||
func ic_sys_cr_system_cond(instr uint32) bool {
|
||||
return sys_op_4((instr>>16)&0x7, 0x7, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_IC
|
||||
}
|
||||
|
||||
func lsl_ubfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return instr&0xfc00 != 0x7c00 && (instr>>10)&0x3f+1 == (instr>>16)&0x3f
|
||||
}
|
||||
|
||||
func lsl_ubfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return instr&0xfc00 != 0xfc00 && (instr>>10)&0x3f+1 == (instr>>16)&0x3f
|
||||
}
|
||||
|
||||
func mov_orr_32_log_imm_cond(instr uint32) bool {
|
||||
return !move_wide_preferred_4((instr>>31)&0x1, (instr>>22)&0x1, (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func mov_orr_64_log_imm_cond(instr uint32) bool {
|
||||
return !move_wide_preferred_4((instr>>31)&0x1, (instr>>22)&0x1, (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func mov_movn_32_movewide_cond(instr uint32) bool {
|
||||
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0) && !is_ones_n16((instr>>5)&0xffff)
|
||||
}
|
||||
|
||||
func mov_movn_64_movewide_cond(instr uint32) bool {
|
||||
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
|
||||
}
|
||||
|
||||
func mov_add_32_addsub_imm_cond(instr uint32) bool {
|
||||
return instr&0x1f == 0x1f || (instr>>5)&0x1f == 0x1f
|
||||
}
|
||||
|
||||
func mov_add_64_addsub_imm_cond(instr uint32) bool {
|
||||
return instr&0x1f == 0x1f || (instr>>5)&0x1f == 0x1f
|
||||
}
|
||||
|
||||
func mov_movz_32_movewide_cond(instr uint32) bool {
|
||||
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
|
||||
}
|
||||
|
||||
func mov_movz_64_movewide_cond(instr uint32) bool {
|
||||
return !(is_zero((instr>>5)&0xffff) && (instr>>21)&0x3 != 0x0)
|
||||
}
|
||||
|
||||
func ror_extr_32_extract_cond(instr uint32) bool {
|
||||
return (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func ror_extr_64_extract_cond(instr uint32) bool {
|
||||
return (instr>>5)&0x1f == (instr>>16)&0x1f
|
||||
}
|
||||
|
||||
func sbfiz_sbfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func sbfiz_sbfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func sbfx_sbfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func sbfx_sbfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func tlbi_sys_cr_system_cond(instr uint32) bool {
|
||||
return sys_op_4((instr>>16)&0x7, 0x8, (instr>>8)&0xf, (instr>>5)&0x7) == Sys_TLBI
|
||||
}
|
||||
|
||||
func ubfiz_ubfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func ubfiz_ubfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return uint8((instr>>10)&0x3f) < uint8((instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func ubfx_ubfm_32m_bitfield_cond(instr uint32) bool {
|
||||
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func ubfx_ubfm_64m_bitfield_cond(instr uint32) bool {
|
||||
return bfxpreferred_4((instr>>31)&0x1, extract_bit((instr>>29)&0x3, 1), (instr>>10)&0x3f, (instr>>16)&0x3f)
|
||||
}
|
||||
|
||||
func fcvtzs_asisdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func fcvtzs_asimdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func fcvtzu_asisdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func fcvtzu_asimdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func mov_umov_asimdins_w_w_cond(instr uint32) bool {
|
||||
return ((instr>>16)&0x1f)&0x7 == 0x4
|
||||
}
|
||||
|
||||
func mov_umov_asimdins_x_x_cond(instr uint32) bool {
|
||||
return ((instr>>16)&0x1f)&0xf == 0x8
|
||||
}
|
||||
|
||||
func mov_orr_asimdsame_only_cond(instr uint32) bool {
|
||||
return (instr>>16)&0x1f == (instr>>5)&0x1f
|
||||
}
|
||||
|
||||
func rshrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func scvtf_asisdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func scvtf_asimdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func shl_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func shl_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func shrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sli_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sli_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqrshrn_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqrshrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqrshrun_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqrshrun_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshl_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshl_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshlu_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshlu_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshrn_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshrun_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sqshrun_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sri_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sri_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func srshr_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func srshr_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func srsra_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func srsra_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sshll_asimdshf_l_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sshr_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sshr_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ssra_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ssra_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func sxtl_sshll_asimdshf_l_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0 && bit_count((instr>>19)&0xf) == 1
|
||||
}
|
||||
|
||||
func ucvtf_asisdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ucvtf_asimdshf_c_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqrshrn_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqrshrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqshl_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqshl_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqshrn_asisdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uqshrn_asimdshf_n_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func urshr_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func urshr_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ursra_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ursra_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ushll_asimdshf_l_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ushr_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func ushr_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func usra_asisdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func usra_asimdshf_r_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0
|
||||
}
|
||||
func uxtl_ushll_asimdshf_l_cond(instr uint32) bool {
|
||||
return instr&0x780000 != 0x0 && bit_count((instr>>19)&0xf) == 1
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
func extract_bit(value, bit uint32) uint32 {
|
||||
return (value >> bit) & 1
|
||||
}
|
||||
|
||||
func bfxpreferred_4(sf, opc1, imms, immr uint32) bool {
|
||||
if imms < immr {
|
||||
return false
|
||||
}
|
||||
if (imms>>5 == sf) && (imms&0x1f == 0x1f) {
|
||||
return false
|
||||
}
|
||||
if immr == 0 {
|
||||
if sf == 0 && (imms == 7 || imms == 15) {
|
||||
return false
|
||||
}
|
||||
if sf == 1 && opc1 == 0 && (imms == 7 ||
|
||||
imms == 15 || imms == 31) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func move_wide_preferred_4(sf, N, imms, immr uint32) bool {
|
||||
if sf == 1 && N != 1 {
|
||||
return false
|
||||
}
|
||||
if sf == 0 && !(N == 0 && ((imms>>5)&1) == 0) {
|
||||
return false
|
||||
}
|
||||
if imms < 16 {
|
||||
return (-immr)%16 <= (15 - imms)
|
||||
}
|
||||
width := uint32(32)
|
||||
if sf == 1 {
|
||||
width = uint32(64)
|
||||
}
|
||||
if imms >= (width - 15) {
|
||||
return (immr % 16) <= (imms - (width - 15))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Sys uint8
|
||||
|
||||
const (
|
||||
Sys_AT Sys = iota
|
||||
Sys_DC
|
||||
Sys_IC
|
||||
Sys_TLBI
|
||||
Sys_SYS
|
||||
)
|
||||
|
||||
func sys_op_4(op1, crn, crm, op2 uint32) Sys {
|
||||
// TODO: system instruction
|
||||
return Sys_SYS
|
||||
}
|
||||
|
||||
func is_zero(x uint32) bool {
|
||||
return x == 0
|
||||
}
|
||||
|
||||
func is_ones_n16(x uint32) bool {
|
||||
return x == 0xffff
|
||||
}
|
||||
|
||||
func bit_count(x uint32) uint8 {
|
||||
var count uint8
|
||||
for count = 0; x > 0; x >>= 1 {
|
||||
if (x & 1) == 1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecode(t *testing.T) {
|
||||
data, err := ioutil.ReadFile("testdata/cases.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
all := string(data)
|
||||
for strings.Contains(all, "\t\t") {
|
||||
all = strings.Replace(all, "\t\t", "\t", -1)
|
||||
}
|
||||
for _, line := range strings.Split(all, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
f := strings.SplitN(line, "\t", 3)
|
||||
i := strings.Index(f[0], "|")
|
||||
if i < 0 {
|
||||
t.Errorf("parsing %q: missing | separator", f[0])
|
||||
continue
|
||||
}
|
||||
if i%2 != 0 {
|
||||
t.Errorf("parsing %q: misaligned | separator", f[0])
|
||||
}
|
||||
code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
|
||||
if err != nil {
|
||||
t.Errorf("parsing %q: %v", f[0], err)
|
||||
continue
|
||||
}
|
||||
syntax, asm := f[1], f[2]
|
||||
inst, decodeErr := Decode(code)
|
||||
if decodeErr != nil && decodeErr != errUnknown {
|
||||
// Some rarely used system instructions are not supported
|
||||
// Following logicals will filter such unknown instructions
|
||||
|
||||
t.Errorf("parsing %x: %s", code, decodeErr)
|
||||
continue
|
||||
}
|
||||
var out string
|
||||
switch syntax {
|
||||
case "gnu":
|
||||
out = GNUSyntax(inst)
|
||||
case "plan9":
|
||||
out = GoSyntax(inst, 0, nil, nil)
|
||||
default:
|
||||
t.Errorf("unknown syntax %q", syntax)
|
||||
continue
|
||||
}
|
||||
// TODO: system instruction.
|
||||
var Todo = strings.Fields(`
|
||||
sys
|
||||
dc
|
||||
at
|
||||
tlbi
|
||||
ic
|
||||
hvc
|
||||
smc
|
||||
`)
|
||||
if strings.Replace(out, " ", "", -1) != strings.Replace(asm, " ", "", -1) && !hasPrefix(asm, Todo...) {
|
||||
// Exclude MSR since GNU objdump result is incorrect. eg. 0xd504431f msr s0_4_c4_c3_0, xzr
|
||||
if !strings.HasSuffix(asm, " nv") && !strings.HasPrefix(asm, "msr") {
|
||||
t.Errorf("Decode(%s) [%s] = %s, want %s", f[0], syntax, out, asm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,601 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Support for testing against external disassembler program.
|
||||
// Copied and simplified from ../../arm/armasm/ext_test.go.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
dumpTest = flag.Bool("dump", false, "dump all encodings")
|
||||
mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
|
||||
longTest = flag.Bool("long", false, "long test")
|
||||
keep = flag.Bool("keep", false, "keep object files around")
|
||||
debug = false
|
||||
)
|
||||
|
||||
// An ExtInst represents a single decoded instruction parsed
|
||||
// from an external disassembler's output.
|
||||
type ExtInst struct {
|
||||
addr uint64
|
||||
enc [4]byte
|
||||
nenc int
|
||||
text string
|
||||
}
|
||||
|
||||
func (r ExtInst) String() string {
|
||||
return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
|
||||
}
|
||||
|
||||
// An ExtDis is a connection between an external disassembler and a test.
|
||||
type ExtDis struct {
|
||||
Arch Mode
|
||||
Dec chan ExtInst
|
||||
File *os.File
|
||||
Size int
|
||||
KeepFile bool
|
||||
Cmd *exec.Cmd
|
||||
}
|
||||
|
||||
// InstJson describes instruction fields value got from ARMv8-A Reference Manual
|
||||
type InstJson struct {
|
||||
Name string
|
||||
Bits string
|
||||
Arch string
|
||||
Syntax string
|
||||
Code string
|
||||
Alias string
|
||||
Enc uint32
|
||||
}
|
||||
|
||||
// A Mode is an instruction execution mode.
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
_ Mode = iota
|
||||
ModeARM64
|
||||
)
|
||||
|
||||
// Run runs the given command - the external disassembler - and returns
|
||||
// a buffered reader of its standard output.
|
||||
func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
|
||||
if *keep {
|
||||
log.Printf("%s\n", strings.Join(cmd, " "))
|
||||
}
|
||||
ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
|
||||
out, err := ext.Cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stdoutpipe: %v", err)
|
||||
}
|
||||
if err := ext.Cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("exec: %v", err)
|
||||
}
|
||||
|
||||
b := bufio.NewReaderSize(out, 1<<20)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Wait waits for the command started with Run to exit.
|
||||
func (ext *ExtDis) Wait() error {
|
||||
return ext.Cmd.Wait()
|
||||
}
|
||||
|
||||
// testExtDis tests a set of byte sequences against an external disassembler.
|
||||
// The disassembler is expected to produce the given syntax and run
|
||||
// in the given architecture mode (16, 32, or 64-bit).
|
||||
// The extdis function must start the external disassembler
|
||||
// and then parse its output, sending the parsed instructions on ext.Dec.
|
||||
// The generate function calls its argument f once for each byte sequence
|
||||
// to be tested. The generate function itself will be called twice, and it must
|
||||
// make the same sequence of calls to f each time.
|
||||
// When a disassembly does not match the internal decoding,
|
||||
// allowedMismatch determines whether this mismatch should be
|
||||
// allowed, or else considered an error.
|
||||
func testExtDis(
|
||||
t *testing.T,
|
||||
syntax string,
|
||||
arch Mode,
|
||||
extdis func(ext *ExtDis) error,
|
||||
generate func(f func([]byte)),
|
||||
allowedMismatch func(text string, inst *Inst, dec ExtInst) bool,
|
||||
) {
|
||||
start := time.Now()
|
||||
ext := &ExtDis{
|
||||
Dec: make(chan ExtInst),
|
||||
Arch: arch,
|
||||
}
|
||||
errc := make(chan error)
|
||||
|
||||
// First pass: write instructions to input file for external disassembler.
|
||||
file, f, size, err := writeInst(generate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ext.Size = size
|
||||
ext.File = f
|
||||
defer func() {
|
||||
f.Close()
|
||||
if !*keep {
|
||||
os.Remove(file)
|
||||
}
|
||||
}()
|
||||
|
||||
// Second pass: compare disassembly against our decodings.
|
||||
var (
|
||||
totalTests = 0
|
||||
totalSkips = 0
|
||||
totalErrors = 0
|
||||
|
||||
errors = make([]string, 0, 100) // Sampled errors, at most cap
|
||||
)
|
||||
go func() {
|
||||
errc <- extdis(ext)
|
||||
}()
|
||||
|
||||
generate(func(enc []byte) {
|
||||
dec, ok := <-ext.Dec
|
||||
if !ok {
|
||||
t.Errorf("decoding stream ended early")
|
||||
return
|
||||
}
|
||||
inst, text := disasm(syntax, pad(enc))
|
||||
|
||||
totalTests++
|
||||
if *dumpTest {
|
||||
fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
|
||||
}
|
||||
if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" {
|
||||
suffix := ""
|
||||
if allowedMismatch(text, &inst, dec) {
|
||||
totalSkips++
|
||||
if !*mismatch {
|
||||
return
|
||||
}
|
||||
suffix += " (allowed mismatch)"
|
||||
}
|
||||
totalErrors++
|
||||
cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix)
|
||||
|
||||
if len(errors) >= cap(errors) {
|
||||
j := rand.Intn(totalErrors)
|
||||
if j >= cap(errors) {
|
||||
return
|
||||
}
|
||||
errors = append(errors[:j], errors[j+1:]...)
|
||||
}
|
||||
errors = append(errors, cmp)
|
||||
}
|
||||
})
|
||||
|
||||
if *mismatch {
|
||||
totalErrors -= totalSkips
|
||||
}
|
||||
|
||||
for _, b := range errors {
|
||||
t.Log(b)
|
||||
}
|
||||
|
||||
if totalErrors > 0 {
|
||||
t.Fail()
|
||||
}
|
||||
t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
|
||||
t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage())
|
||||
if err := <-errc; err != nil {
|
||||
t.Fatalf("external disassembler: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Start address of text.
|
||||
const start = 0x8000
|
||||
|
||||
// writeInst writes the generated byte sequences to a new file
|
||||
// starting at offset start. That file is intended to be the input to
|
||||
// the external disassembler.
|
||||
func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
|
||||
f, err = ioutil.TempFile("", "arm64asm")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
file = f.Name()
|
||||
|
||||
f.Seek(start, 0)
|
||||
w := bufio.NewWriter(f)
|
||||
defer w.Flush()
|
||||
size = 0
|
||||
generate(func(x []byte) {
|
||||
if debug {
|
||||
fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):])
|
||||
}
|
||||
w.Write(x)
|
||||
w.Write(zeros[len(x):])
|
||||
size += len(zeros)
|
||||
})
|
||||
return file, f, size, nil
|
||||
}
|
||||
|
||||
var zeros = []byte{0, 0, 0, 0}
|
||||
|
||||
// pad pads the code sequence with pops.
|
||||
func pad(enc []byte) []byte {
|
||||
if len(enc) < 4 {
|
||||
enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
|
||||
}
|
||||
return enc
|
||||
}
|
||||
|
||||
// disasm returns the decoded instruction and text
|
||||
// for the given source bytes, using the given syntax and mode.
|
||||
func disasm(syntax string, src []byte) (inst Inst, text string) {
|
||||
var err error
|
||||
inst, err = Decode(src)
|
||||
if err != nil {
|
||||
text = "error: " + err.Error()
|
||||
return
|
||||
}
|
||||
text = inst.String()
|
||||
switch syntax {
|
||||
case "gnu":
|
||||
text = GNUSyntax(inst)
|
||||
case "plan9": // [sic]
|
||||
text = GoSyntax(inst, 0, nil, nil)
|
||||
default:
|
||||
text = "error: unknown syntax " + syntax
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// decodecoverage returns a floating point number denoting the
|
||||
// decoder coverage.
|
||||
func decodeCoverage() float64 {
|
||||
n := 0
|
||||
for _, t := range decoderCover {
|
||||
if t {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return 100 * float64(1+n) / float64(1+len(decoderCover))
|
||||
}
|
||||
|
||||
// Helpers for writing disassembler output parsers.
|
||||
|
||||
// hasPrefix reports whether any of the space-separated words in the text s
|
||||
// begins with any of the given prefixes.
|
||||
func hasPrefix(s string, prefixes ...string) bool {
|
||||
for _, prefix := range prefixes {
|
||||
for cur_s := s; cur_s != ""; {
|
||||
if strings.HasPrefix(cur_s, prefix) {
|
||||
return true
|
||||
}
|
||||
i := strings.Index(cur_s, " ")
|
||||
if i < 0 {
|
||||
break
|
||||
}
|
||||
cur_s = cur_s[i+1:]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isHex reports whether b is a hexadecimal character (0-9a-fA-F).
|
||||
func isHex(b byte) bool {
|
||||
return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F')
|
||||
}
|
||||
|
||||
// parseHex parses the hexadecimal byte dump in hex,
|
||||
// appending the parsed bytes to raw and returning the updated slice.
|
||||
// The returned bool reports whether any invalid hex was found.
|
||||
// Spaces and tabs between bytes are okay but any other non-hex is not.
|
||||
func parseHex(hex []byte, raw []byte) ([]byte, bool) {
|
||||
hex = bytes.TrimSpace(hex)
|
||||
for j := 0; j < len(hex); {
|
||||
for hex[j] == ' ' || hex[j] == '\t' {
|
||||
j++
|
||||
}
|
||||
if j >= len(hex) {
|
||||
break
|
||||
}
|
||||
if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
|
||||
return nil, false
|
||||
}
|
||||
raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1]))
|
||||
j += 2
|
||||
}
|
||||
return raw, true
|
||||
}
|
||||
|
||||
func unhex(b byte) byte {
|
||||
if '0' <= b && b <= '9' {
|
||||
return b - '0'
|
||||
} else if 'A' <= b && b <= 'F' {
|
||||
return b - 'A' + 10
|
||||
} else if 'a' <= b && b <= 'f' {
|
||||
return b - 'a' + 10
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
|
||||
func index(s []byte, t string) int {
|
||||
i := 0
|
||||
for {
|
||||
j := bytes.IndexByte(s[i:], t[0])
|
||||
if j < 0 {
|
||||
return -1
|
||||
}
|
||||
i = i + j
|
||||
if i+len(t) > len(s) {
|
||||
return -1
|
||||
}
|
||||
for k := 1; k < len(t); k++ {
|
||||
if s[i+k] != t[k] {
|
||||
goto nomatch
|
||||
}
|
||||
}
|
||||
return i
|
||||
nomatch:
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
|
||||
// If s must be rewritten, it is rewritten in place.
|
||||
func fixSpace(s []byte) []byte {
|
||||
s = bytes.TrimSpace(s)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
|
||||
goto Fix
|
||||
}
|
||||
}
|
||||
return s
|
||||
|
||||
Fix:
|
||||
b := s
|
||||
w := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '\t' || c == '\n' {
|
||||
c = ' '
|
||||
}
|
||||
if c == ' ' && w > 0 && b[w-1] == ' ' {
|
||||
continue
|
||||
}
|
||||
b[w] = c
|
||||
w++
|
||||
}
|
||||
if w > 0 && b[w-1] == ' ' {
|
||||
w--
|
||||
}
|
||||
return b[:w]
|
||||
}
|
||||
|
||||
// Fllowing regular expressions matches instructions using relative addressing mode.
|
||||
// pcrel matches B instructions and BL instructions.
|
||||
// pcrelr matches instrucions which consisted of register arguments and label arguments.
|
||||
// pcrelim matches instructions which consisted of register arguments, immediate
|
||||
// arguments and lable arguments.
|
||||
// pcrelrzr and prcelimzr matches instructions when register arguments is zero register.
|
||||
// pcrelprfm matches PRFM instructions when arguments consisted of register and lable.
|
||||
// pcrelprfmim matches PRFM instructions when arguments consisted of immediate and lable.
|
||||
var (
|
||||
pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bl)x?(?:\.)?(?:eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|nv)?) 0x([0-9a-f]+)$`)
|
||||
pcrelr = regexp.MustCompile(`^((?:.*)?(?:ldr|adrp|adr|cbnz|cbz|ldrsw) (?:x|w|s|d|q)(?:[0-9]+,)) 0x([0-9a-f]+)$`)
|
||||
pcrelrzr = regexp.MustCompile(`^((?:.*)?(?:ldr|adrp|adr|cbnz|cbz|ldrsw) (?:x|w)zr,) 0x([0-9a-f]+)$`)
|
||||
pcrelim = regexp.MustCompile(`^((?:.*)?(?:tbnz|tbz) (?:x|w)(?:[0-9]+,) (?:#[0-9a-f]+,)) 0x([0-9a-f]+)$`)
|
||||
pcrelimzr = regexp.MustCompile(`^((?:.*)?(?:tbnz|tbz) (?:x|w)zr, (?:#[0-9a-f]+,)) 0x([0-9a-f]+)$`)
|
||||
pcrelprfm = regexp.MustCompile(`^((?:.*)?(?:prfm) (?:[0-9a-z]+,)) 0x([0-9a-f]+)$`)
|
||||
pcrelprfmim = regexp.MustCompile(`^((?:.*)?(?:prfm) (?:#0x[0-9a-f]+,)) 0x([0-9a-f]+)$`)
|
||||
)
|
||||
|
||||
// Round is the multiple of the number of instructions that read from Json file.
|
||||
// Round used as seed value for pseudo-random number generator provides the same sequence
|
||||
// in the same round run for the external disassembler and decoder.
|
||||
var Round int
|
||||
|
||||
// condmark is used to mark conditional instructions when need to generate and test
|
||||
// conditional instructions.
|
||||
var condmark bool = false
|
||||
|
||||
// Generate instruction binary according to Json file
|
||||
// Encode variable field of instruction with random value
|
||||
func doFuzzy(inst *InstJson, Ninst int) {
|
||||
var testdata uint32
|
||||
var NonDigRE = regexp.MustCompile(`[\D]`)
|
||||
rand.Seed(int64(Round + Ninst))
|
||||
off := 0
|
||||
DigBit := ""
|
||||
if condmark == true && !strings.Contains(inst.Bits, "cond") {
|
||||
inst.Enc = 0xffffffff
|
||||
} else {
|
||||
for _, f := range strings.Split(inst.Bits, "|") {
|
||||
if i := strings.Index(f, ":"); i >= 0 {
|
||||
// consider f contains "01:2" and "Rm:5"
|
||||
DigBit = f[:i]
|
||||
m := NonDigRE.FindStringSubmatch(DigBit)
|
||||
if m == nil {
|
||||
DigBit = strings.TrimSpace(DigBit)
|
||||
s := strings.Split(DigBit, "")
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case "1", "(1)":
|
||||
testdata |= 1 << uint(31-off)
|
||||
}
|
||||
off++
|
||||
}
|
||||
} else {
|
||||
// DigBit is "Rn" or "imm3"
|
||||
n, _ := strconv.Atoi(f[i+1:])
|
||||
if DigBit == "cond" && condmark == true {
|
||||
r := uint8(Round)
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
switch (r >> uint(i)) & 1 {
|
||||
case 1:
|
||||
testdata |= 1 << uint(31-off)
|
||||
}
|
||||
off++
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < n; i++ {
|
||||
r := rand.Intn(2)
|
||||
switch r {
|
||||
case 1:
|
||||
testdata |= 1 << uint(31-off)
|
||||
}
|
||||
off++
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, bit := range strings.Fields(f) {
|
||||
switch bit {
|
||||
case "0", "(0)":
|
||||
off++
|
||||
continue
|
||||
case "1", "(1)":
|
||||
testdata |= 1 << uint(31-off)
|
||||
default:
|
||||
r := rand.Intn(2)
|
||||
switch r {
|
||||
case 1:
|
||||
testdata |= 1 << uint(31-off)
|
||||
}
|
||||
}
|
||||
off++
|
||||
}
|
||||
}
|
||||
if off != 32 {
|
||||
log.Printf("incorrect bit count for %s %s: have %d", inst.Name, inst.Bits, off)
|
||||
}
|
||||
inst.Enc = testdata
|
||||
}
|
||||
}
|
||||
|
||||
// Generators.
|
||||
//
|
||||
// The test cases are described as functions that invoke a callback repeatedly,
|
||||
// with a new input sequence each time. These helpers make writing those
|
||||
// a little easier.
|
||||
|
||||
// JSONCases generates ARM64 instructions according to inst.json.
|
||||
func JSONCases(t *testing.T) func(func([]byte)) {
|
||||
return func(try func([]byte)) {
|
||||
data, err := ioutil.ReadFile("inst.json")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var insts []InstJson
|
||||
var instsN []InstJson
|
||||
// Change N value to get more cases only when condmark=false.
|
||||
N := 100
|
||||
if condmark == true {
|
||||
N = 16
|
||||
}
|
||||
if err := json.Unmarshal(data, &insts); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Append instructions to get more test cases.
|
||||
for i := 0; i < N; {
|
||||
for _, inst := range insts {
|
||||
instsN = append(instsN, inst)
|
||||
}
|
||||
i++
|
||||
}
|
||||
Round = 0
|
||||
for i := range instsN {
|
||||
if i%len(insts) == 0 {
|
||||
Round++
|
||||
}
|
||||
doFuzzy(&instsN[i], i)
|
||||
}
|
||||
for _, inst := range instsN {
|
||||
if condmark == true && inst.Enc == 0xffffffff {
|
||||
continue
|
||||
}
|
||||
enc := inst.Enc
|
||||
try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// condCases generates conditional instructions.
|
||||
func condCases(t *testing.T) func(func([]byte)) {
|
||||
return func(try func([]byte)) {
|
||||
condmark = true
|
||||
JSONCases(t)(func(enc []byte) {
|
||||
try(enc)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// hexCases generates the cases written in hexadecimal in the encoded string.
|
||||
// Spaces in 'encoded' separate entire test cases, not individual bytes.
|
||||
func hexCases(t *testing.T, encoded string) func(func([]byte)) {
|
||||
return func(try func([]byte)) {
|
||||
for _, x := range strings.Fields(encoded) {
|
||||
src, err := hex.DecodeString(x)
|
||||
if err != nil {
|
||||
t.Errorf("parsing %q: %v", x, err)
|
||||
}
|
||||
try(src)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// testdataCases generates the test cases recorded in testdata/cases.txt.
|
||||
// It only uses the inputs; it ignores the answers recorded in that file.
|
||||
func testdataCases(t *testing.T) func(func([]byte)) {
|
||||
var codes [][]byte
|
||||
data, err := ioutil.ReadFile("testdata/cases.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
f := strings.Fields(line)[0]
|
||||
i := strings.Index(f, "|")
|
||||
if i < 0 {
|
||||
t.Errorf("parsing %q: missing | separator", f)
|
||||
continue
|
||||
}
|
||||
if i%2 != 0 {
|
||||
t.Errorf("parsing %q: misaligned | separator", f)
|
||||
}
|
||||
code, err := hex.DecodeString(f[:i] + f[i+1:])
|
||||
if err != nil {
|
||||
t.Errorf("parsing %q: %v", f, err)
|
||||
continue
|
||||
}
|
||||
codes = append(codes, code)
|
||||
}
|
||||
|
||||
return func(try func([]byte)) {
|
||||
for _, code := range codes {
|
||||
try(code)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
|
||||
// This form typically matches the syntax defined in the ARM Reference Manual.
|
||||
func GNUSyntax(inst Inst) string {
|
||||
switch inst.Op {
|
||||
case RET:
|
||||
if r, ok := inst.Args[0].(Reg); ok && r == X30 {
|
||||
return "ret"
|
||||
}
|
||||
case B:
|
||||
if _, ok := inst.Args[0].(Cond); ok {
|
||||
return strings.ToLower("b." + inst.Args[0].String() + " " + inst.Args[1].String())
|
||||
}
|
||||
case SYSL:
|
||||
result := strings.ToLower(inst.String())
|
||||
return strings.Replace(result, "c", "C", -1)
|
||||
case DCPS1, DCPS2, DCPS3, CLREX:
|
||||
return strings.ToLower(strings.TrimSpace(inst.String()))
|
||||
case ISB:
|
||||
if strings.Contains(inst.String(), "SY") {
|
||||
result := strings.TrimSuffix(inst.String(), " SY")
|
||||
return strings.ToLower(result)
|
||||
}
|
||||
}
|
||||
return strings.ToLower(inst.String())
|
||||
}
|
|
@ -0,0 +1,963 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// An Op is an ARM64 opcode.
|
||||
type Op uint16
|
||||
|
||||
// NOTE: The actual Op values are defined in tables.go.
|
||||
// They are chosen to simplify instruction decoding and
|
||||
// are not a dense packing from 0 to N, although the
|
||||
// density is high, probably at least 90%.
|
||||
|
||||
func (op Op) String() string {
|
||||
if op >= Op(len(opstr)) || opstr[op] == "" {
|
||||
return fmt.Sprintf("Op(%d)", int(op))
|
||||
}
|
||||
return opstr[op]
|
||||
}
|
||||
|
||||
// An Inst is a single instruction.
|
||||
type Inst struct {
|
||||
Op Op // Opcode mnemonic
|
||||
Enc uint32 // Raw encoding bits.
|
||||
Args Args // Instruction arguments, in ARM manual order.
|
||||
}
|
||||
|
||||
func (i Inst) String() string {
|
||||
var args []string
|
||||
for _, arg := range i.Args {
|
||||
if arg == nil {
|
||||
break
|
||||
}
|
||||
args = append(args, arg.String())
|
||||
}
|
||||
return i.Op.String() + " " + strings.Join(args, ", ")
|
||||
}
|
||||
|
||||
// An Args holds the instruction arguments.
|
||||
// If an instruction has fewer than 5 arguments,
|
||||
// the final elements in the array are nil.
|
||||
type Args [5]Arg
|
||||
|
||||
// An Arg is a single instruction argument, one of these types:
|
||||
// Reg, RegSP, ImmShift, RegExtshiftAmount, PCRel, MemImmediate,
|
||||
// MemExtend, Imm, Imm64, Imm_hint, Imm_clrex, Imm_dcps, Cond,
|
||||
// Imm_c, Imm_option, Imm_prfop, Pstatefield, Systemreg, Imm_fp
|
||||
// RegisterWithArrangement, RegisterWithArrangementAndIndex.
|
||||
type Arg interface {
|
||||
isArg()
|
||||
String() string
|
||||
}
|
||||
|
||||
// A Reg is a single register.
|
||||
// The zero value denotes W0, not the absence of a register.
|
||||
type Reg uint16
|
||||
|
||||
const (
|
||||
W0 Reg = iota
|
||||
W1
|
||||
W2
|
||||
W3
|
||||
W4
|
||||
W5
|
||||
W6
|
||||
W7
|
||||
W8
|
||||
W9
|
||||
W10
|
||||
W11
|
||||
W12
|
||||
W13
|
||||
W14
|
||||
W15
|
||||
W16
|
||||
W17
|
||||
W18
|
||||
W19
|
||||
W20
|
||||
W21
|
||||
W22
|
||||
W23
|
||||
W24
|
||||
W25
|
||||
W26
|
||||
W27
|
||||
W28
|
||||
W29
|
||||
W30
|
||||
WZR
|
||||
|
||||
X0
|
||||
X1
|
||||
X2
|
||||
X3
|
||||
X4
|
||||
X5
|
||||
X6
|
||||
X7
|
||||
X8
|
||||
X9
|
||||
X10
|
||||
X11
|
||||
X12
|
||||
X13
|
||||
X14
|
||||
X15
|
||||
X16
|
||||
X17
|
||||
X18
|
||||
X19
|
||||
X20
|
||||
X21
|
||||
X22
|
||||
X23
|
||||
X24
|
||||
X25
|
||||
X26
|
||||
X27
|
||||
X28
|
||||
X29
|
||||
X30
|
||||
XZR
|
||||
|
||||
B0
|
||||
B1
|
||||
B2
|
||||
B3
|
||||
B4
|
||||
B5
|
||||
B6
|
||||
B7
|
||||
B8
|
||||
B9
|
||||
B10
|
||||
B11
|
||||
B12
|
||||
B13
|
||||
B14
|
||||
B15
|
||||
B16
|
||||
B17
|
||||
B18
|
||||
B19
|
||||
B20
|
||||
B21
|
||||
B22
|
||||
B23
|
||||
B24
|
||||
B25
|
||||
B26
|
||||
B27
|
||||
B28
|
||||
B29
|
||||
B30
|
||||
B31
|
||||
|
||||
H0
|
||||
H1
|
||||
H2
|
||||
H3
|
||||
H4
|
||||
H5
|
||||
H6
|
||||
H7
|
||||
H8
|
||||
H9
|
||||
H10
|
||||
H11
|
||||
H12
|
||||
H13
|
||||
H14
|
||||
H15
|
||||
H16
|
||||
H17
|
||||
H18
|
||||
H19
|
||||
H20
|
||||
H21
|
||||
H22
|
||||
H23
|
||||
H24
|
||||
H25
|
||||
H26
|
||||
H27
|
||||
H28
|
||||
H29
|
||||
H30
|
||||
H31
|
||||
|
||||
S0
|
||||
S1
|
||||
S2
|
||||
S3
|
||||
S4
|
||||
S5
|
||||
S6
|
||||
S7
|
||||
S8
|
||||
S9
|
||||
S10
|
||||
S11
|
||||
S12
|
||||
S13
|
||||
S14
|
||||
S15
|
||||
S16
|
||||
S17
|
||||
S18
|
||||
S19
|
||||
S20
|
||||
S21
|
||||
S22
|
||||
S23
|
||||
S24
|
||||
S25
|
||||
S26
|
||||
S27
|
||||
S28
|
||||
S29
|
||||
S30
|
||||
S31
|
||||
|
||||
D0
|
||||
D1
|
||||
D2
|
||||
D3
|
||||
D4
|
||||
D5
|
||||
D6
|
||||
D7
|
||||
D8
|
||||
D9
|
||||
D10
|
||||
D11
|
||||
D12
|
||||
D13
|
||||
D14
|
||||
D15
|
||||
D16
|
||||
D17
|
||||
D18
|
||||
D19
|
||||
D20
|
||||
D21
|
||||
D22
|
||||
D23
|
||||
D24
|
||||
D25
|
||||
D26
|
||||
D27
|
||||
D28
|
||||
D29
|
||||
D30
|
||||
D31
|
||||
|
||||
Q0
|
||||
Q1
|
||||
Q2
|
||||
Q3
|
||||
Q4
|
||||
Q5
|
||||
Q6
|
||||
Q7
|
||||
Q8
|
||||
Q9
|
||||
Q10
|
||||
Q11
|
||||
Q12
|
||||
Q13
|
||||
Q14
|
||||
Q15
|
||||
Q16
|
||||
Q17
|
||||
Q18
|
||||
Q19
|
||||
Q20
|
||||
Q21
|
||||
Q22
|
||||
Q23
|
||||
Q24
|
||||
Q25
|
||||
Q26
|
||||
Q27
|
||||
Q28
|
||||
Q29
|
||||
Q30
|
||||
Q31
|
||||
|
||||
V0
|
||||
V1
|
||||
V2
|
||||
V3
|
||||
V4
|
||||
V5
|
||||
V6
|
||||
V7
|
||||
V8
|
||||
V9
|
||||
V10
|
||||
V11
|
||||
V12
|
||||
V13
|
||||
V14
|
||||
V15
|
||||
V16
|
||||
V17
|
||||
V18
|
||||
V19
|
||||
V20
|
||||
V21
|
||||
V22
|
||||
V23
|
||||
V24
|
||||
V25
|
||||
V26
|
||||
V27
|
||||
V28
|
||||
V29
|
||||
V30
|
||||
V31
|
||||
|
||||
WSP = WZR // These are different registers with the same encoding.
|
||||
SP = XZR // These are different registers with the same encoding.
|
||||
)
|
||||
|
||||
func (Reg) isArg() {}
|
||||
|
||||
func (r Reg) String() string {
|
||||
switch {
|
||||
case r == WZR:
|
||||
return "WZR"
|
||||
case r == XZR:
|
||||
return "XZR"
|
||||
case W0 <= r && r <= W30:
|
||||
return fmt.Sprintf("W%d", int(r-W0))
|
||||
case X0 <= r && r <= X30:
|
||||
return fmt.Sprintf("X%d", int(r-X0))
|
||||
|
||||
case B0 <= r && r <= B31:
|
||||
return fmt.Sprintf("B%d", int(r-B0))
|
||||
case H0 <= r && r <= H31:
|
||||
return fmt.Sprintf("H%d", int(r-H0))
|
||||
case S0 <= r && r <= S31:
|
||||
return fmt.Sprintf("S%d", int(r-S0))
|
||||
case D0 <= r && r <= D31:
|
||||
return fmt.Sprintf("D%d", int(r-D0))
|
||||
case Q0 <= r && r <= Q31:
|
||||
return fmt.Sprintf("Q%d", int(r-Q0))
|
||||
|
||||
case V0 <= r && r <= V31:
|
||||
return fmt.Sprintf("V%d", int(r-V0))
|
||||
default:
|
||||
return fmt.Sprintf("Reg(%d)", int(r))
|
||||
}
|
||||
}
|
||||
|
||||
// A RegSP represent a register and X31/W31 is regarded as SP/WSP.
|
||||
type RegSP Reg
|
||||
|
||||
func (RegSP) isArg() {}
|
||||
|
||||
func (r RegSP) String() string {
|
||||
switch Reg(r) {
|
||||
case WSP:
|
||||
return "WSP"
|
||||
case SP:
|
||||
return "SP"
|
||||
default:
|
||||
return Reg(r).String()
|
||||
}
|
||||
}
|
||||
|
||||
type ImmShift struct {
|
||||
imm uint16
|
||||
shift uint8
|
||||
}
|
||||
|
||||
func (ImmShift) isArg() {}
|
||||
|
||||
func (is ImmShift) String() string {
|
||||
if is.shift == 0 {
|
||||
return fmt.Sprintf("#%#x", is.imm)
|
||||
}
|
||||
if is.shift < 128 {
|
||||
return fmt.Sprintf("#%#x, LSL #%d", is.imm, is.shift)
|
||||
}
|
||||
return fmt.Sprintf("#%#x, MSL #%d", is.imm, is.shift-128)
|
||||
}
|
||||
|
||||
type ExtShift uint8
|
||||
|
||||
const (
|
||||
_ ExtShift = iota
|
||||
uxtb
|
||||
uxth
|
||||
uxtw
|
||||
uxtx
|
||||
sxtb
|
||||
sxth
|
||||
sxtw
|
||||
sxtx
|
||||
lsl
|
||||
lsr
|
||||
asr
|
||||
ror
|
||||
)
|
||||
|
||||
func (extShift ExtShift) String() string {
|
||||
switch extShift {
|
||||
case uxtb:
|
||||
return "UXTB"
|
||||
|
||||
case uxth:
|
||||
return "UXTH"
|
||||
|
||||
case uxtw:
|
||||
return "UXTW"
|
||||
|
||||
case uxtx:
|
||||
return "UXTX"
|
||||
|
||||
case sxtb:
|
||||
return "SXTB"
|
||||
|
||||
case sxth:
|
||||
return "SXTH"
|
||||
|
||||
case sxtw:
|
||||
return "SXTW"
|
||||
|
||||
case sxtx:
|
||||
return "SXTX"
|
||||
|
||||
case lsl:
|
||||
return "LSL"
|
||||
|
||||
case lsr:
|
||||
return "LSR"
|
||||
|
||||
case asr:
|
||||
return "ASR"
|
||||
|
||||
case ror:
|
||||
return "ROR"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RegExtshiftAmount struct {
|
||||
reg Reg
|
||||
extShift ExtShift
|
||||
amount uint8
|
||||
show_zero bool
|
||||
}
|
||||
|
||||
func (RegExtshiftAmount) isArg() {}
|
||||
|
||||
func (rea RegExtshiftAmount) String() string {
|
||||
buf := rea.reg.String()
|
||||
if rea.extShift != ExtShift(0) {
|
||||
buf += ", " + rea.extShift.String()
|
||||
if rea.amount != 0 {
|
||||
buf += fmt.Sprintf(" #%d", rea.amount)
|
||||
} else {
|
||||
if rea.show_zero == true {
|
||||
buf += fmt.Sprintf(" #%d", rea.amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// A PCRel describes a memory address (usually a code label)
|
||||
// as a distance relative to the program counter.
|
||||
type PCRel int64
|
||||
|
||||
func (PCRel) isArg() {}
|
||||
|
||||
func (r PCRel) String() string {
|
||||
return fmt.Sprintf(".%+#x", uint64(r))
|
||||
}
|
||||
|
||||
// An AddrMode is an ARM addressing mode.
|
||||
type AddrMode uint8
|
||||
|
||||
const (
|
||||
_ AddrMode = iota
|
||||
AddrPostIndex // [R], X - use address R, set R = R + X
|
||||
AddrPreIndex // [R, X]! - use address R + X, set R = R + X
|
||||
AddrOffset // [R, X] - use address R + X
|
||||
AddrPostReg // [Rn], Rm - - use address Rn, set Rn = Rn + Rm
|
||||
)
|
||||
|
||||
// A MemImmediate is a memory reference made up of a base R and immediate X.
|
||||
// The effective memory address is R or R+X depending on AddrMode.
|
||||
type MemImmediate struct {
|
||||
Base RegSP
|
||||
Mode AddrMode
|
||||
imm int32
|
||||
}
|
||||
|
||||
func (MemImmediate) isArg() {}
|
||||
|
||||
func (m MemImmediate) String() string {
|
||||
R := m.Base.String()
|
||||
X := fmt.Sprintf("#%d", m.imm)
|
||||
|
||||
switch m.Mode {
|
||||
case AddrOffset:
|
||||
if X == "#0" {
|
||||
return fmt.Sprintf("[%s]", R)
|
||||
}
|
||||
return fmt.Sprintf("[%s,%s]", R, X)
|
||||
case AddrPreIndex:
|
||||
return fmt.Sprintf("[%s,%s]!", R, X)
|
||||
case AddrPostIndex:
|
||||
return fmt.Sprintf("[%s],%s", R, X)
|
||||
case AddrPostReg:
|
||||
post := Reg(X0) + Reg(m.imm)
|
||||
postR := post.String()
|
||||
return fmt.Sprintf("[%s], %s", R, postR)
|
||||
}
|
||||
return fmt.Sprintf("unimplemented!")
|
||||
}
|
||||
|
||||
// A MemExtend is a memory reference made up of a base R and index expression X.
|
||||
// The effective memory address is R or R+X depending on Index, Extend and Amount.
|
||||
type MemExtend struct {
|
||||
Base RegSP
|
||||
Index Reg
|
||||
Extend ExtShift
|
||||
Amount uint8
|
||||
Absent bool
|
||||
}
|
||||
|
||||
func (MemExtend) isArg() {}
|
||||
|
||||
func (m MemExtend) String() string {
|
||||
Rbase := m.Base.String()
|
||||
RIndex := m.Index.String()
|
||||
if m.Absent {
|
||||
if m.Amount != 0 {
|
||||
return fmt.Sprintf("[%s,%s,%s #0]", Rbase, RIndex, m.Extend.String())
|
||||
} else {
|
||||
if m.Extend != lsl {
|
||||
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
|
||||
} else {
|
||||
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if m.Amount != 0 {
|
||||
return fmt.Sprintf("[%s,%s,%s #%d]", Rbase, RIndex, m.Extend.String(), m.Amount)
|
||||
} else {
|
||||
if m.Extend != lsl {
|
||||
return fmt.Sprintf("[%s,%s,%s]", Rbase, RIndex, m.Extend.String())
|
||||
} else {
|
||||
return fmt.Sprintf("[%s,%s]", Rbase, RIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An Imm is an integer constant.
|
||||
type Imm struct {
|
||||
Imm uint32
|
||||
Decimal bool
|
||||
}
|
||||
|
||||
func (Imm) isArg() {}
|
||||
|
||||
func (i Imm) String() string {
|
||||
if !i.Decimal {
|
||||
return fmt.Sprintf("#%#x", i.Imm)
|
||||
} else {
|
||||
return fmt.Sprintf("#%d", i.Imm)
|
||||
}
|
||||
}
|
||||
|
||||
type Imm64 struct {
|
||||
Imm uint64
|
||||
Decimal bool
|
||||
}
|
||||
|
||||
func (Imm64) isArg() {}
|
||||
|
||||
func (i Imm64) String() string {
|
||||
if !i.Decimal {
|
||||
return fmt.Sprintf("#%#x", i.Imm)
|
||||
} else {
|
||||
return fmt.Sprintf("#%d", i.Imm)
|
||||
}
|
||||
}
|
||||
|
||||
// An Imm_hint is an integer constant for HINT instruction.
|
||||
type Imm_hint uint8
|
||||
|
||||
func (Imm_hint) isArg() {}
|
||||
|
||||
func (i Imm_hint) String() string {
|
||||
return fmt.Sprintf("#%#x", uint32(i))
|
||||
}
|
||||
|
||||
// An Imm_clrex is an integer constant for CLREX instruction.
|
||||
type Imm_clrex uint8
|
||||
|
||||
func (Imm_clrex) isArg() {}
|
||||
|
||||
func (i Imm_clrex) String() string {
|
||||
if i == 15 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("#%#x", uint32(i))
|
||||
}
|
||||
|
||||
// An Imm_dcps is an integer constant for DCPS[123] instruction.
|
||||
type Imm_dcps uint16
|
||||
|
||||
func (Imm_dcps) isArg() {}
|
||||
|
||||
func (i Imm_dcps) String() string {
|
||||
if i == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("#%#x", uint32(i))
|
||||
}
|
||||
|
||||
// Standard conditions.
|
||||
type Cond struct {
|
||||
Value uint8
|
||||
Invert bool
|
||||
}
|
||||
|
||||
func (Cond) isArg() {}
|
||||
|
||||
func (c Cond) String() string {
|
||||
cond31 := c.Value >> 1
|
||||
invert := bool((c.Value & 1) == 1)
|
||||
invert = (invert != c.Invert)
|
||||
switch cond31 {
|
||||
case 0:
|
||||
if invert {
|
||||
return "NE"
|
||||
} else {
|
||||
return "EQ"
|
||||
}
|
||||
case 1:
|
||||
if invert {
|
||||
return "CC"
|
||||
} else {
|
||||
return "CS"
|
||||
}
|
||||
case 2:
|
||||
if invert {
|
||||
return "PL"
|
||||
} else {
|
||||
return "MI"
|
||||
}
|
||||
case 3:
|
||||
if invert {
|
||||
return "VC"
|
||||
} else {
|
||||
return "VS"
|
||||
}
|
||||
case 4:
|
||||
if invert {
|
||||
return "LS"
|
||||
} else {
|
||||
return "HI"
|
||||
}
|
||||
case 5:
|
||||
if invert {
|
||||
return "LT"
|
||||
} else {
|
||||
return "GE"
|
||||
}
|
||||
case 6:
|
||||
if invert {
|
||||
return "LE"
|
||||
} else {
|
||||
return "GT"
|
||||
}
|
||||
case 7:
|
||||
return "AL"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// An Imm_c is an integer constant for SYS/SYSL/TLBI instruction.
|
||||
type Imm_c uint8
|
||||
|
||||
func (Imm_c) isArg() {}
|
||||
|
||||
func (i Imm_c) String() string {
|
||||
return fmt.Sprintf("C%d", uint8(i))
|
||||
}
|
||||
|
||||
// An Imm_option is an integer constant for DMB/DSB/ISB instruction.
|
||||
type Imm_option uint8
|
||||
|
||||
func (Imm_option) isArg() {}
|
||||
|
||||
func (i Imm_option) String() string {
|
||||
switch uint8(i) {
|
||||
case 15:
|
||||
return "SY"
|
||||
case 14:
|
||||
return "ST"
|
||||
case 13:
|
||||
return "LD"
|
||||
case 11:
|
||||
return "ISH"
|
||||
case 10:
|
||||
return "ISHST"
|
||||
case 9:
|
||||
return "ISHLD"
|
||||
case 7:
|
||||
return "NSH"
|
||||
case 6:
|
||||
return "NSHST"
|
||||
case 5:
|
||||
return "NSHLD"
|
||||
case 3:
|
||||
return "OSH"
|
||||
case 2:
|
||||
return "OSHST"
|
||||
case 1:
|
||||
return "OSHLD"
|
||||
}
|
||||
return fmt.Sprintf("#%#02x", uint8(i))
|
||||
}
|
||||
|
||||
// An Imm_prfop is an integer constant for PRFM instruction.
|
||||
type Imm_prfop uint8
|
||||
|
||||
func (Imm_prfop) isArg() {}
|
||||
|
||||
func (i Imm_prfop) String() string {
|
||||
prf_type := (i >> 3) & (1<<2 - 1)
|
||||
prf_target := (i >> 1) & (1<<2 - 1)
|
||||
prf_policy := i & 1
|
||||
var result string
|
||||
|
||||
switch prf_type {
|
||||
case 0:
|
||||
result = "PLD"
|
||||
case 1:
|
||||
result = "PLI"
|
||||
case 2:
|
||||
result = "PST"
|
||||
case 3:
|
||||
return fmt.Sprintf("#%#02x", uint8(i))
|
||||
}
|
||||
switch prf_target {
|
||||
case 0:
|
||||
result += "L1"
|
||||
case 1:
|
||||
result += "L2"
|
||||
case 2:
|
||||
result += "L3"
|
||||
case 3:
|
||||
return fmt.Sprintf("#%#02x", uint8(i))
|
||||
}
|
||||
if prf_policy == 0 {
|
||||
result += "KEEP"
|
||||
} else {
|
||||
result += "STRM"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type Pstatefield uint8
|
||||
|
||||
const (
|
||||
SPSel Pstatefield = iota
|
||||
DAIFSet
|
||||
DAIFClr
|
||||
)
|
||||
|
||||
func (Pstatefield) isArg() {}
|
||||
|
||||
func (p Pstatefield) String() string {
|
||||
switch p {
|
||||
case SPSel:
|
||||
return "SPSel"
|
||||
case DAIFSet:
|
||||
return "DAIFSet"
|
||||
case DAIFClr:
|
||||
return "DAIFClr"
|
||||
default:
|
||||
return "unimplemented"
|
||||
}
|
||||
}
|
||||
|
||||
type Systemreg struct {
|
||||
op0 uint8
|
||||
op1 uint8
|
||||
cn uint8
|
||||
cm uint8
|
||||
op2 uint8
|
||||
}
|
||||
|
||||
func (Systemreg) isArg() {}
|
||||
|
||||
func (s Systemreg) String() string {
|
||||
return fmt.Sprintf("S%d_%d_C%d_C%d_%d",
|
||||
s.op0, s.op1, s.cn, s.cm, s.op2)
|
||||
}
|
||||
|
||||
// An Imm_fp is a signed floating-point constant.
|
||||
type Imm_fp struct {
|
||||
s uint8
|
||||
exp int8
|
||||
pre uint8
|
||||
}
|
||||
|
||||
func (Imm_fp) isArg() {}
|
||||
|
||||
func (i Imm_fp) String() string {
|
||||
var s, pre, numerator, denominator int16
|
||||
var result float64
|
||||
if i.s == 0 {
|
||||
s = 1
|
||||
} else {
|
||||
s = -1
|
||||
}
|
||||
pre = s * int16(16+i.pre)
|
||||
if i.exp > 0 {
|
||||
numerator = (pre << uint8(i.exp))
|
||||
denominator = 16
|
||||
} else {
|
||||
numerator = pre
|
||||
denominator = (16 << uint8(-1*i.exp))
|
||||
}
|
||||
result = float64(numerator) / float64(denominator)
|
||||
return fmt.Sprintf("#%.18e", result)
|
||||
}
|
||||
|
||||
type Arrangement uint8
|
||||
|
||||
const (
|
||||
_ Arrangement = iota
|
||||
ArrangementB
|
||||
Arrangement8B
|
||||
Arrangement16B
|
||||
ArrangementH
|
||||
Arrangement4H
|
||||
Arrangement8H
|
||||
ArrangementS
|
||||
Arrangement2S
|
||||
Arrangement4S
|
||||
ArrangementD
|
||||
Arrangement1D
|
||||
Arrangement2D
|
||||
Arrangement1Q
|
||||
)
|
||||
|
||||
func (a Arrangement) String() (result string) {
|
||||
switch a {
|
||||
case ArrangementB:
|
||||
result = ".B"
|
||||
case Arrangement8B:
|
||||
result = ".8B"
|
||||
case Arrangement16B:
|
||||
result = ".16B"
|
||||
case ArrangementH:
|
||||
result = ".H"
|
||||
case Arrangement4H:
|
||||
result = ".4H"
|
||||
case Arrangement8H:
|
||||
result = ".8H"
|
||||
case ArrangementS:
|
||||
result = ".S"
|
||||
case Arrangement2S:
|
||||
result = ".2S"
|
||||
case Arrangement4S:
|
||||
result = ".4S"
|
||||
case ArrangementD:
|
||||
result = ".D"
|
||||
case Arrangement1D:
|
||||
result = ".1D"
|
||||
case Arrangement2D:
|
||||
result = ".2D"
|
||||
case Arrangement1Q:
|
||||
result = ".1Q"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Register with arrangement: <Vd>.<T>, { <Vt>.8B, <Vt2>.8B},
|
||||
type RegisterWithArrangement struct {
|
||||
r Reg
|
||||
a Arrangement
|
||||
cnt uint8
|
||||
}
|
||||
|
||||
func (RegisterWithArrangement) isArg() {}
|
||||
|
||||
func (r RegisterWithArrangement) String() string {
|
||||
result := r.r.String()
|
||||
result += r.a.String()
|
||||
if r.cnt > 0 {
|
||||
result = "{" + result
|
||||
if r.cnt == 2 {
|
||||
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
|
||||
result += ", " + r1.String() + r.a.String()
|
||||
} else if r.cnt > 2 {
|
||||
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
|
||||
for i := 1; i < int(r.cnt); i++ {
|
||||
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
|
||||
result += ", " + cur.String() + r.a.String()
|
||||
}
|
||||
} else {
|
||||
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
|
||||
result += "-" + r1.String() + r.a.String()
|
||||
}
|
||||
}
|
||||
result += "}"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Register with arrangement and index: <Vm>.<Ts>[<index>],
|
||||
// { <Vt>.B, <Vt2>.B }[<index>].
|
||||
type RegisterWithArrangementAndIndex struct {
|
||||
r Reg
|
||||
a Arrangement
|
||||
index uint8
|
||||
cnt uint8
|
||||
}
|
||||
|
||||
func (RegisterWithArrangementAndIndex) isArg() {}
|
||||
|
||||
func (r RegisterWithArrangementAndIndex) String() string {
|
||||
result := r.r.String()
|
||||
result += r.a.String()
|
||||
if r.cnt > 0 {
|
||||
result = "{" + result
|
||||
if r.cnt == 2 {
|
||||
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+1)&31)
|
||||
result += ", " + r1.String() + r.a.String()
|
||||
} else if r.cnt > 2 {
|
||||
if (uint16(r.cnt) + ((uint16(r.r) - uint16(V0)) & 31)) > 32 {
|
||||
for i := 1; i < int(r.cnt); i++ {
|
||||
cur := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(i))&31)
|
||||
result += ", " + cur.String() + r.a.String()
|
||||
}
|
||||
} else {
|
||||
r1 := V0 + Reg((uint16(r.r)-uint16(V0)+uint16(r.cnt)-1)&31)
|
||||
result += "-" + r1.String() + r.a.String()
|
||||
}
|
||||
}
|
||||
result += "}"
|
||||
}
|
||||
return fmt.Sprintf("%s[%d]", result, r.index)
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestObjdumpARM64Testdata(t *testing.T) { testObjdumpARM64(t, testdataCases(t)) }
|
||||
func TestObjdumpARM64Manual(t *testing.T) { testObjdumpARM64(t, hexCases(t, objdumpManualTests)) }
|
||||
func TestObjdumpARM64Cond(t *testing.T) { testObjdumpARM64(t, condCases(t)) }
|
||||
func TestObjdumpARM64(t *testing.T) { testObjdumpARM64(t, JSONCases(t)) }
|
||||
|
||||
// objdumpManualTests holds test cases that will be run by TestObjdumpARMManual.
|
||||
// If you are debugging a few cases that turned up in a longer run, it can be useful
|
||||
// to list them here and then use -run=Manual, particularly with tracing enabled.
|
||||
// Note that these are byte sequences, so they must be reversed from the usual
|
||||
// word presentation.
|
||||
var objdumpManualTests = `
|
||||
bf2003d5
|
||||
9f2003d5
|
||||
7f2003d5
|
||||
5f2003d5
|
||||
3f2003d5
|
||||
1f2003d5
|
||||
df4d03d5
|
||||
ff4d03d5
|
||||
28d91b14
|
||||
da6cb530
|
||||
15e5e514
|
||||
ff4603d5
|
||||
df4803d5
|
||||
bf4100d5
|
||||
9f3f03d5
|
||||
9f3e03d5
|
||||
9f3d03d5
|
||||
9f3b03d5
|
||||
9f3a03d5
|
||||
9f3903d5
|
||||
9f3703d5
|
||||
9f3603d5
|
||||
9f3503d5
|
||||
9f3303d5
|
||||
9f3203d5
|
||||
9f3103d5
|
||||
ff4603d5
|
||||
df4803d5
|
||||
bf4100d5
|
||||
a3681b53
|
||||
47dc78d3
|
||||
0500a012
|
||||
0500e092
|
||||
0500a052
|
||||
0500a0d2
|
||||
cd5a206e
|
||||
cd5a202e
|
||||
743d050e
|
||||
743d0a0e
|
||||
743d0c0e
|
||||
743d084e
|
||||
`
|
||||
|
||||
// allowedMismatchObjdump reports whether the mismatch between text and dec
|
||||
// should be allowed by the test.
|
||||
func allowedMismatchObjdump(text string, inst *Inst, dec ExtInst) bool {
|
||||
// Skip unsupported instructions
|
||||
if hasPrefix(dec.text, todo...) {
|
||||
return true
|
||||
}
|
||||
// GNU objdump has incorrect alias conditions for following instructions
|
||||
if inst.Enc&0x000003ff == 0x000003ff && hasPrefix(dec.text, "negs") && hasPrefix(text, "cmp") {
|
||||
return true
|
||||
}
|
||||
// GNU objdump "NV" is equal to our "AL"
|
||||
if strings.HasSuffix(dec.text, " nv") && strings.HasSuffix(text, " al") {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(dec.text, "b.nv") && strings.HasPrefix(text, "b.al") {
|
||||
return true
|
||||
}
|
||||
// GNU objdump recognizes invalid binaries as following instructions
|
||||
if hasPrefix(dec.text, "hint", "mrs", "msr", "bfc", "orr", "mov") {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(text, "hint") {
|
||||
return true
|
||||
}
|
||||
// GNU objdump recognizes reserved valuse as valid ones
|
||||
if strings.Contains(text, "unknown instruction") && hasPrefix(dec.text, "fmla", "fmul", "fmulx", "fcvtzs", "fcvtzu", "fmls", "fmov", "scvtf", "ucvtf") {
|
||||
return true
|
||||
}
|
||||
// GNU objdump misses spaces between operands for some instructions (e.g., "ld1 {v10.2s, v11.2s}, [x23],#16")
|
||||
if strings.Replace(text, " ", "", -1) == strings.Replace(dec.text, " ", "", -1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: system instruction.
|
||||
var todo = strings.Fields(`
|
||||
sys
|
||||
dc
|
||||
at
|
||||
tlbi
|
||||
ic
|
||||
hvc
|
||||
smc
|
||||
`)
|
||||
|
||||
// Following instructions can't be covered because they are just aliases to another instructions which are always preferred
|
||||
var Ncover = strings.Fields(`
|
||||
sbfm
|
||||
asrv
|
||||
bfm
|
||||
ubfm
|
||||
lslv
|
||||
lsrv
|
||||
rorv
|
||||
ins
|
||||
dup
|
||||
`)
|
|
@ -0,0 +1,299 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copied and simplified from ../../arm/armasm/objdumpext_test.go.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const objdumpPath = "/usr/bin/objdump"
|
||||
|
||||
func testObjdumpARM64(t *testing.T, generate func(func([]byte))) {
|
||||
testObjdumpArch(t, generate, ModeARM64)
|
||||
}
|
||||
|
||||
func testObjdumpArch(t *testing.T, generate func(func([]byte)), arch Mode) {
|
||||
if _, err := os.Stat(objdumpPath); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
// Check objdump can disassemble elf64-aarch64.
|
||||
if test := objdumpinfo(); test == false {
|
||||
t.Skip("Skip the test if installed objdump doesn't support aarch64 elf format")
|
||||
}
|
||||
testExtDis(t, "gnu", arch, objdump, generate, allowedMismatchObjdump)
|
||||
testExtDis(t, "plan9", arch, objdump, generate, allowedMismatchObjdump)
|
||||
}
|
||||
|
||||
func objdumpinfo() bool {
|
||||
var i = []byte("aarch64")
|
||||
out, err := exec.Command(objdumpPath, "-i").Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if bytes.Contains(out, i) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func objdump(ext *ExtDis) error {
|
||||
// File already written with instructions; add ELF header.
|
||||
if ext.Arch == ModeARM64 {
|
||||
if err := writeELF64(ext.File, ext.Size); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
panic("unknown arch")
|
||||
}
|
||||
|
||||
b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
nmatch int
|
||||
reading bool
|
||||
next uint64 = start
|
||||
addr uint64
|
||||
encbuf [4]byte
|
||||
enc []byte
|
||||
text string
|
||||
)
|
||||
flush := func() {
|
||||
if addr == next {
|
||||
// PC-relative addresses are translated to absolute addresses based on PC by GNU objdump
|
||||
// Following logical rewrites the absolute addresses back to PC-relative ones for comparing
|
||||
// with our disassembler output which are PC-relative
|
||||
|
||||
if m := pcrelprfmim.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
if m := pcrelprfm.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
if m := pcrelim.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
if m := pcrelimzr.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
if m := pcrelr.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
if strings.Contains(m[1], "adrp") {
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr&0xfffff000)))
|
||||
} else {
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
}
|
||||
if m := pcrelrzr.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
if strings.Contains(m[1], "adrp") {
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr&0xfffff000)))
|
||||
} else {
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
}
|
||||
if m := pcrel.FindStringSubmatch(text); m != nil {
|
||||
targ, _ := strconv.ParseUint(m[2], 16, 64)
|
||||
text = fmt.Sprintf("%s .%+#x", m[1], uint64(targ-uint64(addr)))
|
||||
}
|
||||
if strings.HasPrefix(text, "mov") && strings.Contains(text, "//") {
|
||||
s := strings.Split(text, " //")
|
||||
text = s[0]
|
||||
}
|
||||
text = strings.Replace(text, "#0.0", "#0", -1)
|
||||
if text == "undefined" && len(enc) == 4 {
|
||||
text = "error: unknown instruction"
|
||||
enc = nil
|
||||
}
|
||||
if len(enc) == 4 {
|
||||
// prints as word but we want to record bytes
|
||||
enc[0], enc[3] = enc[3], enc[0]
|
||||
enc[1], enc[2] = enc[2], enc[1]
|
||||
}
|
||||
ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
|
||||
encbuf = [4]byte{}
|
||||
enc = nil
|
||||
next += 4
|
||||
}
|
||||
}
|
||||
var textangle = []byte("<.text>:")
|
||||
for {
|
||||
line, err := b.ReadSlice('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("reading objdump output: %v", err)
|
||||
}
|
||||
if bytes.Contains(line, textangle) {
|
||||
reading = true
|
||||
continue
|
||||
}
|
||||
if !reading {
|
||||
continue
|
||||
}
|
||||
if debug {
|
||||
os.Stdout.Write(line)
|
||||
}
|
||||
if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
|
||||
enc = enc1
|
||||
continue
|
||||
}
|
||||
flush()
|
||||
nmatch++
|
||||
addr, enc, text = parseLine(line, encbuf[:0])
|
||||
if addr > next {
|
||||
return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
|
||||
}
|
||||
}
|
||||
flush()
|
||||
if next != start+uint64(ext.Size) {
|
||||
return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
|
||||
}
|
||||
if err := ext.Wait(); err != nil {
|
||||
return fmt.Errorf("exec: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
undefined = []byte("undefined")
|
||||
unpredictable = []byte("unpredictable")
|
||||
)
|
||||
|
||||
func parseLine(line []byte, encstart []byte) (addr uint64, enc []byte, text string) {
|
||||
ok := false
|
||||
oline := line
|
||||
i := index(line, ":\t")
|
||||
if i < 0 {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
x, err := strconv.ParseUint(string(bytes.TrimSpace(line[:i])), 16, 32)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
addr = uint64(x)
|
||||
line = line[i+2:]
|
||||
i = bytes.IndexByte(line, '\t')
|
||||
if i < 0 {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
enc, ok = parseHex(line[:i], encstart)
|
||||
if !ok {
|
||||
log.Fatalf("cannot parse disassembly: %q", oline)
|
||||
}
|
||||
line = bytes.TrimSpace(line[i:])
|
||||
if bytes.Contains(line, undefined) {
|
||||
text = "undefined"
|
||||
return
|
||||
}
|
||||
if false && bytes.Contains(line, unpredictable) {
|
||||
text = "unpredictable"
|
||||
return
|
||||
}
|
||||
if i := bytes.IndexByte(line, ';'); i >= 0 {
|
||||
line = bytes.TrimSpace(line[:i])
|
||||
}
|
||||
text = string(fixSpace(line))
|
||||
return
|
||||
}
|
||||
|
||||
func parseContinuation(line []byte, enc []byte) []byte {
|
||||
i := index(line, ":\t")
|
||||
if i < 0 {
|
||||
return nil
|
||||
}
|
||||
line = line[i+1:]
|
||||
enc, _ = parseHex(line, enc)
|
||||
return enc
|
||||
}
|
||||
|
||||
// writeELF64 writes an ELF64 header to the file, describing a text
|
||||
// segment that starts at start (0x8000) and extends for size bytes.
|
||||
func writeELF64(f *os.File, size int) error {
|
||||
f.Seek(0, 0)
|
||||
var hdr elf.Header64
|
||||
var prog elf.Prog64
|
||||
var sect elf.Section64
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, &hdr)
|
||||
off1 := buf.Len()
|
||||
binary.Write(&buf, binary.LittleEndian, &prog)
|
||||
off2 := buf.Len()
|
||||
binary.Write(&buf, binary.LittleEndian, §)
|
||||
off3 := buf.Len()
|
||||
buf.Reset()
|
||||
data := byte(elf.ELFDATA2LSB)
|
||||
hdr = elf.Header64{
|
||||
Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
|
||||
Type: 2,
|
||||
Machine: uint16(elf.EM_AARCH64),
|
||||
Version: 1,
|
||||
Entry: start,
|
||||
Phoff: uint64(off1),
|
||||
Shoff: uint64(off2),
|
||||
Flags: 0x05000002,
|
||||
Ehsize: uint16(off1),
|
||||
Phentsize: uint16(off2 - off1),
|
||||
Phnum: 1,
|
||||
Shentsize: uint16(off3 - off2),
|
||||
Shnum: 3,
|
||||
Shstrndx: 2,
|
||||
}
|
||||
binary.Write(&buf, binary.LittleEndian, &hdr)
|
||||
prog = elf.Prog64{
|
||||
Type: 1,
|
||||
Off: start,
|
||||
Vaddr: start,
|
||||
Paddr: start,
|
||||
Filesz: uint64(size),
|
||||
Memsz: uint64(size),
|
||||
Flags: 5,
|
||||
Align: start,
|
||||
}
|
||||
binary.Write(&buf, binary.LittleEndian, &prog)
|
||||
binary.Write(&buf, binary.LittleEndian, §) // NULL section
|
||||
sect = elf.Section64{
|
||||
Name: 1,
|
||||
Type: uint32(elf.SHT_PROGBITS),
|
||||
Addr: start,
|
||||
Off: start,
|
||||
Size: uint64(size),
|
||||
Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
|
||||
Addralign: 4,
|
||||
}
|
||||
binary.Write(&buf, binary.LittleEndian, §) // .text
|
||||
sect = elf.Section64{
|
||||
Name: uint32(len("\x00.text\x00")),
|
||||
Type: uint32(elf.SHT_STRTAB),
|
||||
Addr: 0,
|
||||
Off: uint64(off2 + (off3-off2)*3),
|
||||
Size: uint64(len("\x00.text\x00.shstrtab\x00")),
|
||||
Addralign: 1,
|
||||
}
|
||||
binary.Write(&buf, binary.LittleEndian, §)
|
||||
buf.WriteString("\x00.text\x00.shstrtab\x00")
|
||||
f.Write(buf.Bytes())
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,611 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm64asm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GoSyntax returns the Go assembler syntax for the instruction.
|
||||
// The syntax was originally defined by Plan 9.
|
||||
// The pc is the program counter of the instruction, used for
|
||||
// expanding PC-relative addresses into absolute ones.
|
||||
// The symname function queries the symbol table for the program
|
||||
// being disassembled. Given a target address it returns the name
|
||||
// and base address of the symbol containing the target, if any;
|
||||
// otherwise it returns "", 0.
|
||||
// The reader text should read from the text segment using text addresses
|
||||
// as offsets; it is used to display pc-relative loads as constant loads.
|
||||
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
|
||||
if symname == nil {
|
||||
symname = func(uint64) (string, uint64) { return "", 0 }
|
||||
}
|
||||
|
||||
var args []string
|
||||
for _, a := range inst.Args {
|
||||
if a == nil {
|
||||
break
|
||||
}
|
||||
args = append(args, plan9Arg(&inst, pc, symname, a))
|
||||
}
|
||||
|
||||
op := inst.Op.String()
|
||||
|
||||
switch inst.Op {
|
||||
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW:
|
||||
// Check for PC-relative load.
|
||||
if offset, ok := inst.Args[1].(PCRel); ok {
|
||||
addr := pc + uint64(offset)
|
||||
if _, ok := inst.Args[0].(Reg); !ok {
|
||||
break
|
||||
}
|
||||
if s, base := symname(addr); s != "" && addr == base {
|
||||
args[1] = fmt.Sprintf("$%s(SB)", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move addressing mode into opcode suffix.
|
||||
suffix := ""
|
||||
switch inst.Op {
|
||||
case LDR, LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH, STUR, STURB, STURH, LD1:
|
||||
switch mem := inst.Args[1].(type) {
|
||||
case MemImmediate:
|
||||
switch mem.Mode {
|
||||
case AddrOffset:
|
||||
// no suffix
|
||||
case AddrPreIndex:
|
||||
suffix = ".W"
|
||||
case AddrPostIndex, AddrPostReg:
|
||||
suffix = ".P"
|
||||
}
|
||||
}
|
||||
|
||||
case STP, LDP:
|
||||
switch mem := inst.Args[2].(type) {
|
||||
case MemImmediate:
|
||||
switch mem.Mode {
|
||||
case AddrOffset:
|
||||
// no suffix
|
||||
case AddrPreIndex:
|
||||
suffix = ".W"
|
||||
case AddrPostIndex:
|
||||
suffix = ".P"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch inst.Op {
|
||||
case BL:
|
||||
return "CALL " + args[0]
|
||||
|
||||
case BLR:
|
||||
r := inst.Args[0].(Reg)
|
||||
regno := uint16(r) & 31
|
||||
return fmt.Sprintf("CALL (R%d)", regno)
|
||||
|
||||
case RET:
|
||||
if r, ok := inst.Args[0].(Reg); ok && r == X30 {
|
||||
return "RET"
|
||||
}
|
||||
|
||||
case B:
|
||||
if cond, ok := inst.Args[0].(Cond); ok {
|
||||
return "B" + cond.String() + " " + args[1]
|
||||
}
|
||||
return "JMP" + " " + args[0]
|
||||
|
||||
case BR:
|
||||
r := inst.Args[0].(Reg)
|
||||
regno := uint16(r) & 31
|
||||
return fmt.Sprintf("JMP (R%d)", regno)
|
||||
|
||||
case MOV:
|
||||
rno := -1
|
||||
switch a := inst.Args[0].(type) {
|
||||
case Reg:
|
||||
rno = int(a)
|
||||
case RegSP:
|
||||
rno = int(a)
|
||||
case RegisterWithArrangementAndIndex:
|
||||
op = "VMOV"
|
||||
}
|
||||
if rno >= 0 && rno <= int(WZR) {
|
||||
op = "MOVW"
|
||||
} else if rno >= int(X0) && rno <= int(XZR) {
|
||||
op = "MOVD"
|
||||
}
|
||||
if _, ok := inst.Args[1].(RegisterWithArrangementAndIndex); ok {
|
||||
op = "VMOV"
|
||||
}
|
||||
|
||||
case LDR:
|
||||
var rno uint16
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno = uint16(r)
|
||||
} else {
|
||||
rno = uint16(inst.Args[0].(RegSP))
|
||||
}
|
||||
if rno <= uint16(WZR) {
|
||||
op = "MOVWU" + suffix
|
||||
} else {
|
||||
op = "MOVD" + suffix
|
||||
}
|
||||
|
||||
case LDRB:
|
||||
op = "MOVBU" + suffix
|
||||
|
||||
case LDRH:
|
||||
op = "MOVHU" + suffix
|
||||
|
||||
case LDRSW:
|
||||
op = "MOVW" + suffix
|
||||
|
||||
case LDRSB:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op = "MOVBW" + suffix
|
||||
} else {
|
||||
op = "MOVB" + suffix
|
||||
}
|
||||
}
|
||||
case LDRSH:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op = "MOVHW" + suffix
|
||||
} else {
|
||||
op = "MOVH" + suffix
|
||||
}
|
||||
}
|
||||
case STR, STUR:
|
||||
var rno uint16
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno = uint16(r)
|
||||
} else {
|
||||
rno = uint16(inst.Args[0].(RegSP))
|
||||
}
|
||||
if rno <= uint16(WZR) {
|
||||
op = "MOVW" + suffix
|
||||
} else {
|
||||
op = "MOVD" + suffix
|
||||
}
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case STRB, STURB:
|
||||
op = "MOVB" + suffix
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case STRH, STURH:
|
||||
op = "MOVH" + suffix
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case TBNZ, TBZ:
|
||||
args[0], args[1], args[2] = args[2], args[0], args[1]
|
||||
|
||||
case MADD, MSUB, SMADDL, SMSUBL, UMADDL, UMSUBL:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
args[2], args[3] = args[3], args[2]
|
||||
case STLR:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case STLRB, STLRH:
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case STLXR, STXR:
|
||||
if r, ok := inst.Args[1].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
args[1], args[2] = args[2], args[1]
|
||||
|
||||
case STLXRB, STLXRH, STXRB, STXRH:
|
||||
args[1], args[2] = args[2], args[1]
|
||||
|
||||
case BFI, BFXIL, SBFIZ, SBFX, UBFIZ, UBFX:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
args[1], args[2], args[3] = args[3], args[1], args[2]
|
||||
|
||||
case STP, LDP:
|
||||
args[0] = fmt.Sprintf("(%s, %s)", args[0], args[1])
|
||||
args[1] = args[2]
|
||||
if op == "STP" {
|
||||
op = op + suffix
|
||||
return op + " " + args[0] + ", " + args[1]
|
||||
} else if op == "LDP" {
|
||||
op = op + suffix
|
||||
return op + " " + args[1] + ", " + args[0]
|
||||
}
|
||||
|
||||
case FCCMP, FCCMPE:
|
||||
args[0], args[1] = args[1], args[0]
|
||||
fallthrough
|
||||
|
||||
case FCMP, FCMPE:
|
||||
if _, ok := inst.Args[1].(Imm); ok {
|
||||
args[1] = "$(0.0)"
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case FADD, FSUB, FMUL, FNMUL, FDIV, FMAX, FMIN, FMAXNM, FMINNM, FCSEL:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno >= uint16(S0) && rno <= uint16(S31) {
|
||||
op = fmt.Sprintf("%sS", op)
|
||||
} else if rno >= uint16(D0) && rno <= uint16(D31) {
|
||||
op = fmt.Sprintf("%sD", op)
|
||||
}
|
||||
}
|
||||
|
||||
case FCVT:
|
||||
for i := 1; i >= 0; i-- {
|
||||
if r, ok := inst.Args[i].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno >= uint16(H0) && rno <= uint16(H31) {
|
||||
op = fmt.Sprintf("%sH", op)
|
||||
} else if rno >= uint16(S0) && rno <= uint16(S31) {
|
||||
op = fmt.Sprintf("%sS", op)
|
||||
} else if rno >= uint16(D0) && rno <= uint16(D31) {
|
||||
op = fmt.Sprintf("%sD", op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case FABS, FNEG, FSQRT, FRINTN, FRINTP, FRINTM, FRINTZ, FRINTA, FRINTX, FRINTI:
|
||||
if r, ok := inst.Args[1].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno >= uint16(S0) && rno <= uint16(S31) {
|
||||
op = fmt.Sprintf("%sS", op)
|
||||
} else if rno >= uint16(D0) && rno <= uint16(D31) {
|
||||
op = fmt.Sprintf("%sD", op)
|
||||
}
|
||||
}
|
||||
|
||||
case FCVTZS, FCVTZU, SCVTF, UCVTF:
|
||||
if _, ok := inst.Args[2].(Imm); !ok {
|
||||
for i := 1; i >= 0; i-- {
|
||||
if r, ok := inst.Args[i].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno >= uint16(S0) && rno <= uint16(S31) {
|
||||
op = fmt.Sprintf("%sS", op)
|
||||
} else if rno >= uint16(D0) && rno <= uint16(D31) {
|
||||
op = fmt.Sprintf("%sD", op)
|
||||
} else if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case FMOV:
|
||||
for i := 0; i <= 1; i++ {
|
||||
if r, ok := inst.Args[i].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno >= uint16(S0) && rno <= uint16(S31) {
|
||||
op = fmt.Sprintf("%sS", op)
|
||||
break
|
||||
} else if rno >= uint16(D0) && rno <= uint16(D31) {
|
||||
op = fmt.Sprintf("%sD", op)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case SYSL:
|
||||
op1 := int(inst.Args[1].(Imm).Imm)
|
||||
cn := int(inst.Args[2].(Imm_c))
|
||||
cm := int(inst.Args[3].(Imm_c))
|
||||
op2 := int(inst.Args[4].(Imm).Imm)
|
||||
sysregno := int32(op1<<16 | cn<<12 | cm<<8 | op2<<5)
|
||||
args[1] = fmt.Sprintf("$%d", sysregno)
|
||||
return op + " " + args[1] + ", " + args[0]
|
||||
|
||||
case CBNZ, CBZ:
|
||||
if r, ok := inst.Args[0].(Reg); ok {
|
||||
rno := uint16(r)
|
||||
if rno <= uint16(WZR) {
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
args[0], args[1] = args[1], args[0]
|
||||
|
||||
case ADR, ADRP:
|
||||
addr := int64(inst.Args[1].(PCRel))
|
||||
args[1] = fmt.Sprintf("%d(PC)", addr)
|
||||
|
||||
default:
|
||||
index := sort.SearchStrings(noSuffixOpSet, op)
|
||||
if !(index < len(noSuffixOpSet) && noSuffixOpSet[index] == op) {
|
||||
rno := -1
|
||||
switch a := inst.Args[0].(type) {
|
||||
case Reg:
|
||||
rno = int(a)
|
||||
case RegSP:
|
||||
rno = int(a)
|
||||
case RegisterWithArrangement:
|
||||
op = fmt.Sprintf("V%s", op)
|
||||
}
|
||||
|
||||
if rno >= 0 && rno <= int(WZR) {
|
||||
// Add "w" to opcode suffix.
|
||||
op += "W"
|
||||
}
|
||||
}
|
||||
op = op + suffix
|
||||
}
|
||||
|
||||
// conditional instructions, replace args.
|
||||
if _, ok := inst.Args[3].(Cond); ok {
|
||||
if _, ok := inst.Args[2].(Reg); ok {
|
||||
args[1], args[2] = args[2], args[1]
|
||||
} else {
|
||||
args[0], args[2] = args[2], args[0]
|
||||
}
|
||||
}
|
||||
// Reverse args, placing dest last.
|
||||
for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
|
||||
args[i], args[j] = args[j], args[i]
|
||||
}
|
||||
|
||||
if args != nil {
|
||||
op += " " + strings.Join(args, ", ")
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
// No need add "W" to opcode suffix.
|
||||
// Opcode must be inserted in ascending order.
|
||||
var noSuffixOpSet = strings.Fields(`
|
||||
CRC32B
|
||||
CRC32CB
|
||||
CRC32CH
|
||||
CRC32CW
|
||||
CRC32CX
|
||||
CRC32H
|
||||
CRC32W
|
||||
CRC32X
|
||||
LDARB
|
||||
LDARH
|
||||
LDAXRB
|
||||
LDAXRH
|
||||
LDXRB
|
||||
LDXRH
|
||||
`)
|
||||
|
||||
func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
|
||||
switch a := arg.(type) {
|
||||
case Imm:
|
||||
return fmt.Sprintf("$%d", uint32(a.Imm))
|
||||
|
||||
case Imm64:
|
||||
return fmt.Sprintf("$%d", int64(a.Imm))
|
||||
|
||||
case ImmShift:
|
||||
if a.shift == 0 {
|
||||
return fmt.Sprintf("$%d", a.imm)
|
||||
}
|
||||
return fmt.Sprintf("$(%d<<%d)", a.imm, a.shift)
|
||||
|
||||
case PCRel:
|
||||
addr := int64(pc) + int64(a)
|
||||
if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
|
||||
return fmt.Sprintf("%s(SB)", s)
|
||||
}
|
||||
return fmt.Sprintf("%d(PC)", a/4)
|
||||
|
||||
case Reg:
|
||||
regenum := uint16(a)
|
||||
regno := uint16(a) & 31
|
||||
|
||||
if regenum >= uint16(B0) && regenum <= uint16(D31) {
|
||||
// FP registers are the same ones as SIMD registers
|
||||
// Print Fn for scalar variant to align with assembler (e.g., FCVT)
|
||||
return fmt.Sprintf("F%d", regno)
|
||||
} else if regenum >= uint16(Q0) && regenum <= uint16(Q31) {
|
||||
// Print Vn to align with assembler (e.g., SHA256H)
|
||||
return fmt.Sprintf("V%d", regno)
|
||||
}
|
||||
|
||||
if regno == 31 {
|
||||
return "ZR"
|
||||
}
|
||||
return fmt.Sprintf("R%d", regno)
|
||||
|
||||
case RegSP:
|
||||
regno := uint16(a) & 31
|
||||
if regno == 31 {
|
||||
return "RSP"
|
||||
}
|
||||
return fmt.Sprintf("R%d", regno)
|
||||
|
||||
case RegExtshiftAmount:
|
||||
reg := ""
|
||||
regno := uint16(a.reg) & 31
|
||||
if regno == 31 {
|
||||
reg = "ZR"
|
||||
} else {
|
||||
reg = fmt.Sprintf("R%d", uint16(a.reg)&31)
|
||||
}
|
||||
extshift := ""
|
||||
amount := ""
|
||||
if a.extShift != ExtShift(0) {
|
||||
switch a.extShift {
|
||||
default:
|
||||
extshift = "." + a.extShift.String()
|
||||
|
||||
case lsl:
|
||||
extshift = "<<"
|
||||
amount = fmt.Sprintf("%d", a.amount)
|
||||
return reg + extshift + amount
|
||||
|
||||
case lsr:
|
||||
extshift = ">>"
|
||||
amount = fmt.Sprintf("%d", a.amount)
|
||||
return reg + extshift + amount
|
||||
|
||||
case asr:
|
||||
extshift = "->"
|
||||
amount = fmt.Sprintf("%d", a.amount)
|
||||
return reg + extshift + amount
|
||||
case ror:
|
||||
extshift = "@>"
|
||||
amount = fmt.Sprintf("%d", a.amount)
|
||||
return reg + extshift + amount
|
||||
}
|
||||
if a.amount != 0 {
|
||||
amount = fmt.Sprintf("<<%d", a.amount)
|
||||
}
|
||||
}
|
||||
return reg + extshift + amount
|
||||
|
||||
case MemImmediate:
|
||||
off := ""
|
||||
base := ""
|
||||
regno := uint16(a.Base) & 31
|
||||
if regno == 31 {
|
||||
base = "(RSP)"
|
||||
} else {
|
||||
base = fmt.Sprintf("(R%d)", regno)
|
||||
}
|
||||
if a.imm != 0 && a.Mode != AddrPostReg {
|
||||
off = fmt.Sprintf("%d", a.imm)
|
||||
} else if a.Mode == AddrPostReg {
|
||||
postR := fmt.Sprintf("(R%d)", a.imm)
|
||||
return base + postR
|
||||
}
|
||||
return off + base
|
||||
|
||||
case MemExtend:
|
||||
base := ""
|
||||
index := ""
|
||||
extend := ""
|
||||
indexreg := ""
|
||||
regno := uint16(a.Base) & 31
|
||||
if regno == 31 {
|
||||
base = "(RSP)"
|
||||
} else {
|
||||
base = fmt.Sprintf("(R%d)", regno)
|
||||
}
|
||||
regno = uint16(a.Index) & 31
|
||||
if regno == 31 {
|
||||
indexreg = "ZR"
|
||||
} else {
|
||||
indexreg = fmt.Sprintf("R%d", regno)
|
||||
}
|
||||
if a.Extend == lsl {
|
||||
if a.Amount != 0 {
|
||||
extend = fmt.Sprintf("<<%d", a.Amount)
|
||||
}
|
||||
} else {
|
||||
extend = "unimplemented!"
|
||||
}
|
||||
index = indexreg + extend
|
||||
return index + base
|
||||
|
||||
case Cond:
|
||||
switch arg.String() {
|
||||
case "CS":
|
||||
return "HS"
|
||||
case "CC":
|
||||
return "LO"
|
||||
}
|
||||
|
||||
case Imm_clrex:
|
||||
return fmt.Sprintf("$%d", uint32(a))
|
||||
|
||||
case Imm_dcps:
|
||||
return fmt.Sprintf("$%d", uint32(a))
|
||||
|
||||
case Imm_option:
|
||||
return fmt.Sprintf("$%d", uint8(a))
|
||||
|
||||
case Imm_hint:
|
||||
return fmt.Sprintf("$%d", uint8(a))
|
||||
|
||||
case Imm_fp:
|
||||
var s, pre, numerator, denominator int16
|
||||
var result float64
|
||||
if a.s == 0 {
|
||||
s = 1
|
||||
} else {
|
||||
s = -1
|
||||
}
|
||||
pre = s * int16(16+a.pre)
|
||||
if a.exp > 0 {
|
||||
numerator = (pre << uint8(a.exp))
|
||||
denominator = 16
|
||||
} else {
|
||||
numerator = pre
|
||||
denominator = (16 << uint8(-1*a.exp))
|
||||
}
|
||||
result = float64(numerator) / float64(denominator)
|
||||
return strings.TrimRight(fmt.Sprintf("$%f", result), "0")
|
||||
|
||||
case RegisterWithArrangement:
|
||||
result := a.r.String()
|
||||
arrange := a.a.String()
|
||||
c := []rune(arrange)
|
||||
switch len(c) {
|
||||
case 3:
|
||||
c[1], c[2] = c[2], c[1] // .8B -> .B8
|
||||
case 4:
|
||||
c[1], c[2], c[3] = c[3], c[1], c[2] // 16B -> B16
|
||||
}
|
||||
arrange = string(c)
|
||||
result += arrange
|
||||
if a.cnt > 0 {
|
||||
result = "[" + result
|
||||
for i := 1; i < int(a.cnt); i++ {
|
||||
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
|
||||
result += ", " + cur.String() + arrange
|
||||
}
|
||||
result += "]"
|
||||
}
|
||||
return result
|
||||
|
||||
case RegisterWithArrangementAndIndex:
|
||||
result := a.r.String()
|
||||
arrange := a.a.String()
|
||||
result += arrange
|
||||
if a.cnt > 0 {
|
||||
result = "[" + result
|
||||
for i := 1; i < int(a.cnt); i++ {
|
||||
cur := V0 + Reg((uint16(a.r)-uint16(V0)+uint16(i))&31)
|
||||
result += ", " + cur.String() + arrange
|
||||
}
|
||||
result += "]"
|
||||
}
|
||||
return fmt.Sprintf("%s[%d]", result, a.index)
|
||||
|
||||
case Systemreg:
|
||||
return fmt.Sprintf("$%d", uint32(a.op0&1)<<14|uint32(a.op1&7)<<11|uint32(a.cn&15)<<7|uint32(a.cm&15)<<3|uint32(a.op2)&7)
|
||||
|
||||
}
|
||||
|
||||
return strings.ToUpper(arg.String())
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,7 @@
|
|||
go test command:
|
||||
cd ..; go test -run 'ObjdumpARM64Cond' -v -timeout 10h -long 2>&1 | tee log
|
||||
cd ..; go test -run 'ObjdumpARM64Testdata' -v -timeout 10h -long 2>&1 | tee -a log
|
||||
cd ..; go test -run 'ObjdumpARM64' -v -timeout 10h -long 2>&1 | tee -a log
|
||||
cd ..; go test -run 'ObjdumpARM64Manual' -v -timeout 10h -long 2>&1 | tee -a log
|
||||
cd ..; go test -run 'TestDecode'
|
||||
cd ..; go test -run '.*'
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,714 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// arm64spec reads the ``ARMv8-A Reference Manual''
|
||||
// to collect instruction encoding details and writes those
|
||||
// details to standard output in JSON format.
|
||||
// usage: arm64spec file.pdf
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"rsc.io/pdf"
|
||||
)
|
||||
|
||||
type Inst struct {
|
||||
Name string
|
||||
Bits string
|
||||
Arch string
|
||||
Syntax string
|
||||
Code string
|
||||
Alias string
|
||||
}
|
||||
|
||||
const debugPage = 0
|
||||
|
||||
var stdout *bufio.Writer
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("arm64spec: ")
|
||||
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "usage: arm64spec file.pdf\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
f, err := pdf.Open(os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Find instruction set reference in outline, to build instruction list.
|
||||
instList := instHeadings(f.Outline())
|
||||
if debugPage == 0 {
|
||||
fmt.Println("the number of instructions:", len(instList))
|
||||
}
|
||||
if len(instList) < 200 {
|
||||
log.Fatalf("only found %d instructions in table of contents", len(instList))
|
||||
}
|
||||
|
||||
file, err := os.Create("inst.json")
|
||||
check(err)
|
||||
w := bufio.NewWriter(file)
|
||||
_, err = w.WriteString("[")
|
||||
check(err)
|
||||
numTable := 0
|
||||
defer w.Flush()
|
||||
defer file.Close()
|
||||
|
||||
// Scan document looking for instructions.
|
||||
// Must find exactly the ones in the outline.
|
||||
n := f.NumPage()
|
||||
PageLoop:
|
||||
for pageNum := 435; pageNum <= n; pageNum++ {
|
||||
if debugPage > 0 && pageNum != debugPage {
|
||||
continue
|
||||
}
|
||||
if pageNum == 770 {
|
||||
continue
|
||||
}
|
||||
if pageNum > 1495 {
|
||||
break
|
||||
}
|
||||
p := f.Page(pageNum)
|
||||
name, table := parsePage(pageNum, p, f)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if len(table) < 1 {
|
||||
if false {
|
||||
fmt.Fprintf(os.Stderr, "no encodings for instruction %q (page %d)\n", name, pageNum)
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, inst := range table {
|
||||
if numTable > 0 {
|
||||
_, err = w.WriteString(jsFix.Replace(","))
|
||||
check(err)
|
||||
_, err = w.WriteString("\n")
|
||||
check(err)
|
||||
}
|
||||
numTable++
|
||||
js, _ := json.Marshal(inst)
|
||||
_, err = w.WriteString(jsFix.Replace(string(js)))
|
||||
check(err)
|
||||
}
|
||||
for j, headline := range instList {
|
||||
if name == headline {
|
||||
instList[j] = ""
|
||||
continue PageLoop
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "unexpected instruction %q (page %d)\n", name, pageNum)
|
||||
}
|
||||
|
||||
_, err = w.WriteString("\n]\n")
|
||||
check(err)
|
||||
w.Flush()
|
||||
|
||||
if debugPage == 0 {
|
||||
for _, headline := range instList {
|
||||
if headline != "" {
|
||||
fmt.Fprintf(os.Stderr, "missing instruction %q\n", headline)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func instHeadings(outline pdf.Outline) []string {
|
||||
return appendInstHeadings(outline, nil)
|
||||
}
|
||||
|
||||
var instRE = regexp.MustCompile(`C[\d.]+ Alphabetical list of A64 base instructions`)
|
||||
var instRE_A = regexp.MustCompile(`C[\d.]+ Alphabetical list of A64 floating-point and Advanced SIMD instructions`)
|
||||
var childRE = regexp.MustCompile(`C[\d.]+ (.+)`)
|
||||
var sectionRE = regexp.MustCompile(`^C[\d.]+$`)
|
||||
var bitRE = regexp.MustCompile(`^( |[01]|\([01]\))*$`)
|
||||
var IMMRE = regexp.MustCompile(`^imm[\d]+$`)
|
||||
|
||||
func appendInstHeadings(outline pdf.Outline, list []string) []string {
|
||||
if instRE.MatchString(outline.Title) || instRE_A.MatchString(outline.Title) {
|
||||
for _, child := range outline.Child {
|
||||
m := childRE.FindStringSubmatch(child.Title)
|
||||
if m == nil {
|
||||
fmt.Fprintf(os.Stderr, "cannot parse section title: %s\n", child.Title)
|
||||
continue
|
||||
}
|
||||
list = append(list, m[1])
|
||||
}
|
||||
}
|
||||
for _, child := range outline.Child {
|
||||
list = appendInstHeadings(child, list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
const inch = 72.0
|
||||
|
||||
func parsePage(num int, p pdf.Page, f *pdf.Reader) (name string, table []Inst) {
|
||||
content := p.Content()
|
||||
var text []pdf.Text
|
||||
CrossTwoPage := true
|
||||
for _, t := range content.Text {
|
||||
text = append(text, t)
|
||||
}
|
||||
text = findWords(text)
|
||||
if !(instRE.MatchString(text[1].S) || instRE_A.MatchString(text[1].S)) || len(text) == 0 || !sectionRE.MatchString(text[2].S) {
|
||||
return "", nil
|
||||
}
|
||||
// Check whether the content crosses the page.
|
||||
for _, t := range text {
|
||||
if match(t, "Arial,Bold", 10, "Assembler symbols") {
|
||||
CrossTwoPage = false
|
||||
break
|
||||
}
|
||||
}
|
||||
// Deal with cross page issue. To the next page content.
|
||||
var Ncontent pdf.Content
|
||||
Npagebox := false
|
||||
CrossThreePage := false
|
||||
Noffset := ""
|
||||
if CrossTwoPage == true {
|
||||
Np := f.Page(num + 1)
|
||||
Ncontent = Np.Content()
|
||||
var Ntext []pdf.Text
|
||||
for _, t := range Ncontent.Text {
|
||||
Ntext = append(Ntext, t)
|
||||
}
|
||||
Ntext = findWords(Ntext)
|
||||
if len(Ntext) == 0 || sectionRE.MatchString(Ntext[2].S) {
|
||||
Ntext = text[:0]
|
||||
} else {
|
||||
for _, t := range Ntext {
|
||||
if match(t, "Arial,Bold", 10, "offset") {
|
||||
Noffset = t.S
|
||||
Npagebox = true
|
||||
}
|
||||
// This istruction cross three pages.
|
||||
if match(t, "Arial,Bold", 10, "Assembler symbols") {
|
||||
CrossThreePage = false
|
||||
} else {
|
||||
CrossThreePage = true
|
||||
}
|
||||
text = append(text, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
if CrossThreePage == true {
|
||||
NNp := f.Page(num + 2)
|
||||
NNcontent := NNp.Content()
|
||||
var NNtext []pdf.Text
|
||||
for _, t := range NNcontent.Text {
|
||||
NNtext = append(NNtext, t)
|
||||
}
|
||||
NNtext = findWords(NNtext)
|
||||
if len(NNtext) == 0 || sectionRE.MatchString(NNtext[2].S) {
|
||||
NNtext = text[:0]
|
||||
} else {
|
||||
for _, t := range NNtext {
|
||||
text = append(text, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get alias and remove text we should ignore.
|
||||
out := text[:0]
|
||||
alias := ""
|
||||
for _, t := range text {
|
||||
if strings.Contains(t.S, "instruction is used by the alias") || strings.Contains(t.S, "instruction is an alias of") {
|
||||
alias_t := strings.SplitAfter(t.S, ".")
|
||||
alias = alias_t[0]
|
||||
}
|
||||
// Skip page footer
|
||||
if match(t, "Arial-ItalicMT", 8, "") || match(t, "ArialMT", 8, "") {
|
||||
if debugPage > 0 {
|
||||
fmt.Println("==the skip page footer is:==", t)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Skip the body text
|
||||
if match(t, "TimesNewRoman", 9, "") || match(t, "TimesNewRomanPS-ItalicMT", 9, "") {
|
||||
if debugPage > 0 {
|
||||
fmt.Println("==the skip body text is:==", t)
|
||||
}
|
||||
continue
|
||||
}
|
||||
out = append(out, t)
|
||||
}
|
||||
text = out
|
||||
// Page header must be child title.
|
||||
if len(text) == 0 || !sectionRE.MatchString(text[0].S) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
name = text[1].S
|
||||
inst := Inst{
|
||||
Name: name,
|
||||
Alias: alias,
|
||||
}
|
||||
text = text[2:]
|
||||
// Skip body text before bits.
|
||||
OffsetMark := false
|
||||
k := 0
|
||||
for k = 0; k < len(text); {
|
||||
if !match(text[k], "Arial", 8, "31") {
|
||||
k++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Check offset.
|
||||
if k > 0 && match(text[k-1], "Arial,Bold", 10, "") {
|
||||
OffsetMark = true
|
||||
text = text[k-1:]
|
||||
} else {
|
||||
text = text[k:]
|
||||
}
|
||||
// Encodings follow.
|
||||
BitMark := false
|
||||
bits := ""
|
||||
// Find bits.
|
||||
for i := 0; i < len(text); {
|
||||
inst.Bits = ""
|
||||
offset := ""
|
||||
abits := ""
|
||||
// Read bits only one time.
|
||||
if OffsetMark == true {
|
||||
for i < len(text) && !match(text[i], "Arial", 8, "") {
|
||||
i++
|
||||
}
|
||||
if i < len(text) {
|
||||
offset = text[i-1].S
|
||||
BitMark = false
|
||||
bits = ""
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if BitMark == false {
|
||||
if Npagebox == true && Noffset == offset {
|
||||
bits, i = readBitBox(name, Ncontent, text, i)
|
||||
} else {
|
||||
bits, i = readBitBox(name, content, text, i)
|
||||
}
|
||||
BitMark = true
|
||||
// Every time, get "then SEE" after get bits.
|
||||
enc := false
|
||||
if i < len(text)-1 {
|
||||
m := i
|
||||
for m < len(text)-1 && !match(text[m], "Arial-BoldItalicMT", 9, "encoding") {
|
||||
m++
|
||||
}
|
||||
if match(text[m], "Arial-BoldItalicMT", 9, "encoding") && m < len(text) {
|
||||
enc = true
|
||||
m = m + 1
|
||||
}
|
||||
if enc == true {
|
||||
for m < len(text) && !match(text[m], "Arial,Bold", 10, "") && match(text[m], "LucidaSansTypewriteX", 6.48, "") {
|
||||
if strings.Contains(text[m].S, "then SEE") {
|
||||
inst.Code = text[m].S
|
||||
break
|
||||
} else {
|
||||
m++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Possible subarchitecture notes.
|
||||
ArchLoop:
|
||||
for i < len(text) {
|
||||
if !match(text[i], "Arial-BoldItalicMT", 9, "variant") || match(text[i], "Arial-BoldItalicMT", 9, "encoding") {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
inst.Arch = ""
|
||||
inst.Arch += offset
|
||||
inst.Arch += " "
|
||||
inst.Arch += text[i].S
|
||||
inst.Arch = strings.TrimSpace(inst.Arch)
|
||||
i++
|
||||
// Encoding syntaxes.
|
||||
sign := ""
|
||||
SynMark := false
|
||||
for i < len(text) && match(text[i], "LucidaSansTypewriteX", 6.48, "") && SynMark == false {
|
||||
if (strings.Contains(text[i].S, "==") || strings.Contains(text[i].S, "!=")) && SynMark == false {
|
||||
sign = text[i].S
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// Avoid "equivalent to" another syntax.
|
||||
if SynMark == false {
|
||||
SynMark = true
|
||||
inst.Syntax = ""
|
||||
inst.Syntax = text[i].S
|
||||
i++
|
||||
}
|
||||
}
|
||||
abits = bits
|
||||
// Analyse and replace some bits value.eg, sf==1
|
||||
if strings.Contains(sign, "&&") {
|
||||
split := strings.Split(sign, "&&")
|
||||
for k := 0; k < len(split); {
|
||||
if strings.Contains(split[k], "==") && !strings.Contains(split[k], "!") {
|
||||
tmp := strings.Split(split[k], "==")
|
||||
prefix := strings.TrimSpace(tmp[0])
|
||||
value := strings.TrimSpace(tmp[1])
|
||||
if strings.Contains(bits, prefix) && !strings.Contains(value, "x") {
|
||||
abits = strings.Replace(abits, prefix, value, -1)
|
||||
}
|
||||
}
|
||||
k++
|
||||
}
|
||||
} else if strings.Contains(sign, "==") && !strings.Contains(sign, "!") {
|
||||
split := strings.Split(sign, "==")
|
||||
prefix := strings.TrimSpace(split[0])
|
||||
value := strings.TrimSpace(split[1])
|
||||
if strings.Contains(bits, prefix) && !strings.Contains(value, "x") {
|
||||
abits = strings.Replace(abits, prefix, value, -1)
|
||||
}
|
||||
}
|
||||
// Deal with syntax contains {2}
|
||||
if strings.Contains(inst.Syntax, "{2}") {
|
||||
if !strings.Contains(abits, "Q") {
|
||||
fmt.Fprintf(os.Stderr, "instruction%s - syntax%s: is wrong!!\n", name, inst.Syntax)
|
||||
}
|
||||
syn := inst.Syntax
|
||||
bits := abits
|
||||
for i := 0; i < 2; {
|
||||
if i == 0 {
|
||||
inst.Bits = strings.Replace(bits, "Q", "0", -1)
|
||||
inst.Syntax = strings.Replace(syn, "{2}", "", -1)
|
||||
table = append(table, inst)
|
||||
}
|
||||
if i == 1 {
|
||||
inst.Bits = strings.Replace(bits, "Q", "1", -1)
|
||||
inst.Syntax = strings.Replace(syn, "{2}", "2", -1)
|
||||
table = append(table, inst)
|
||||
}
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
inst.Bits = abits
|
||||
table = append(table, inst)
|
||||
}
|
||||
|
||||
if OffsetMark == true && i < len(text) && match(text[i], "Arial-BoldItalicMT", 9, "variant") && !match(text[i], "Arial-BoldItalicMT", 9, "encoding") {
|
||||
continue ArchLoop
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return name, table
|
||||
}
|
||||
|
||||
func readBitBox(name string, content pdf.Content, text []pdf.Text, i int) (string, int) {
|
||||
// Bits headings
|
||||
y3 := 0.0
|
||||
x1 := 0.0
|
||||
for i < len(text) && match(text[i], "Arial", 8, "") {
|
||||
if y3 == 0 {
|
||||
y3 = text[i].Y
|
||||
}
|
||||
if x1 == 0 {
|
||||
x1 = text[i].X
|
||||
}
|
||||
if text[i].Y != y3 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
// Bits fields in box
|
||||
x2 := 0.0
|
||||
y2 := 0.0
|
||||
dy1 := 0.0
|
||||
for i < len(text) && match(text[i], "Arial", 8, "") {
|
||||
if x2 < text[i].X+text[i].W {
|
||||
x2 = text[i].X + text[i].W
|
||||
}
|
||||
if y2 == 0 {
|
||||
y2 = text[i].Y
|
||||
}
|
||||
if text[i].Y != y2 {
|
||||
break
|
||||
}
|
||||
dy1 = text[i].FontSize
|
||||
i++
|
||||
}
|
||||
// Bits fields below box
|
||||
x3 := 0.0
|
||||
y1 := 0.0
|
||||
for i < len(text) && match(text[i], "Arial", 8, "") {
|
||||
if x3 < text[i].X+text[i].W {
|
||||
x3 = text[i].X + text[i].W
|
||||
}
|
||||
y1 = text[i].Y
|
||||
if text[i].Y != y1 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
//no bits fields below box
|
||||
below_flag := true
|
||||
if y1 == 0.0 {
|
||||
below_flag = false
|
||||
y1 = y2
|
||||
}
|
||||
// Encoding box
|
||||
if debugPage > 0 {
|
||||
fmt.Println("encoding box", x1, y3, x2, y1)
|
||||
}
|
||||
|
||||
// Find lines (thin rectangles) separating bit fields.
|
||||
var bottom, top pdf.Rect
|
||||
const (
|
||||
yMargin = 0.25 * 72
|
||||
xMargin = 2 * 72
|
||||
)
|
||||
cont := 0
|
||||
if below_flag == true {
|
||||
for _, r := range content.Rect {
|
||||
cont = cont + 1
|
||||
if x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
|
||||
if y1-yMargin < r.Min.Y && r.Min.Y < y2-dy1 {
|
||||
bottom = r
|
||||
}
|
||||
if y2+dy1 < r.Min.Y && r.Min.Y < y3+yMargin {
|
||||
top = r
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, r := range content.Rect {
|
||||
cont = cont + 1
|
||||
if x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
|
||||
if y1-yMargin-dy1 < r.Min.Y && r.Min.Y < y3-dy1 {
|
||||
bottom = r
|
||||
}
|
||||
if y2+dy1 < r.Min.Y && r.Min.Y < y3+yMargin {
|
||||
top = r
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if debugPage > 0 {
|
||||
fmt.Println("top", top, "bottom", bottom, "content.Rect number", cont)
|
||||
}
|
||||
|
||||
const ε = 0.5 * 72
|
||||
cont_1 := 0
|
||||
var bars []pdf.Rect
|
||||
for _, r := range content.Rect {
|
||||
if math.Abs(r.Min.X-r.Max.X) < bottom.Max.X-bottom.Min.X-(ε/2) && math.Abs(r.Min.Y-bottom.Min.Y) < ε && math.Abs(r.Max.Y-top.Min.Y) < ε {
|
||||
cont_1 = cont_1 + 1
|
||||
bars = append(bars, r)
|
||||
}
|
||||
}
|
||||
sort.Sort(RectHorizontal(bars))
|
||||
if debugPage > 0 {
|
||||
fmt.Println("==bars number==", cont_1)
|
||||
}
|
||||
|
||||
// There are 16-bit and 32-bit encodings.
|
||||
// In practice, they are about 2.65 and 5.3 inches wide, respectively.
|
||||
// Use 4 inches as a cutoff.
|
||||
nbit := 32
|
||||
dx := top.Max.X - top.Min.X
|
||||
if top.Max.X-top.Min.X < 4*72 {
|
||||
nbit = 16
|
||||
}
|
||||
|
||||
total := 0
|
||||
var buf bytes.Buffer
|
||||
for i := 0; i < len(bars); i++ {
|
||||
if i > 0 {
|
||||
fmt.Fprintf(&buf, "|")
|
||||
}
|
||||
var sub []pdf.Text
|
||||
x1, x2 := bars[i].Min.X, bars[i].Max.X
|
||||
for _, t := range content.Text {
|
||||
tx := t.X + t.W/2
|
||||
ty := t.Y
|
||||
if x1 < tx && tx < x2 && y2-dy1 < ty && ty < y2+dy1 {
|
||||
sub = append(sub, t)
|
||||
}
|
||||
}
|
||||
var str []string
|
||||
for _, t := range findWords(sub) {
|
||||
str = append(str, t.S)
|
||||
}
|
||||
s := strings.Join(str, " ")
|
||||
s = strings.Replace(s, ")(", ") (", -1)
|
||||
|
||||
// If bits contain "!" or "x", be replaced by the bits below it.
|
||||
if strings.Contains(s, "!") || strings.Contains(s, "x") {
|
||||
var sub1 []pdf.Text
|
||||
for _, t := range content.Text {
|
||||
tx := t.X + t.W/2
|
||||
ty := t.Y
|
||||
if x1 < tx && tx < x2 && y1-dy1 < ty && ty < y1+dy1 {
|
||||
sub1 = append(sub1, t)
|
||||
}
|
||||
|
||||
}
|
||||
var str1 []string
|
||||
for _, t := range findWords(sub1) {
|
||||
str1 = append(str1, t.S)
|
||||
}
|
||||
s = strings.Join(str1, " ")
|
||||
s = strings.Replace(s, ")(", ") (", -1)
|
||||
}
|
||||
|
||||
n := len(strings.Fields(s))
|
||||
|
||||
var b int
|
||||
if IMMRE.MatchString(s) {
|
||||
bitNum := strings.TrimPrefix(s, "imm")
|
||||
b, _ = strconv.Atoi(bitNum)
|
||||
} else if s == "immhi" {
|
||||
b = 19
|
||||
} else {
|
||||
b = int(float64(nbit)*(x2-x1)/dx + 0.5)
|
||||
}
|
||||
if n == b {
|
||||
for k, f := range strings.Fields(s) {
|
||||
if k > 0 {
|
||||
fmt.Fprintf(&buf, "|")
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s", f)
|
||||
}
|
||||
} else {
|
||||
if n != 1 {
|
||||
fmt.Fprintf(os.Stderr, "%s - multi-field %d-bit encoding: %s\n", name, n, s)
|
||||
}
|
||||
fmt.Fprintf(&buf, "%s:%d", s, b)
|
||||
}
|
||||
total += b
|
||||
}
|
||||
|
||||
if total != nbit || total == 0 {
|
||||
fmt.Fprintf(os.Stderr, "%s - %d-bit encoding\n", name, total)
|
||||
}
|
||||
return buf.String(), i
|
||||
}
|
||||
|
||||
type RectHorizontal []pdf.Rect
|
||||
|
||||
func (x RectHorizontal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
func (x RectHorizontal) Less(i, j int) bool { return x[i].Min.X < x[j].Min.X }
|
||||
func (x RectHorizontal) Len() int { return len(x) }
|
||||
|
||||
func checkNoEncodings(num int, text []pdf.Text) {
|
||||
for _, t := range text {
|
||||
if match(t, "Helvetica-Bold", 9, "Encoding") {
|
||||
fmt.Fprintf(os.Stderr, "page %d: unexpected encoding: %s\n", num, t.S)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func match(t pdf.Text, font string, size float64, substr string) bool {
|
||||
return t.Font == font && math.Abs(t.FontSize-size) < 0.1 && strings.Contains(t.S, substr)
|
||||
}
|
||||
|
||||
func findWords(chars []pdf.Text) (words []pdf.Text) {
|
||||
// Sort by Y coordinate and normalize.
|
||||
const nudge = 1
|
||||
sort.Sort(pdf.TextVertical(chars))
|
||||
old := -100000.0
|
||||
for i, c := range chars {
|
||||
if c.Y != old && math.Abs(old-c.Y) < nudge {
|
||||
chars[i].Y = old
|
||||
} else {
|
||||
old = c.Y
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by Y coordinate, breaking ties with X.
|
||||
// This will bring letters in a single word together.
|
||||
sort.Sort(pdf.TextVertical(chars))
|
||||
|
||||
// Loop over chars.
|
||||
for i := 0; i < len(chars); {
|
||||
// Find all chars on line.
|
||||
j := i + 1
|
||||
for j < len(chars) && chars[j].Y == chars[i].Y {
|
||||
j++
|
||||
}
|
||||
var end float64
|
||||
// Split line into words (really, phrases).
|
||||
for k := i; k < j; {
|
||||
ck := &chars[k]
|
||||
s := ck.S
|
||||
end = ck.X + ck.W
|
||||
charSpace := ck.FontSize / 6
|
||||
wordSpace := ck.FontSize * 2 / 3
|
||||
l := k + 1
|
||||
for l < j {
|
||||
// Grow word.
|
||||
cl := &chars[l]
|
||||
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace {
|
||||
s += cl.S
|
||||
end = cl.X + cl.W
|
||||
l++
|
||||
continue
|
||||
}
|
||||
// Add space to phrase before next word.
|
||||
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace {
|
||||
s += " " + cl.S
|
||||
end = cl.X + cl.W
|
||||
l++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
f := ck.Font
|
||||
f = strings.TrimSuffix(f, ",Italic")
|
||||
f = strings.TrimSuffix(f, "-Italic")
|
||||
words = append(words, pdf.Text{f, ck.FontSize, ck.X, ck.Y, end - ck.X, s})
|
||||
k = l
|
||||
}
|
||||
i = j
|
||||
}
|
||||
|
||||
return words
|
||||
}
|
||||
|
||||
func sameFont(f1, f2 string) bool {
|
||||
f1 = strings.TrimSuffix(f1, ",Italic")
|
||||
f1 = strings.TrimSuffix(f1, "-Italic")
|
||||
f2 = strings.TrimSuffix(f1, ",Italic")
|
||||
f2 = strings.TrimSuffix(f1, "-Italic")
|
||||
return strings.TrimSuffix(f1, ",Italic") == strings.TrimSuffix(f2, ",Italic") || f1 == "Symbol" || f2 == "Symbol" || f1 == "TimesNewRoman" || f2 == "TimesNewRoman"
|
||||
}
|
||||
|
||||
var jsFix = strings.NewReplacer(
|
||||
`\u003c`, `<`,
|
||||
`\u003e`, `>`,
|
||||
`\u0026`, `&`,
|
||||
`\u0009`, `\t`,
|
||||
)
|
||||
|
||||
func printTable(name string, table []Inst) {
|
||||
_ = strconv.Atoi
|
||||
}
|
Загрузка…
Ссылка в новой задаче