/* C-SKY disassembler.
- Copyright (C) 1988-2019 Free Software Foundation, Inc.
+ Copyright (C) 1988-2021 Free Software Foundation, Inc.
Contributed by C-SKY Microsystems and Mentor Graphics.
This file is part of the GNU opcodes library.
#include "config.h"
#include <stdio.h>
#include "bfd_stdint.h"
+#include <elf/csky.h>
#include "disassemble.h"
#include "elf-bfd.h"
#include "opcode/csky.h"
#define CSKY_INST_TYPE unsigned long
#define HAS_SUB_OPERAND (unsigned int)0xffffffff
+#define CSKY_DEFAULT_ISA 0xffffffff
enum sym_type
{
disassemble_info *info;
/* Opcode information. */
struct csky_opcode_info const *opinfo;
+ BFD_HOST_U_64_BIT isa;
/* The value of operand to show. */
int value;
/* Whether to look up/print a symbol name. */
enum sym_type last_type;
int last_map_sym = 1;
bfd_vma last_map_addr = 0;
+int using_abi = 0;
/* Only for objdump tool. */
#define INIT_MACH_FLAG 0xffffffff
static unsigned int
csky_chars_to_number (unsigned char * buf, int n)
{
- if (n == 0)
- abort ();
int i;
- int val = 0;
+ unsigned int val = 0;
if (dis_info.info->endian == BFD_ENDIAN_BIG)
- while (n--)
- val |= buf[n] << (n*8);
- else
for (i = 0; i < n; i++)
- val |= buf[i] << (i*8);
+ val = val << 8 | buf[i];
+ else
+ for (i = n - 1; i >= 0; i--)
+ val = val << 8 | buf[i];
return val;
}
p = g_opcodeP;
while (p->mnemonic)
{
+ if (!(p->isa_flag16 & dis_info.isa)
+ && !(p->isa_flag32 & dis_info.isa))
+ {
+ p++;
+ continue;
+ }
+
/* Get the opcode mask. */
for (i = 0; i < OP_TABLE_NUM; i++)
if (length == 2)
disassembler_ftype
csky_get_disassembler (bfd *abfd)
{
- if (abfd != NULL)
- mach_flag = elf_elfheader (abfd)->e_flags;
- return print_insn_csky;
+ obj_attribute *attr;
+ const char *sec_name = NULL;
+ if (!abfd)
+ dis_info.isa = CSKY_DEFAULT_ISA;
+ else
+ {
+ mach_flag = elf_elfheader (abfd)->e_flags;
+
+ sec_name = get_elf_backend_data (abfd)->obj_attrs_section;
+ /* Skip any input that hasn't attribute section.
+ This enables to link object files without attribute section with
+ any others. */
+ if (bfd_get_section_by_name (abfd, sec_name) != NULL)
+ {
+ attr = elf_known_obj_attributes_proc (abfd);
+ dis_info.isa = attr[Tag_CSKY_ISA_EXT_FLAGS].i;
+ dis_info.isa <<= 32;
+ dis_info.isa |= attr[Tag_CSKY_ISA_FLAGS].i;
+ }
+ else
+ dis_info.isa = CSKY_DEFAULT_ISA;
+ }
+
+ return print_insn_csky;
+}
+
+/* Parse the string of disassembler options. */
+static void
+parse_csky_dis_options (const char *opts_in)
+{
+ char *opts = xstrdup (opts_in);
+ char *opt = opts;
+ char *opt_end = opts;
+
+ for (; opt_end != NULL; opt = opt_end + 1)
+ {
+ if ((opt_end = strchr (opt, ',')) != NULL)
+ *opt_end = 0;
+ if (strcmp (opt, "abi-names") == 0)
+ using_abi = 1;
+ else
+ fprintf (stderr,
+ "unrecognized disassembler option: %s", opt);
+ }
+}
+
+/* Get general register name. */
+static const char *
+get_gr_name (int regno)
+{
+ return csky_get_general_reg_name (mach_flag, regno, using_abi);
+}
+
+/* Get control register name. */
+static const char *
+get_cr_name (unsigned int regno, int bank)
+{
+ return csky_get_control_reg_name (mach_flag, bank, regno, using_abi);
}
static int
switch (oprnd->type)
{
case OPRND_TYPE_CTRLREG:
- if (IS_CSKY_V1 (mach_flag))
- {
- /* In V1 only cr0-cr12 have alias names. */
- if (value <= 12)
- strcat (str, csky_ctrl_regs[value].name);
- /* Others using crn(n > 12). */
- else if (value <= 30)
- {
- sprintf (buf, "cr%d", (int)value);
- strcat (str, buf);
- }
- else
- return -1;
- }
- else
- {
- int sel;
- int crx;
- sel = value >> 5;
- crx = value & 0x1f;
- sprintf (buf, "cr<%d, %d>", crx, sel);
- strcat (str, buf);
- }
- break;
+ if (IS_CSKY_V1(mach_flag) && ((value & 0x1f) == 0x1f))
+ return -1;
+ strcat (str, get_cr_name((value & 0x1f), (value >> 5)));
+ break;
case OPRND_TYPE_DUMMY_REG:
mask = dis_info.opinfo->oprnd.oprnds[0].mask;
value = inst & mask;
bit++;
}
value = result;
- strcat (str, csky_general_reg[value]);
+ strcat (str, get_gr_name (value));
break;
case OPRND_TYPE_GREG0_7:
case OPRND_TYPE_GREG0_15:
case OPRND_TYPE_GREG16_31:
case OPRND_TYPE_REGnsplr:
case OPRND_TYPE_AREG:
- if (IS_CSKY_V2 (mach_flag) && value == 14)
- strcat (str, "sp");
- else
- strcat (str, csky_general_reg[value]);
- dis_info.value = value;
+ strcat (str, get_gr_name (value));
break;
case OPRND_TYPE_CPREG:
- strcat (str, csky_cp_reg[value]);
+ sprintf (buf, "cpr%d", (int)value);
+ strcat (str, buf);
break;
case OPRND_TYPE_FREG:
sprintf (buf, "fr%d", (int)value);
strcat (str, buf);
break;
case OPRND_TYPE_VREG:
+ dis_info.value = value;
sprintf (buf, "vr%d", (int)value);
strcat (str, buf);
break;
case OPRND_TYPE_CPCREG:
- strcat (str, csky_cp_creg[value]);
+ sprintf (buf, "cpcr%d", (int)value);
+ strcat (str, buf);
break;
case OPRND_TYPE_CPIDX:
- strcat (str, csky_cp_idx[value]);
+ sprintf (buf, "cp%d", (int)value);
+ strcat (str, buf);
break;
case OPRND_TYPE_IMM2b_JMPIX:
value = (value + 2) << 3;
strcat (str, buf);
ret = 0;
break;
+ case OPRND_TYPE_IMM5b_VSH:
+ {
+ char num[128];
+ value = ((value & 0x1) << 4) | (value >> 1);
+ sprintf (num, "%d", (int)value);
+ strcat (str, num);
+ ret = 0;
+ break;
+ }
case OPRND_TYPE_MSB2SIZE:
case OPRND_TYPE_LSB2SIZE:
{
case OPRND_TYPE_IMM2b:
case OPRND_TYPE_IMM4b:
case OPRND_TYPE_IMM5b:
+ case OPRND_TYPE_IMM5b_LS:
case OPRND_TYPE_IMM7b:
case OPRND_TYPE_IMM8b:
case OPRND_TYPE_IMM12b:
sprintf (buf, "%f", fvalue);
strcat (str, buf);
+ break;
+ }
+ case OPRND_TYPE_HFLOAT_FMOVI:
+ case OPRND_TYPE_SFLOAT_FMOVI:
+ {
+ int imm4;
+ int imm8;
+ imm4 = ((inst >> 16) & 0xf);
+ imm4 = (138 - imm4) << 23;
+
+ imm8 = ((inst >> 8) & 0x3);
+ imm8 |= (((inst >> 20) & 0x3f) << 2);
+ imm8 <<= 15;
+
+ value = ((inst >> 5) & 1) << 31;
+ value |= imm4 | imm8;
+
+ imm4 = 138 - (imm4 >> 23);
+ imm8 >>= 15;
+ if ((inst >> 5) & 1)
+ {
+ imm8 = 0 - imm8;
+ }
+
+ float f = 0;
+ memcpy (&f, &value, sizeof (float));
+ sprintf (buf, "%f\t// imm9:%4d, imm4:%2d", f, imm8, imm4);
+ strcat (str, buf);
+
+ break;
+ }
+
+ case OPRND_TYPE_DFLOAT_FMOVI:
+ {
+ uint64_t imm4;
+ uint64_t imm8;
+ uint64_t dvalue;
+ imm4 = ((inst >> 16) & 0xf);
+ imm4 = (1034 - imm4) << 52;
+
+ imm8 = ((inst >> 8) & 0x3);
+ imm8 |= (((inst >> 20) & 0x3f) << 2);
+ imm8 <<= 44;
+
+ dvalue = (((uint64_t)inst >> 5) & 1) << 63;
+ dvalue |= imm4 | imm8;
+
+ imm4 = 1034 - (imm4 >> 52);
+ imm8 >>= 44;
+ if (inst >> 5)
+ {
+ imm8 = 0 - imm8;
+ }
+ double d = 0;
+ memcpy (&d, &dvalue, sizeof (double));
+ sprintf (buf, "%lf\t// imm9:%4ld, imm4:%2ld", d, (long) imm8, (long) imm4);
+ strcat (str, buf);
+
break;
}
case OPRND_TYPE_LABEL_WITH_BRACKET:
case OPRND_TYPE_FREGLIST_DASH:
if (IS_CSKY_V2 (mach_flag))
{
- int vrx = value & 0xf;
- int vry = vrx + (value >> 4);
+ int vrx = 0;
+ int vry = 0;
+ if (dis_info.isa & CSKY_ISA_FLOAT_7E60
+ && (strstr (str, "fstm") != NULL
+ || strstr (str, "fldm") != NULL))
+ {
+ vrx = value & 0x1f;
+ vry = vrx + (value >> 5);
+ }
+ else
+ {
+ vrx = value & 0xf;
+ vry = vrx + (value >> 4);
+ }
sprintf (buf, "fr%d-fr%d", vrx, vry);
strcat (str, buf);
}
case OPRND_TYPE_REGLIST_DASH:
if (IS_CSKY_V1 (mach_flag))
{
- strcat (str, csky_general_reg[value]);
- strcat (str, "-r15");
+ sprintf (buf, "%s-r15", get_gr_name (value));
+ strcat (str, buf);
}
else
{
- strcat (str, csky_general_reg[value >> 5]);
+ if ((value & 0x1f) + (value >> 5) > 31)
+ {
+ ret = -1;
+ break;
+ }
+ strcat (str, get_gr_name ((value >> 5)));
strcat (str, "-");
- strcat (str, csky_general_reg[(value & 0x1f) + (value >> 5)]);
+ strcat (str, get_gr_name ((value & 0x1f) + (value >> 5)));
}
break;
case OPRND_TYPE_PSR_BITS_LIST:
}
case OPRND_TYPE_REGbsp:
if (IS_CSKY_V1 (mach_flag))
- strcat (str, "(sp)");
+ sprintf(buf, "(%s)", get_gr_name (0));
else
- strcat (str, "(sp)");
+ sprintf(buf, "(%s)", get_gr_name (14));
+ strcat (str, buf);
break;
case OPRND_TYPE_REGsp:
if (IS_CSKY_V1 (mach_flag))
- strcat (str, "sp");
+ strcat (str, get_gr_name (0));
else
- strcat (str, "sp");
+ strcat (str, get_gr_name (14));
break;
case OPRND_TYPE_REGnr4_r7:
case OPRND_TYPE_AREG_WITH_BRACKET:
- if (IS_CSKY_V1 (mach_flag) && (value < 4 || value > 7))
- {
- strcat (str, "(");
- strcat (str, csky_general_reg[value]);
- strcat (str, ")");
- }
- else
- {
- strcat (str, "(");
- strcat (str, csky_general_reg[value]);
- strcat (str, ")");
- }
+ strcat (str, "(");
+ strcat (str, get_gr_name (value));
+ strcat (str, ")");
break;
case OPRND_TYPE_AREG_WITH_LSHIFT:
- strcat (str, csky_general_reg[value >> 5]);
+ strcat (str, get_gr_name (value >> 5));
strcat (str, " << ");
if ((value & 0x1f) == 0x1)
strcat (str, "0");
strcat (str, "3");
break;
case OPRND_TYPE_AREG_WITH_LSHIFT_FPU:
- strcat (str, csky_general_reg[value >> 2]);
+ strcat (str, get_gr_name (value >> 2));
strcat (str, " << ");
if ((value & 0x3) == 0x0)
strcat (str, "0");
else if ((value & 0x3) == 0x3)
strcat (str, "3");
break;
- case OPRND_TYPE_FREG_WITH_INDEX:
+ case OPRND_TYPE_VREG_WITH_INDEX:
{
unsigned freg_val = value & 0xf;
unsigned index_val = (value >> 4) & 0xf;
strcat(str, buf);
break;
}
+ case OPRND_TYPE_FREG_WITH_INDEX:
+ {
+ unsigned freg_val = value & 0xf;
+ unsigned index_val = (value >> 4) & 0xf;
+ sprintf (buf, "fr%d[%d]", freg_val, index_val);
+ strcat(str, buf);
+ break;
+ }
case OPRND_TYPE_REGr4_r7:
if (IS_CSKY_V1 (mach_flag))
- strcat (str, "r4-r7");
+ {
+ sprintf (buf, "%s-%s", get_gr_name (4), get_gr_name (7));
+ strcat (str, buf);
+ }
break;
case OPRND_TYPE_CONST1:
strcat (str, "1");
break;
case OPRND_TYPE_REG_r1a:
case OPRND_TYPE_REG_r1b:
- strcat (str, "r1");
+ strcat (str, get_gr_name (1));
break;
case OPRND_TYPE_REG_r28:
- strcat (str, "r28");
+ strcat (str, get_gr_name (28));
break;
case OPRND_TYPE_REGLIST_DASH_COMMA:
/* 16-bit reglist. */
if (value & 0xf)
{
- strcat (str, "r4");
+ strcat (str, get_gr_name (4));
if ((value & 0xf) > 1)
{
strcat (str, "-");
- strcat (str, csky_general_reg[(value & 0xf) + 3]);
+ strcat (str, get_gr_name ((value & 0xf) + 3));
}
if (value & ~0xf)
strcat (str, ", ");
if (value & 0x10)
{
/* r15. */
- strcat (str, "r15");
+ strcat (str, get_gr_name (15));
if (value & ~0x1f)
strcat (str, ", ");
}
value >>= 5;
if (value & 0x3)
{
- strcat (str, "r16");
+ strcat (str, get_gr_name (16));
if ((value & 0x7) > 1)
{
strcat (str, "-");
- strcat (str, csky_general_reg[(value & 0xf) + 15]);
+ strcat (str, get_gr_name ((value & 0x7) + 15));
}
if (value & ~0x7)
strcat (str, ", ");
}
if (value & 0x8)
/* r15. */
- strcat (str, "r28");
+ strcat (str, get_gr_name (28));
}
break;
case OPRND_TYPE_UNCOND10b:
CSKY_INST_TYPE inst = 0;
int status;
char str[256];
- long given;
+ unsigned long given;
int is_data = FALSE;
void (*printer) (bfd_vma, struct disassemble_info *, long);
unsigned int size = 4;
dis_info.mem = memaddr;
dis_info.info = info;
dis_info.need_output_symbol = 0;
+
+ if (info->disassembler_options)
+ {
+ parse_csky_dis_options (info->disassembler_options);
+ info->disassembler_options = NULL;
+ }
+
if (mach_flag != INIT_MACH_FLAG && mach_flag != BINARY_MACH_FLAG)
info->mach = mach_flag;
else if (mach_flag == INIT_MACH_FLAG)
- mach_flag = info->mach;
+ {
+ mach_flag = info->mach;
+ dis_info.isa = CSKY_DEFAULT_ISA;
+ }
if (mach_flag == BINARY_MACH_FLAG && info->endian == BFD_ENDIAN_UNKNOWN)
- info->endian = BFD_ENDIAN_LITTLE;
+ {
+ info->endian = BFD_ENDIAN_LITTLE;
+ dis_info.isa = CSKY_DEFAULT_ISA;
+ }
/* First check the full symtab for a mapping symbol, even if there
are no usable non-mapping symbols for this address. */