diff options
author | Andrew Bennett <andrew.bennett@imgtec.com> | 2014-09-10 11:32:01 +0100 |
---|---|---|
committer | Andrew Bennett <andrew.bennett@imgtec.com> | 2014-09-15 12:15:55 +0100 |
commit | 7361da2c952eb96d1869e49e35e8bc95ab42074a (patch) | |
tree | c427e271b015d6a2c690c7536c513369085588f9 /opcodes/mips-dis.c | |
parent | ea79f94a7ab96c6114b80bf78830f877325b10ff (diff) | |
download | binutils-gdb-7361da2c952eb96d1869e49e35e8bc95ab42074a.tar.gz |
Add support for MIPS R6.
bfd/
* aoutx.h (NAME (aout, machine_type)): Add mips32r6 and mips64r6.
* archures.c (bfd_architecture): Likewise.
* bfd-in2.h (bfd_architecture): Likewise.
(bfd_reloc_code_real): Add relocs BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3 and
BFD_RELOC_MIPS_19_PCREL_S2.
* cpu-mips.c (arch_info_struct): Add mips32r6 and mips64r6.
* elf32-mips.c: Define relocs R_MIPS_PC21_S2, R_MIPS_PC26_S2
R_MIPS_PC18_S3, R_MIPS_PC19_S2, R_MIPS_PCHI16 and R_MIPS_PCLO16.
(mips_reloc_map): Add entries for BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3,
BFD_RELOC_MIPS_19_PCREL_S2, BFD_RELOC_HI16_S_PCREL and
BFD_RELOC_LO16_PCREL.
* elf64-mips.c: Define REL, and RELA relocations R_MIPS_PC21_S2,
R_MIPS_PC26_S2, R_MIPS_PC18_S3, R_MIPS_PC19_S2, R_MIPS_PCHI16
and R_MIPS_PCLO16.
(mips_reloc_map): Add entries for BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3,
BFD_RELOC_MIPS_19_PCREL_S2, BFD_RELOC_HI16_S_PCREL and
BFD_RELOC_LO16_PCREL.
* elfn32-mips.c: Likewise.
* elfxx-mips.c (MIPSR6_P): New define.
(mipsr6_exec_plt_entry): New array.
(hi16_reloc_p): Add support for R_MIPS_PCHI16.
(lo16_reloc_p): Add support for R_MIPS_PCLO16.
(aligned_pcrel_reloc_p): New function.
(mips_elf_relocation_needs_la25_stub): Add support for relocs:
R_MIPS_PC21_S2 and R_MIPS_PC26_S2.
(mips_elf_calculate_relocation): Add support for relocs:
R_MIPS_PC21_S2, R_MIPS_PC26_S2, R_MIPS_PC18_S3, R_MIPS_PC19_S2,
R_MIPS_PCHI16 and R_MIPS_PCLO16.
(_bfd_elf_mips_mach): Add support for mips32r6 and mips64r6.
(mips_elf_add_lo16_rel_addend): Add support for R_MIPS_PCHI16.
(_bfd_mips_elf_check_relocs): Add support for relocs:
R_MIPS_PC21_S2 and R_MIPS_PC26_S2.
(_bfd_mips_elf_relocate_section): Add a check for unaligned
pc relative relocs.
(_bfd_mips_elf_finish_dynamic_symbol): Add support for MIPS r6
plt entry.
(mips_set_isa_flags): Add support for mips32r6 and mips64r6.
(_bfd_mips_elf_print_private_bfd_data): Likewise.
(mips_32bit_flags_p): Add support for mips32r6.
* libbfd.h (bfd_reloc_code_real_names): Add entries for
BFD_RELOC_MIPS_21_PCREL_S2, BFD_RELOC_MIPS_26_PCREL_S2,
BFD_RELOC_MIPS_18_PCREL_S3 and BFD_RELOC_MIPS_19_PCREL_S2.
* reloc.c: Document relocs BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3 and
BFD_RELOC_MIPS_19_PCREL_S2.
binutils/
* readelf.c (get_machine_flags): Add support for mips32r6 and
mips64r6.
elfcpp/
* mips.h (E_MIPS_ARCH_32R6, E_MIPS_ARCH_64R6): New enum constants.
gas/
* config/tc-mips.c (mips_nan2008): New static global.
(mips_flag_nan2008): Removed.
(LL_SC_FMT): New define.
(COP12_FMT): Updated.
(ISA_IS_R6): New define.
(ISA_HAS_64BIT_REGS): Add mips64r6.
(ISA_HAS_DROR): Likewise.
(ISA_HAS_64BIT_FPRS): Add mips32r6 and mips64r6.
(ISA_HAS_ROR): Likewise.
(ISA_HAS_ODD_SINGLE_FPR): Likewise.
(ISA_HAS_MXHC1): Likewise.
(hilo_interlocks): Likewise.
(md_longopts): Likewise.
(ISA_HAS_LEGACY_NAN): New define.
(options): Add OPTION_MIPS32R6 and OPTION_MIPS64R6.
(mips_ase): Add field rem_rev.
(mips_ases): Updated to add which ISA an ASE was removed in.
(mips_isa_rev): Add support for mips32r6 and mips64r6.
(mips_check_isa_supports_ase): Add support to check if an ASE
has been removed in the specified MIPS ISA revision.
(validate_mips_insn): Skip '-' character.
(macro_build): Likewise.
(mips_check_options): Prevent R6 working with fp32, mips16,
micromips, or branch relaxation.
(file_mips_check_options): Set R6 floating point registers to
64 bit. Also deal with the nan2008 option.
(limited_pcrel_reloc_p): Add relocs: BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3,
BFD_RELOC_MIPS_19_PCREL_S2, BFD_RELOC_HI16_S_PCREL and
BFD_RELOC_LO16_PCREL.
(operand_reg_mask): Add support for OP_SAME_RS_RT, OP_CHECK_PREV
and OP_NON_ZERO_REG.
(match_check_prev_operand): New static function.
(match_same_rs_rt_operand): New static function.
(match_non_zero_reg_operand): New static function.
(match_operand): Added entries for: OP_SAME_RS_RT, OP_CHECK_PREV
and OP_NON_ZERO_REG.
(insns_between): Added case to deal with forbidden slots.
(append_insn): Added support for relocs: BFD_RELOC_MIPS_21_PCREL_S2
and BFD_RELOC_MIPS_26_PCREL_S2.
(match_insn): Add support for operands -A, -B, +' and +". Also
skip '-' character.
(mips_percent_op): Add entries for %pcrel_hi and %pcrel_lo.
(md_parse_option): Add support for mips32r6 and mips64r6. Also
update the nan option handling.
(md_pcrel_from): Add cases for relocs: BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2.
(mips_force_relocation): Prevent forced relaxation for MIPS r6.
(md_apply_fix): Add support for relocs: BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3,
BFD_RELOC_MIPS_19_PCREL_S2, BFD_RELOC_HI16_S_PCREL and
BFD_RELOC_LO16_PCREL.
(s_mipsset): Add support for mips32r6 and mips64r6.
(s_nan): Update to support the new nan2008 framework.
(tc_gen_reloc): Add relocs: BFD_RELOC_MIPS_21_PCREL_S2,
BFD_RELOC_MIPS_26_PCREL_S2, BFD_RELOC_MIPS_18_PCREL_S3,
BFD_RELOC_MIPS_19_PCREL_S2, BFD_RELOC_HI16_S_PCREL and
BFD_RELOC_LO16_PCREL.
(mips_elf_final_processing): Updated to use the mips_nan2008.
(mips_cpu_info_table): Add entries for mips32r6 and mips64r6.
(macro): Enable ldc2, sdc2, ll, lld, swc2, sc, scd, cache, pref
macros for R6.
(mips_fix_adjustable): Make PC relative R6 relocations relative
to the symbol and not the section.
* configure.ac: Add support for mips32r6 and mips64r6.
* configure: Regenerate.
* doc/c-mips.texi: Document the -mips32r6 and -mips64r6 command line
options.
* doc/as.texinfo: Likewise.
gas/testsuite/
* gas/mips/24k-triple-stores-1.s: If testing for r6 prevent
non-supported instructions from being tested.
* gas/mips/24k-triple-stores-2.s: Likewise.
* gas/mips/24k-triple-stores-3.s: Likewise.
* gas/mips/24k-triple-stores-6.s: Likewise.
* gas/mips/beq.s: Likewise.
* gas/mips/eva.s: Likewise.
* gas/mips/ld-zero-3.s: Likewise.
* gas/mips/mips32-cp2.s: Likewise.
* gas/mips/mips32.s: Likewise.
* gas/mips/mips4.s: Likewise.
* gas/mips/add.s: Don't test the add instructions if r6, and
add padding.
* gas/mips/add.d: Check for a triple dot not a nop at the end of the
disassembly output.
* gas/mips/micromips@add.d: Likewise.
* gas/mips/mipsr6@24k-branch-delay-1.d: New file.
* gas/mips/mipsr6@24k-triple-stores-1.d: New file.
* gas/mips/mipsr6@24k-triple-stores-2-llsc.d: New file.
* gas/mips/mipsr6@24k-triple-stores-2.d: New file.
* gas/mips/mipsr6@24k-triple-stores-3.d: New file.
* gas/mips/mipsr6@24k-triple-stores-6.d: New file.
* gas/mips/mipsr6@add.d: New file.
* gas/mips/mipsr6@attr-gnu-4-1-msingle-float.l: New file.
* gas/mips/mipsr6@attr-gnu-4-1-msingle-float.s: New file.
* gas/mips/mipsr6@attr-gnu-4-1-msoft-float.l: New file.
* gas/mips/mipsr6@attr-gnu-4-1-msoft-float.s: New file.
* gas/mips/mipsr6@attr-gnu-4-2-mdouble-float.l: New file.
* gas/mips/mipsr6@attr-gnu-4-2-mdouble-float.s: New file.
* gas/mips/mipsr6@beq.d: New file.
* gas/mips/mipsr6@bge.d: New file.
* gas/mips/mipsr6@bgeu.d: New file.
* gas/mips/mipsr6@blt.d: New file.
* gas/mips/mipsr6@bltu.d: New file.
* gas/mips/mipsr6@branch-misc-1.d: New file.
* gas/mips/mipsr6@branch-misc-2-64.d: New file.
* gas/mips/mipsr6@branch-misc-2pic-64.d: New file.
* gas/mips/mipsr6@branch-misc-4-64.d: New file.
* gas/mips/mipsr6@cache.d: New file.
* gas/mips/mipsr6@eva.d: New file.
* gas/mips/mipsr6@jal-svr4pic-noreorder.d: New file.
* gas/mips/mipsr6@jal-svr4pic.d: New file.
* gas/mips/mipsr6@ld-zero-2.d: New file.
* gas/mips/mipsr6@ld-zero-3.d: New file.
* gas/mips/mipsr6@loc-swap-dis.d: New file.
* gas/mips/mipsr6@mips32-cp2.d: New file.
* gas/mips/mipsr6@mips32-imm.d: New file.
* gas/mips/mipsr6@mips32.d: New file.
* gas/mips/mipsr6@mips32r2.d: New file.
* gas/mips/mipsr6@mips4-fp.d: New file.
* gas/mips/mipsr6@mips4-fp.l: New file.
* gas/mips/mipsr6@mips4-fp.s: New file.
* gas/mips/mipsr6@mips4.d: New file.
* gas/mips/mipsr6@mips5-fp.d: New file.
* gas/mips/mipsr6@mips5-fp.l: New file.
* gas/mips/mipsr6@mips5-fp.s: New file.
* gas/mips/mipsr6@mips64.d: New file.
* gas/mips/mipsr6@msa-branch.d: New file.
* gas/mips/mipsr6@msa.d: New file.
* gas/mips/mipsr6@pref.d: New file.
* gas/mips/mipsr6@relax-swap3.d: New file.
* gas/mips/r6-64-n32.d: New file.
* gas/mips/r6-64-n64.d: New file.
* gas/mips/r6-64-removed.l: New file.
* gas/mips/r6-64-removed.s: New file.
* gas/mips/r6-64.s: New file.
* gas/mips/r6-attr-none-double.d: New file.
* gas/mips/r6-n32.d: New file.
* gas/mips/r6-n64.d: New file.
* gas/mips/r6-removed.l: New file.
* gas/mips/r6-removed.s: New file.
* gas/mips/r6.d: New file.
* gas/mips/r6.s: New file.
* gas/mips/mipsr6@mips32-dsp.d: New file.
* gas/mips/mipsr6@mips32-dspr2.d: New file.
* gas/mips/mipsr6@mips32r2-ill.l: New file.
* gas/mips/mipsr6@mips32r2-ill.s: New file.
* gas/mips/cache.s: Add r6 instruction varients.
* gas/mips/mips.exp: Add support for the mips32r6 and mips64r6
architectures. Also prevent non r6 supported tests from running.
Finally, add in support for running the new r6 tests.
(run_dump_test_arch): Add support for mipsr6 tests.
(run_list_test_arch): Add support for using files of the
form arch@testname.l .
include/elf/
* mips.h: Add relocs: R_MIPS_PC21_S2, R_MIPS_PC26_S2, R_MIPS_PC18_S3,
R_MIPS_PC19_S2, R_MIPS_PCHI16 and R_MIPS_PCLO16.
(E_MIPS_ARCH_32R6): New define.
(E_MIPS_ARCH_64R6): New define.
include/opcode/
* mips.h (mips_operand_type): Add new entries: OP_SAME_RS_RT,
OP_CHECK_PREV and OP_NON_ZERO_REG. Add descriptions for the MIPS R6
instruction arguments: -a, -b, -d, -s, -t, -u, -v, -w, -x, -y, -A, -B,
+I, +O, +R, +:, +\, +", +;
(mips_check_prev_operand): New struct.
(INSN2_FORBIDDEN_SLOT): New define.
(INSN_ISA32R6): New define.
(INSN_ISA64R6): New define.
(INSN_UPTO32R6): New define.
(INSN_UPTO64R6): New define.
(mips_isa_table): Add INSN_UPTO32R6 and INSN_UPTO64R6.
(ISA_MIPS32R6): New define.
(ISA_MIPS64R6): New define.
(CPU_MIPS32R6): New define.
(CPU_MIPS64R6): New define.
(cpu_is_member): Add cases for CPU_MIPS32R6, and CPU_MIPS64R6.
ld/
* ldmain.c (get_emulation): Add support for -mips32r6 and -mips64r6.
opcodes/
* mips-dis.c (mips_arch_choices): Add entries for mips32r6 and
mips64r6.
(parse_mips_dis_option): Allow MSA and virtualization support for
mips64r6.
(mips_print_arg_state): Add fields dest_regno and seen_dest.
(mips_seen_register): New function.
(print_insn_arg): Refactored code to use mips_seen_register
function. Add support for OP_SAME_RS_RT, OP_CHECK_PREV and
OP_NON_ZERO_REG. Changed OP_REPEAT_DEST_REG case to print out
the register rather than aborting.
(print_insn_args): Add length argument. Add code to correctly
calculate the instruction address for pc relative instructions.
(validate_insn_args): New static function.
(print_insn_mips): Prevent jalx disassembling for r6. Use
validate_insn_args.
(print_insn_micromips): Use validate_insn_args.
all the arguments are valid.
* mips-formats.h (PREV_CHECK): New define.
* mips-opc.c (decode_mips_operand): Add support for -a, -b, -d, -s,
-t, -u, -v, -w, -x, -y, -A, -B, +I, +O, +R, +:, +\, +", +;
(RD_pc): New define.
(FS): New define.
(I37): New define.
(I69): New define.
(mips_builtin_opcodes): Add MIPS R6 instructions. Exclude recoded
MIPS R6 instructions from MIPS R2 instructions.
Diffstat (limited to 'opcodes/mips-dis.c')
-rw-r--r-- | opcodes/mips-dis.c | 216 |
1 files changed, 201 insertions, 15 deletions
diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index b797e5dad51..1eb1d45b1a3 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -572,6 +572,14 @@ const struct mips_arch_choice mips_arch_choices[] = mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + { "mips32r6", 1, bfd_mach_mipsisa32r6, CPU_MIPS32R6, + ISA_MIPS32R6, + (ASE_EVA | ASE_MSA | ASE_VIRT | ASE_XPA | ASE_MCU | ASE_MT | ASE_DSP + | ASE_DSPR2), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */ { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64, ISA_MIPS64, ASE_MIPS3D | ASE_MDMX, @@ -603,6 +611,14 @@ const struct mips_arch_choice mips_arch_choices[] = mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + { "mips64r6", 1, bfd_mach_mipsisa64r6, CPU_MIPS64R6, + ISA_MIPS64R6, + (ASE_EVA | ASE_MSA | ASE_MSA64 | ASE_XPA | ASE_VIRT | ASE_VIRT64 + | ASE_MCU | ASE_MT | ASE_DSP | ASE_DSPR2), + mips_cp0_names_mips3264r2, + mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2), + mips_cp1_names_mips3264, mips_hwr_names_mips3264r2 }, + { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1, ISA_MIPS64 | INSN_SB1, ASE_MIPS3D, mips_cp0_names_sb1, @@ -832,7 +848,8 @@ parse_mips_dis_option (const char *option, unsigned int len) mips_ase |= ASE_MSA; if ((mips_isa & INSN_ISA_MASK) == ISA_MIPS64R2 || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R3 - || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5) + || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R5 + || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6) mips_ase |= ASE_MSA64; return; } @@ -842,7 +859,8 @@ parse_mips_dis_option (const char *option, unsigned int len) mips_ase |= ASE_VIRT; if (mips_isa & ISA_MIPS64R2 || mips_isa & ISA_MIPS64R3 - || mips_isa & ISA_MIPS64R5) + || mips_isa & ISA_MIPS64R5 + || mips_isa & ISA_MIPS64R6) mips_ase |= ASE_VIRT64; return; } @@ -1084,6 +1102,8 @@ struct mips_print_arg_state { OP_REPEAT_DEST_REG and OP_REPEAT_PREV_REG. */ enum mips_reg_operand_type last_reg_type; unsigned int last_regno; + unsigned int dest_regno; + unsigned int seen_dest; }; /* Initialize STATE for the start of an instruction. */ @@ -1113,6 +1133,23 @@ print_vu0_channel (struct disassemble_info *info, abort (); } +/* Record information about a register operand. */ + +static void +mips_seen_register (struct mips_print_arg_state *state, + unsigned int regno, + enum mips_reg_operand_type reg_type) +{ + state->last_reg_type = reg_type; + state->last_regno = regno; + + if (!state->seen_dest) + { + state->seen_dest = 1; + state->dest_regno = regno; + } +} + /* Print operand OPERAND of OPCODE, using STATE to track inter-operand state. UVAL is the encoding of the operand (shifted into bit 0) and BASE_PC is the base address for OP_PCREL operands. */ @@ -1179,8 +1216,7 @@ print_insn_arg (struct disassemble_info *info, uval = mips_decode_reg_operand (reg_op, uval); print_reg (info, opcode, reg_op->reg_type, uval); - state->last_reg_type = reg_op->reg_type; - state->last_regno = uval; + mips_seen_register (state, uval, reg_op->reg_type); } break; @@ -1246,6 +1282,15 @@ print_insn_arg (struct disassemble_info *info, } break; + case OP_SAME_RS_RT: + case OP_CHECK_PREV: + case OP_NON_ZERO_REG: + { + print_reg (info, opcode, OP_REG_GP, uval & 31); + mips_seen_register (state, uval, OP_REG_GP); + } + break; + case OP_LWM_SWM_LIST: if (operand->size == 2) { @@ -1368,8 +1413,8 @@ print_insn_arg (struct disassemble_info *info, break; case OP_REPEAT_DEST_REG: - /* Should always match OP_REPEAT_PREV_REG first. */ - abort (); + print_reg (info, opcode, state->last_reg_type, state->dest_regno); + break; case OP_PC: infprintf (is, "$pc"); @@ -1392,15 +1437,130 @@ print_insn_arg (struct disassemble_info *info, } } +/* Validate the arguments for INSN, which is described by OPCODE. + Use DECODE_OPERAND to get the encoding of each operand. */ + +static bfd_boolean +validate_insn_args (const struct mips_opcode *opcode, + const struct mips_operand *(*decode_operand) (const char *), + unsigned int insn) +{ + struct mips_print_arg_state state; + const struct mips_operand *operand; + const char *s; + unsigned int uval; + + init_print_arg_state (&state); + for (s = opcode->args; *s; ++s) + { + switch (*s) + { + case ',': + case '(': + case ')': + break; + + case '#': + ++s; + break; + + default: + operand = decode_operand (s); + + if (operand) + { + uval = mips_extract_operand (operand, insn); + switch (operand->type) + { + case OP_REG: + case OP_OPTIONAL_REG: + { + const struct mips_reg_operand *reg_op; + + reg_op = (const struct mips_reg_operand *) operand; + uval = mips_decode_reg_operand (reg_op, uval); + mips_seen_register (&state, uval, reg_op->reg_type); + } + break; + + case OP_SAME_RS_RT: + { + unsigned int reg1, reg2; + + reg1 = uval & 31; + reg2 = uval >> 5; + + if (reg1 != reg2 || reg1 == 0) + return FALSE; + } + break; + + case OP_CHECK_PREV: + { + const struct mips_check_prev_operand *prev_op; + + prev_op = (const struct mips_check_prev_operand *) operand; + + if (!prev_op->zero_ok && uval == 0) + return FALSE; + + if (((prev_op->less_than_ok && uval < state.last_regno) + || (prev_op->greater_than_ok && uval > state.last_regno) + || (prev_op->equal_ok && uval == state.last_regno))) + break; + + return FALSE; + } + + case OP_NON_ZERO_REG: + { + if (uval == 0) + return FALSE; + } + break; + + case OP_INT: + case OP_MAPPED_INT: + case OP_MSB: + case OP_REG_PAIR: + case OP_PCREL: + case OP_PERF_REG: + case OP_ADDIUSP_INT: + case OP_CLO_CLZ_DEST: + case OP_LWM_SWM_LIST: + case OP_ENTRY_EXIT_LIST: + case OP_MDMX_IMM_REG: + case OP_REPEAT_PREV_REG: + case OP_REPEAT_DEST_REG: + case OP_PC: + case OP_VU0_SUFFIX: + case OP_VU0_MATCH_SUFFIX: + case OP_IMM_INDEX: + case OP_REG_INDEX: + break; + + case OP_SAVE_RESTORE_LIST: + /* Should be handled by the caller due to extend behavior. */ + abort (); + } + } + if (*s == 'm' || *s == '+' || *s == '-') + ++s; + } + } + return TRUE; +} + /* Print the arguments for INSN, which is described by OPCODE. Use DECODE_OPERAND to get the encoding of each operand. Use BASE_PC - as the base of OP_PCREL operands. */ + as the base of OP_PCREL operands, adjusting by LENGTH if the OP_PCREL + operand is for a branch or jump. */ static void print_insn_args (struct disassemble_info *info, const struct mips_opcode *opcode, const struct mips_operand *(*decode_operand) (const char *), - unsigned int insn, bfd_vma base_pc) + unsigned int insn, bfd_vma insn_pc, unsigned int length) { const fprintf_ftype infprintf = info->fprintf_func; void *is = info->stream; @@ -1462,9 +1622,27 @@ print_insn_args (struct disassemble_info *info, infprintf (is, "$%d,%d", reg, sel); } else - print_insn_arg (info, &state, opcode, operand, base_pc, - mips_extract_operand (operand, insn)); - if (*s == 'm' || *s == '+') + { + bfd_vma base_pc = insn_pc; + + /* Adjust the PC relative base so that branch/jump insns use + the following PC as the base but genuinely PC relative + operands use the current PC. */ + if (operand->type == OP_PCREL) + { + const struct mips_pcrel_operand *pcrel_op; + + pcrel_op = (const struct mips_pcrel_operand *) operand; + /* The include_isa_bit flag is sufficient to distinguish + branch/jump from other PC relative operands. */ + if (pcrel_op->include_isa_bit) + base_pc += length; + } + + print_insn_arg (info, &state, opcode, operand, base_pc, + mips_extract_operand (operand, insn)); + } + if (*s == 'm' || *s == '+' || *s == '-') ++s; break; } @@ -1530,9 +1708,11 @@ print_insn_mips (bfd_vma memaddr, && !(no_aliases && (op->pinfo2 & INSN2_ALIAS)) && (word & op->mask) == op->match) { - /* We always allow to disassemble the jalx instruction. */ + /* We always disassemble the jalx instruction, except for MIPS r6. */ if (!opcode_is_member (op, mips_isa, mips_ase, mips_processor) - && strcmp (op->name, "jalx")) + && (strcmp (op->name, "jalx") + || (mips_isa & INSN_ISA_MASK) == ISA_MIPS32R6 + || (mips_isa & INSN_ISA_MASK) == ISA_MIPS64R6)) continue; /* Figure out instruction type and branch delay information. */ @@ -1557,6 +1737,9 @@ print_insn_mips (bfd_vma memaddr, | INSN_LOAD_MEMORY)) != 0) info->insn_type = dis_dref; + if (!validate_insn_args (op, decode_mips_operand, word)) + continue; + infprintf (is, "%s", op->name); if (op->pinfo2 & INSN2_VU0_CHANNEL_SUFFIX) { @@ -1571,7 +1754,7 @@ print_insn_mips (bfd_vma memaddr, { infprintf (is, "\t"); print_insn_args (info, op, decode_mips_operand, word, - memaddr + 4); + memaddr, 4); } return INSNLEN; @@ -2077,13 +2260,16 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info) && ((length == 2 && (op->mask & 0xffff0000) == 0) || (length == 4 && (op->mask & 0xffff0000) != 0))) { + if (!validate_insn_args (op, decode_micromips_operand, insn)) + continue; + infprintf (is, "%s", op->name); if (op->args[0]) { infprintf (is, "\t"); print_insn_args (info, op, decode_micromips_operand, insn, - memaddr + length + 1); + memaddr + 1, length); } /* Figure out instruction type and branch delay information. */ |