Add support to the ARC disassembler for selecting instruction classes.

gas	* testsuite/gas/arc/dsp.d: New file.
	* testsuite/gas/arc/dsp.s: Likewise.
	* testsuite/gas/arc/fpu.d: Likewise.
	* testsuite/gas/arc/fpu.s: Likewise.
	* testsuite/gas/arc/ext2op.d: Add specific disassembler option.
	* testsuite/gas/arc/ext3op.d: Likewise.
	* testsuite/gas/arc/tdpfp.d: Likewise.
	* testsuite/gas/arc/tfpuda.d: Likewise.

opcodes	* arc-dis.c (skipclass): New structure.
	(decodelist): New variable.
	(is_compatible_p): New function.
	(new_element): Likewise.
	(skip_class_p): Likewise.
	(find_format_from_table): Use skip_class_p function.
	(find_format): Decode first the extension instructions.
	(print_insn_arc): Select either ARCEM or ARCHS based on elf
	e_flags.
	(parse_option): New function.
	(parse_disassembler_options): Likewise.
	(print_arc_disassembler_options): Likewise.
	(print_insn_arc): Use parse_disassembler_options function.  Proper
	select ARCv2 cpu variant.
	* disassemble.c (disassembler_usage): Add ARC disassembler
	options.

binutils* doc/binutils.texi (objdump): Add ARC disassembler options.
	* testsuite/binutils-all/arc/dsp.s: New file.
	* testsuite/binutils-all/arc/objdump.exp: Likewise.

include	* dis-asm.h: Declare print_arc_disassembler_options.
This commit is contained in:
Claudiu Zissulescu 2016-07-20 17:08:07 +01:00 committed by Nick Clifton
parent 0064d22386
commit 37fd5ef3ec
19 changed files with 716 additions and 124 deletions

View File

@ -1,3 +1,10 @@
2016-07-20 Claudiu Zissulescu <claziss@synopsys.com>
* doc/binutils.texi (objdump): Add ARC disassembler options.
* testsuite/binutils-all/arc/dsp.s: New file.
* testsuite/binutils-all/arc/objdump.exp: Likewise.
* NEWS: Mention the new feature.
2016-07-20 Nick Clifton <nickc@redhat.com>
* doc/binutils.texi (objcopy): Note that the localize symbol

View File

@ -1,5 +1,8 @@
-*- text -*-
* The ARC port of objdump now accepts a -M option to specify the extra
instruction class(es) that should be disassembled.
* The --remove-section option for objcopy and strip now accepts section
patterns starting with an exclamation point to indicate a non-matching
section. A non-matching section is removed from the set of sections

View File

@ -2240,6 +2240,27 @@ some targets. If it is necessary to specify more than one
disassembler option then multiple @option{-M} options can be used or
can be placed together into a comma separated list.
For the ARC architecture the option can be used to specify the extra
instruction classes that should be disassembled. A comma separated
list of one or more of the following values should be used:
@table @code
@item dsp
Recognize DSP instructions.
@item spfp
Recognize FPX SP instructions.
@item dpfp
Recognize FPX DP instructions.
@item quarkse_em
Recognize FPU QuarkSE-EM instructions.
@item fpuda
Recognize double assist FPU instructions.
@item fpus
Recognize single precision FPU instructions.
@item fpud
Recognize double precision FPU instructions.
@end table
If the target is an ARM architecture then this switch can be used to
select which register name set is used during disassembler. Specifying
@option{-M reg-names-std} (the default) will select the register names as
@ -2367,6 +2388,15 @@ ROM dumps). In these cases, the function entry mask would otherwise
be decoded as VAX instructions, which would probably lead the rest
of the function being wrongly disassembled.
For ARC, @option{dsp} controls the printing of DSP instructions,
@option{spfp} selects the printing of FPX single precision FP
instructions, @option{dpfp} selects the printing of FPX double
precision FP instructions, @option{quarkse_em} selects the printing of
special QuarkSE-EM instructions, @option{fpuda} selects the printing
of double precision assist instructions, @option{fpus} selects the
printing of FPU single precision FP instructions, while @option{fpud}
selects the printing of FPU souble precision FP instructions.
@item -p
@itemx --private-headers
Print information that is specific to the object file format. The exact

View File

@ -0,0 +1,5 @@
.cpu EM
.text
vmac2hnfr r0,r2,r4
cmacchfr r0,r2,r4
cmacchnfr r0,r2,r4

View File

@ -0,0 +1,55 @@
# Copyright (C) 2016 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
if {![istarget "arc*-*-*"]} then {
return
}
if {[which $OBJDUMP] == 0} then {
perror "$OBJDUMP does not exist"
return
}
send_user "Version [binutil_version $OBJDUMP]"
###########################
# Set up the test of dsp.s
###########################
if {![binutils_assemble $srcdir/$subdir/dsp.s tmpdir/dsp.o]} then {
return
}
if [is_remote host] {
set objfile [remote_download host tmpdir/dsp.o]
} else {
set objfile tmpdir/dsp.o
}
# Make sure that a warning message is generated (because the disassembly does
# not match the assembled instructions, which has happened because the user
# has not specified a -M option on the disassembler command line, and so the
# disassembler has had to guess as the instruction class in use).
set got [binutils_run $OBJDUMP "$OBJDUMPFLAGS --disassemble $objfile"]
set want "Warning: disassembly.*dsubh12\[ \t\]*r0,r2,r4.*dmulh12.f\[ \t\]*r0,r2,r4.*dmulh11.f"
if [regexp $want $got] then {
pass "Warning test"
} else {
fail "Warning test"
}

View File

@ -1,3 +1,14 @@
2016-07-20 Claudiu Zissulescu <claziss@synopsys.com>
* testsuite/gas/arc/dsp.d: New file.
* testsuite/gas/arc/dsp.s: Likewise.
* testsuite/gas/arc/fpu.d: Likewise.
* testsuite/gas/arc/fpu.s: Likewise.
* testsuite/gas/arc/ext2op.d: Add specific disassembler option.
* testsuite/gas/arc/ext3op.d: Likewise.
* testsuite/gas/arc/tdpfp.d: Likewise.
* testsuite/gas/arc/tfpuda.d: Likewise.
2016-07-20 Maciej W. Rozycki <macro@imgtec.com>
* config/tc-mips.c (mips_force_relocation): Remove

View File

@ -0,0 +1,96 @@
#as: -mcpu=arcem
#objdump: -dr --prefix-addresses --show-raw-insn -M dsp
.*: +file format .*arc.*
Disassembly of section .text:
0x[0-9a-f]+ 3211 0100 vmac2hnfr r0,r2,r4
0x[0-9a-f]+ 282f 0084 abssh r0,r2
0x[0-9a-f]+ 282f 003f aslacc r0
0x[0-9a-f]+ 292f 003f aslsacc r0
0x[0-9a-f]+ 2a0c 0100 asrsr r0,r2,r4
0x[0-9a-f]+ 321b 8100 cbflyhf0r r0,r2,r4
0x[0-9a-f]+ 302f 00b9 cbflyhf1r r0,r2
0x[0-9a-f]+ 3209 8100 cmacchfr r0,r2,r4
0x[0-9a-f]+ 3208 8100 cmacchnfr r0,r2,r4
0x[0-9a-f]+ 3207 8100 cmachfr r0,r2,r4
0x[0-9a-f]+ 3206 8100 cmachnfr r0,r2,r4
0x[0-9a-f]+ 3205 8100 cmpychfr r0,r2,r4
0x[0-9a-f]+ 3202 8100 cmpychnfr r0,r2,r4
0x[0-9a-f]+ 321b 0100 cmpyhfmr r0,r2,r4
0x[0-9a-f]+ 3201 8100 cmpyhfr r0,r2,r4
0x[0-9a-f]+ 3200 8100 cmpyhnfr r0,r2,r4
0x[0-9a-f]+ 2b2f 003f divacc r0
0x[0-9a-f]+ 3218 0100 dmachbl r0,r2,r4
0x[0-9a-f]+ 3219 0100 dmachbm r0,r2,r4
0x[0-9a-f]+ 2a2c 0100 dmachf r0,r2,r4
0x[0-9a-f]+ 2a2d 0100 dmachfr r0,r2,r4
0x[0-9a-f]+ 3216 0100 dmpyhbl r0,r2,r4
0x[0-9a-f]+ 3217 0100 dmpyhbm r0,r2,r4
0x[0-9a-f]+ 2a2a 0100 dmpyhf r0,r2,r4
0x[0-9a-f]+ 2a2b 0100 dmpyhfr r0,r2,r4
0x[0-9a-f]+ 2a28 0100 dmpyhwf r0,r2,r4
0x[0-9a-f]+ 2c2f 803f flagacc r0
0x[0-9a-f]+ 282f 0098 getacc r0,r2
0x[0-9a-f]+ 320c 0100 macf r0,r2,r4
0x[0-9a-f]+ 320d 0100 macfr r0,r2,r4
0x[0-9a-f]+ 3222 0100 macwhfm r0,r2,r4
0x[0-9a-f]+ 3223 0100 macwhfmr r0,r2,r4
0x[0-9a-f]+ 321d 0100 macwhl r0,r2,r4
0x[0-9a-f]+ 321f 0100 macwhul r0,r2,r4
0x[0-9a-f]+ 320a 0100 mpyf r0,r2,r4
0x[0-9a-f]+ 320b 0100 mpyfr r0,r2,r4
0x[0-9a-f]+ 3224 0100 mpywhfl r0,r2,r4
0x[0-9a-f]+ 3225 0100 mpywhflr r0,r2,r4
0x[0-9a-f]+ 3220 0100 mpywhfm r0,r2,r4
0x[0-9a-f]+ 3221 0100 mpywhfmr r0,r2,r4
0x[0-9a-f]+ 321c 0100 mpywhl r0,r2,r4
0x[0-9a-f]+ 321e 0100 mpywhul r0,r2,r4
0x[0-9a-f]+ 3215 0100 msubdf r0,r2,r4
0x[0-9a-f]+ 320e 0100 msubf r0,r2,r4
0x[0-9a-f]+ 320f 0100 msubfr r0,r2,r4
0x[0-9a-f]+ 282f 0086 negsh r0,r2
0x[0-9a-f]+ 282f 0099 normacc r0,r2
0x[0-9a-f]+ 282f 0083 rndh r0,r2
0x[0-9a-f]+ 282f 0082 sath r0,r2
0x[0-9a-f]+ 2a0d 8100 setacc r0,r2,r4
0x[0-9a-f]+ 2a2f 003f sqrtacc r0
0x[0-9a-f]+ 282f 00a8 vabs2h r0,r2
0x[0-9a-f]+ 282f 00a9 vabss2h r0,r2
0x[0-9a-f]+ 2a24 0100 vadd4b r0,r2,r4
0x[0-9a-f]+ 2a14 8100 vadds2h r0,r2,r4
0x[0-9a-f]+ 2a16 8100 vaddsubs2h r0,r2,r4
0x[0-9a-f]+ 2a0d 0100 valgn2h r0,r2,r4
0x[0-9a-f]+ 2a21 0100 vasl2h r0,r2,r4
0x[0-9a-f]+ 2a21 8100 vasls2h r0,r2,r4
0x[0-9a-f]+ 2a22 0100 vasr2h r0,r2,r4
0x[0-9a-f]+ 2a22 8100 vasrs2h r0,r2,r4
0x[0-9a-f]+ 2a23 8100 vasrsr2h r0,r2,r4
0x[0-9a-f]+ 282f 00a4 vext2bhl r0,r2
0x[0-9a-f]+ 282f 00a5 vext2bhm r0,r2
0x[0-9a-f]+ 2a23 0100 vlsr2h r0,r2,r4
0x[0-9a-f]+ 2a1e 0100 vmac2h r0,r2,r4
0x[0-9a-f]+ 2a1e 8100 vmac2hf r0,r2,r4
0x[0-9a-f]+ 2a1f 8100 vmac2hfr r0,r2,r4
0x[0-9a-f]+ 2a1f 0100 vmac2hu r0,r2,r4
0x[0-9a-f]+ 2a24 8100 vmax2h r0,r2,r4
0x[0-9a-f]+ 2a25 8100 vmin2h r0,r2,r4
0x[0-9a-f]+ 2a1c 0100 vmpy2h r0,r2,r4
0x[0-9a-f]+ 2a1c 8100 vmpy2hf r0,r2,r4
0x[0-9a-f]+ 2a1d 8100 vmpy2hfr r0,r2,r4
0x[0-9a-f]+ 2a1d 0100 vmpy2hu r0,r2,r4
0x[0-9a-f]+ 2a20 0100 vmpy2hwf r0,r2,r4
0x[0-9a-f]+ 3204 0100 vmsub2hf r0,r2,r4
0x[0-9a-f]+ 3203 0100 vmsub2hfr r0,r2,r4
0x[0-9a-f]+ 3211 8100 vmsub2hnfr r0,r2,r4
0x[0-9a-f]+ 282f 00aa vneg2h r0,r2
0x[0-9a-f]+ 282f 00ab vnegs2h r0,r2
0x[0-9a-f]+ 282f 00ac vnorm2h r0,r2
0x[0-9a-f]+ 282f 00a2 vrep2hl r0,r2
0x[0-9a-f]+ 282f 00a3 vrep2hm r0,r2
0x[0-9a-f]+ 282f 00a6 vsext2bhl r0,r2
0x[0-9a-f]+ 282f 00a7 vsext2bhm r0,r2
0x[0-9a-f]+ 2a25 0100 vsub4b r0,r2,r4
0x[0-9a-f]+ 2a17 8100 vsubadds2h r0,r2,r4
0x[0-9a-f]+ 2a15 8100 vsubs2h r0,r2,r4

View File

@ -0,0 +1,90 @@
#Test if disassembler correctly prints DSP instructions.
vmac2hnfr r0,r2,r4
abssh r0,r2
aslacc r0
aslsacc r0
asrsr r0,r2,r4
cbflyhf0r r0,r2,r4
cbflyhf1r r0,r2
cmacchfr r0,r2,r4
cmacchnfr r0,r2,r4
cmachfr r0,r2,r4
cmachnfr r0,r2,r4
cmpychfr r0,r2,r4
cmpychnfr r0,r2,r4
cmpyhfmr r0,r2,r4
cmpyhfr r0,r2,r4
cmpyhnfr r0,r2,r4
divacc r0
dmachbl r0,r2,r4
dmachbm r0,r2,r4
dmachf r0,r2,r4
dmachfr r0,r2,r4
dmpyhbl r0,r2,r4
dmpyhbm r0,r2,r4
dmpyhf r0,r2,r4
dmpyhfr r0,r2,r4
dmpyhwf r0,r2,r4
flagacc r0
getacc r0,r2
macf r0,r2,r4
macfr r0,r2,r4
macwhfm r0,r2,r4
macwhfmr r0,r2,r4
macwhl r0,r2,r4
macwhul r0,r2,r4
mpyf r0,r2,r4
mpyfr r0,r2,r4
mpywhfl r0,r2,r4
mpywhflr r0,r2,r4
mpywhfm r0,r2,r4
mpywhfmr r0,r2,r4
mpywhl r0,r2,r4
mpywhul r0,r2,r4
msubdf r0,r2,r4
msubf r0,r2,r4
msubfr r0,r2,r4
negsh r0,r2
normacc r0,r2
rndh r0,r2
sath r0,r2
setacc r0,r2,r4
sqrtacc r0
vabs2h r0,r2
vabss2h r0,r2
vadd4b r0,r2,r4
vadds2h r0,r2,r4
vaddsubs2h r0,r2,r4
valgn2h r0,r2,r4
vasl2h r0,r2,r4
vasls2h r0,r2,r4
vasr2h r0,r2,r4
vasrs2h r0,r2,r4
vasrsr2h r0,r2,r4
vext2bhl r0,r2
vext2bhm r0,r2
vlsr2h r0,r2,r4
vmac2h r0,r2,r4
vmac2hf r0,r2,r4
vmac2hfr r0,r2,r4
vmac2hu r0,r2,r4
vmax2h r0,r2,r4
vmin2h r0,r2,r4
vmpy2h r0,r2,r4
vmpy2hf r0,r2,r4
vmpy2hfr r0,r2,r4
vmpy2hu r0,r2,r4
vmpy2hwf r0,r2,r4
vmsub2hf r0,r2,r4
vmsub2hfr r0,r2,r4
vmsub2hnfr r0,r2,r4
vneg2h r0,r2
vnegs2h r0,r2
vnorm2h r0,r2
vrep2hl r0,r2
vrep2hm r0,r2
vsext2bhl r0,r2
vsext2bhm r0,r2
vsub4b r0,r2,r4
vsubadds2h r0,r2,r4
vsubs2h r0,r2,r4

View File

@ -1,5 +1,5 @@
#as: -mcpu=arcem
#objdump: -dr
#objdump: -dr -M quarkse_em
.*: +file format .*arc.*

View File

@ -1,5 +1,5 @@
#as: -mcpu=arcem
#objdump: -dr
#objdump: -dr -M quarkse_em
.*: +file format .*arc.*

View File

@ -0,0 +1,29 @@
#as: -mcpu=archs
#objdump: -dr --prefix-addresses --show-raw-insn
.*: +file format .*arc.*
Disassembly of section .text:
0x[0-9a-f]+ 3208 0100 fcvt32 r0,r2,r4
0x[0-9a-f]+ 3209 0100 fcvt32_64 r0,r2,r4
0x[0-9a-f]+ 3238 0100 fcvt64 r0,r2,r4
0x[0-9a-f]+ 3239 0100 fcvt64_32 r0,r2,r4
0x[0-9a-f]+ 3231 0100 fdadd r0,r2,r4
0x[0-9a-f]+ 3033 8080 fdcmp r0,r2
0x[0-9a-f]+ 3034 8080 fdcmpf r0,r2
0x[0-9a-f]+ 3237 0100 fddiv r0,r2,r4
0x[0-9a-f]+ 3235 0100 fdmadd r0,r2,r4
0x[0-9a-f]+ 3236 0100 fdmsub r0,r2,r4
0x[0-9a-f]+ 3230 0100 fdmul r0,r2,r4
0x[0-9a-f]+ 302f 0081 fdsqrt r0,r2
0x[0-9a-f]+ 3232 0100 fdsub r0,r2,r4
0x[0-9a-f]+ 3201 0100 fsadd r0,r2,r4
0x[0-9a-f]+ 3003 8080 fscmp r0,r2
0x[0-9a-f]+ 3004 8080 fscmpf r0,r2
0x[0-9a-f]+ 3207 0100 fsdiv r0,r2,r4
0x[0-9a-f]+ 3205 0100 fsmadd r0,r2,r4
0x[0-9a-f]+ 3206 0100 fsmsub r0,r2,r4
0x[0-9a-f]+ 3200 0100 fsmul r0,r2,r4
0x[0-9a-f]+ 302f 0080 fssqrt r0,r2
0x[0-9a-f]+ 3202 0100 fssub r0,r2,r4

View File

@ -0,0 +1,24 @@
# Test if all fpu ops are correctly disassembled as they share the
# same opcode space with FPX instructions.
fcvt32 r0,r2,r4
fcvt32_64 r0,r2,r4
fcvt64 r0,r2,r4
fcvt64_32 r0,r2,r4
fdadd r0,r2,r4
fdcmp r0,r2
fdcmpf r0,r2
fddiv r0,r2,r4
fdmadd r0,r2,r4
fdmsub r0,r2,r4
fdmul r0,r2,r4
fdsqrt r0,r2
fdsub r0,r2,r4
fsadd r0,r2,r4
fscmp r0,r2
fscmpf r0,r2
fsdiv r0,r2,r4
fsmadd r0,r2,r4
fsmsub r0,r2,r4
fsmul r0,r2,r4
fssqrt r0,r2
fssub r0,r2,r4

View File

@ -1,5 +1,5 @@
#as:-mcpu=arcem -mdpfp
#objdump: -dr
#objdump: -dr -M dpfp
#source: tfpx.s
.*: +file format .*arc.*

View File

@ -1,5 +1,5 @@
#as:-mcpu=arcem -mfpuda
#objdump: -dr
#objdump: -dr -M fpuda
#source: tfpx.s
.*: +file format .*arc.*

View File

@ -1,3 +1,7 @@
2016-07-20 Claudiu Zissulescu <claziss@synopsys.com>
* dis-asm.h: Declare print_arc_disassembler_options.
2016-07-15 Thomas Preud'homme <thomas.preudhomme@arm.com>
* bfdlink.h (struct bfd_link_info): Declare new ldscript_def and

View File

@ -328,6 +328,7 @@ extern void print_i386_disassembler_options (FILE *);
extern void print_mips_disassembler_options (FILE *);
extern void print_ppc_disassembler_options (FILE *);
extern void print_arm_disassembler_options (FILE *);
extern void print_arc_disassembler_options (FILE *);
extern void parse_arm_disassembler_option (char *);
extern void print_s390_disassembler_options (FILE *);
extern int get_arm_regname_num_options (void);

View File

@ -1,3 +1,22 @@
2016-07-20 Claudiu Zissulescu <claziss@synopsys.com>
* arc-dis.c (skipclass): New structure.
(decodelist): New variable.
(is_compatible_p): New function.
(new_element): Likewise.
(skip_class_p): Likewise.
(find_format_from_table): Use skip_class_p function.
(find_format): Decode first the extension instructions.
(print_insn_arc): Select either ARCEM or ARCHS based on elf
e_flags.
(parse_option): New function.
(parse_disassembler_options): Likewise.
(print_arc_disassembler_options): Likewise.
(print_insn_arc): Use parse_disassembler_options function. Proper
select ARCv2 cpu variant.
* disassemble.c (disassembler_usage): Add ARC disassembler
options.
2016-07-13 Maciej W. Rozycki <macro@imgtec.com>
* mips-opc.c (mips_builtin_opcodes): Remove the INSN2_ALIAS

View File

@ -25,8 +25,12 @@
#include <assert.h>
#include "dis-asm.h"
#include "opcode/arc.h"
#include "elf/arc.h"
#include "arc-dis.h"
#include "arc-ext.h"
#include "elf-bfd.h"
#include "libiberty.h"
#include "opintl.h"
/* Structure used to iterate over, and extract the values for, operands of
an opcode. */
@ -81,6 +85,20 @@ static const char * const regnames[64] =
"r56", "r57", "ACCL", "ACCH", "lp_count", "rezerved", "LIMM", "pcl"
};
/* This structure keeps track which instruction class(es)
should be ignored durring disassembling. */
typedef struct skipclass
{
insn_class_t insn_class;
insn_subclass_t subclass;
struct skipclass *nxt;
} skipclass_t, *linkclass;
/* Intial classes of instructions to be consider first when
disassembling. */
static linkclass decodelist = NULL;
/* Macros section. */
#ifdef DEBUG
@ -101,6 +119,88 @@ static const char * const regnames[64] =
/* Functions implementation. */
/* Return TRUE when two classes are not opcode conflicting. */
static bfd_boolean
is_compatible_p (insn_class_t classA,
insn_subclass_t sclassA,
insn_class_t classB,
insn_subclass_t sclassB)
{
if (classA == DSP && sclassB == DPX)
return FALSE;
if (sclassA == DPX && classB == DSP)
return FALSE;
return TRUE;
}
/* Add a new element to the decode list. */
static void
add_to_decodelist (insn_class_t insn_class,
insn_subclass_t subclass)
{
linkclass t = (linkclass) xmalloc (sizeof (skipclass_t));
t->insn_class = insn_class;
t->subclass = subclass;
t->nxt = decodelist;
decodelist = t;
}
/* Return TRUE if we need to skip the opcode from being
disassembled. */
static bfd_boolean
skip_this_opcode (const struct arc_opcode * opcode,
struct disassemble_info * info)
{
linkclass t = decodelist;
bfd_boolean addme = TRUE;
/* Check opcode for major 0x06, return if it is not in. */
if (OPCODE (opcode->opcode) != 0x06)
return FALSE;
while (t != NULL
&& is_compatible_p (t->insn_class, t->subclass,
opcode->insn_class, opcode->subclass))
{
if ((t->insn_class == opcode->insn_class)
&& (t->subclass == opcode->subclass))
addme = FALSE;
t = t->nxt;
}
/* If we found an incompatibility then we must skip. */
if (t != NULL)
return TRUE;
/* Even if we do not precisely know the if the right mnemonics
is correctly displayed, keep the disassmbled code class
consistent. */
if (addme)
{
switch (opcode->insn_class)
{
case DSP:
case FLOAT:
/* Add to the conflict list only the classes which
counts. */
add_to_decodelist (opcode->insn_class, opcode->subclass);
/* Warn if we have to decode an opcode and no preferred
classes have been chosen. */
info->fprintf_func (info->stream, _("\n\
Warning: disassembly may be wrong due to guessed opcode class choice.\n\
Use -M<class[,class]> to select the correct opcode class(es).\n\t\t\t\t"));
break;
default:
break;
}
}
return FALSE;
}
static bfd_vma
bfd_getm32 (unsigned int data)
{
@ -111,7 +211,7 @@ bfd_getm32 (unsigned int data)
return value;
}
static int
static bfd_boolean
special_flag_p (const char *opname,
const char *flgname)
{
@ -133,124 +233,137 @@ special_flag_p (const char *opname,
break; /* End of the array. */
if (strcmp (flgname, arc_flag_operands[flgidx].name) == 0)
return 1;
return TRUE;
}
}
return 0;
return FALSE;
}
/* Find opcode from ARC_TABLE given the instruction described by INSN and
INSNLEN. The ISA_MASK restricts the possible matches in ARC_TABLE. */
static const struct arc_opcode *
find_format_from_table (const struct arc_opcode *arc_table,
unsigned *insn, unsigned int insn_len,
unsigned isa_mask, bfd_boolean *has_limm)
find_format_from_table (struct disassemble_info *info,
const struct arc_opcode *arc_table,
unsigned *insn,
unsigned int insn_len,
unsigned isa_mask,
bfd_boolean *has_limm,
bfd_boolean overlaps)
{
unsigned int i = 0;
const struct arc_opcode *opcode = NULL;
const unsigned char *opidx;
const unsigned char *flgidx;
do {
bfd_boolean invalid = FALSE;
do
{
bfd_boolean invalid = FALSE;
opcode = &arc_table[i++];
opcode = &arc_table[i++];
if (ARC_SHORT (opcode->mask) && (insn_len == 2))
{
if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
continue;
}
else if (!ARC_SHORT (opcode->mask) && (insn_len == 4))
{
if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
continue;
}
else
continue;
if (ARC_SHORT (opcode->mask) && (insn_len == 2))
{
if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
continue;
}
else if (!ARC_SHORT (opcode->mask) && (insn_len == 4))
{
if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
continue;
}
else
continue;
if ((insn[0] ^ opcode->opcode) & opcode->mask)
continue;
if ((insn[0] ^ opcode->opcode) & opcode->mask)
continue;
if (!(opcode->cpu & isa_mask))
continue;
if (!(opcode->cpu & isa_mask))
continue;
*has_limm = FALSE;
*has_limm = FALSE;
/* Possible candidate, check the operands. */
for (opidx = opcode->operands; *opidx; opidx++)
{
int value;
const struct arc_operand *operand = &arc_operands[*opidx];
/* Possible candidate, check the operands. */
for (opidx = opcode->operands; *opidx; opidx++)
{
int value;
const struct arc_operand *operand = &arc_operands[*opidx];
if (operand->flags & ARC_OPERAND_FAKE)
continue;
if (operand->flags & ARC_OPERAND_FAKE)
continue;
if (operand->extract)
value = (*operand->extract) (insn[0], &invalid);
else
value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
if (operand->extract)
value = (*operand->extract) (insn[0], &invalid);
else
value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
/* Check for LIMM indicator. If it is there, then make sure
we pick the right format. */
if (operand->flags & ARC_OPERAND_IR
&& !(operand->flags & ARC_OPERAND_LIMM))
{
if ((value == 0x3E && insn_len == 4)
|| (value == 0x1E && insn_len == 2))
{
invalid = TRUE;
break;
}
}
/* Check for LIMM indicator. If it is there, then make sure
we pick the right format. */
if (operand->flags & ARC_OPERAND_IR
&& !(operand->flags & ARC_OPERAND_LIMM))
{
if ((value == 0x3E && insn_len == 4)
|| (value == 0x1E && insn_len == 2))
{
invalid = TRUE;
break;
}
}
if (operand->flags & ARC_OPERAND_LIMM
&& !(operand->flags & ARC_OPERAND_DUPLICATE))
*has_limm = TRUE;
}
if (operand->flags & ARC_OPERAND_LIMM
&& !(operand->flags & ARC_OPERAND_DUPLICATE))
*has_limm = TRUE;
}
/* Check the flags. */
for (flgidx = opcode->flags; *flgidx; flgidx++)
{
/* Get a valid flag class. */
const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
const unsigned *flgopridx;
int foundA = 0, foundB = 0;
unsigned int value;
/* Check the flags. */
for (flgidx = opcode->flags; *flgidx; flgidx++)
{
/* Get a valid flag class. */
const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
const unsigned *flgopridx;
int foundA = 0, foundB = 0;
unsigned int value;
/* Check first the extensions. */
if (cl_flags->flag_class & F_CLASS_EXTEND)
{
value = (insn[0] & 0x1F);
if (arcExtMap_condCodeName (value))
continue;
}
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand =
&arc_flag_operands[*flgopridx];
/* Check first the extensions. */
if (cl_flags->flag_class & F_CLASS_EXTEND)
{
value = (insn[0] & 0x1F);
if (arcExtMap_condCodeName (value))
continue;
}
value = (insn[0] >> flg_operand->shift)
& ((1 << flg_operand->bits) - 1);
if (value == flg_operand->code)
foundA = 1;
if (value)
foundB = 1;
}
if (!foundA && foundB)
{
invalid = TRUE;
break;
}
}
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand =
&arc_flag_operands[*flgopridx];
if (invalid)
continue;
value = (insn[0] >> flg_operand->shift)
& ((1 << flg_operand->bits) - 1);
if (value == flg_operand->code)
foundA = 1;
if (value)
foundB = 1;
}
/* The instruction is valid. */
return opcode;
} while (opcode->mask);
if (!foundA && foundB)
{
invalid = TRUE;
break;
}
}
if (invalid)
continue;
if (insn_len == 4
&& overlaps
&& skip_this_opcode (opcode, info))
continue;
/* The instruction is valid. */
return opcode;
}
while (opcode->mask);
return NULL;
}
@ -344,44 +457,42 @@ find_format_long_instructions (unsigned *insn,
the opcode's operands. */
static bfd_boolean
find_format (bfd_vma memaddr, unsigned *insn, unsigned int *insn_len,
unsigned isa_mask, struct disassemble_info *info,
const struct arc_opcode **opcode_result,
struct arc_operand_iterator *iter)
find_format (bfd_vma memaddr,
unsigned * insn,
unsigned int * insn_len,
unsigned isa_mask,
struct disassemble_info * info,
const struct arc_opcode ** opcode_result,
struct arc_operand_iterator * iter)
{
const struct arc_opcode *opcode;
const struct arc_opcode *opcode = NULL;
bfd_boolean needs_limm;
const extInstruction_t *einsn;
/* Find the first match in the opcode table. */
opcode = find_format_from_table (arc_opcodes, insn, *insn_len,
isa_mask, &needs_limm);
if (opcode == NULL)
/* First, try the extension instructions. */
einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
if (einsn != NULL)
{
const extInstruction_t *einsn;
const char *errmsg = NULL;
/* No instruction found. Try the extensions. */
einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
if (einsn != NULL)
opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
if (opcode == NULL)
{
const char *errmsg = NULL;
opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
if (opcode == NULL)
{
(*info->fprintf_func) (info->stream,
"An error occured while "
"generating the extension instruction "
"operations");
*opcode_result = NULL;
return FALSE;
}
opcode = find_format_from_table (opcode, insn, *insn_len,
isa_mask, &needs_limm);
assert (opcode != NULL);
(*info->fprintf_func) (info->stream, "\
An error occured while generating the extension instruction operations");
*opcode_result = NULL;
return FALSE;
}
opcode = find_format_from_table (info, opcode, insn, *insn_len,
isa_mask, &needs_limm, FALSE);
}
/* Then, try finding the first match in the opcode table. */
if (opcode == NULL)
opcode = find_format_from_table (info, arc_opcodes, insn, *insn_len,
isa_mask, &needs_limm, TRUE);
if (needs_limm && opcode != NULL)
{
bfd_byte buffer[4];
@ -697,6 +808,65 @@ operand_iterator_next (struct arc_operand_iterator *iter,
return TRUE;
}
/* Helper for parsing the options. */
static void
parse_option (char *option)
{
if (CONST_STRNEQ (option, "dsp"))
add_to_decodelist (DSP, NONE);
else if (CONST_STRNEQ (option, "spfp"))
add_to_decodelist (FLOAT, SPX);
else if (CONST_STRNEQ (option, "dpfp"))
add_to_decodelist (FLOAT, DPX);
else if (CONST_STRNEQ (option, "quarkse_em"))
add_to_decodelist (FLOAT, QUARKSE);
else if (CONST_STRNEQ (option, "fpuda"))
add_to_decodelist (FLOAT, DPA);
else if (CONST_STRNEQ (option, "fpud"))
{
add_to_decodelist (FLOAT, SP);
add_to_decodelist (FLOAT, CVT);
}
else if (CONST_STRNEQ (option, "fpus"))
{
add_to_decodelist (FLOAT, DP);
add_to_decodelist (FLOAT, CVT);
}
else
fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
}
/* Go over the options list and parse it. */
static void
parse_disassembler_options (char *options)
{
if (options == NULL)
return;
while (*options)
{
/* Skip empty options. */
if (*options == ',')
{
++ options;
continue;
}
parse_option (options);
while (*options != ',' && *options != '\0')
++ options;
}
}
/* Disassemble ARC instructions. */
static int
@ -716,11 +886,23 @@ print_insn_arc (bfd_vma memaddr,
const struct arc_operand *operand;
int value;
struct arc_operand_iterator iter;
Elf_Internal_Ehdr *header = NULL;
if (info->disassembler_options)
{
parse_disassembler_options (info->disassembler_options);
/* Avoid repeated parsing of the options. */
info->disassembler_options = NULL;
}
memset (&iter, 0, sizeof (iter));
lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
if (info->section && info->section->owner)
header = elf_elfheader (info->section->owner);
switch (info->mach)
{
case bfd_mach_arc_arc700:
@ -733,7 +915,15 @@ print_insn_arc (bfd_vma memaddr,
case bfd_mach_arc_arcv2:
default:
isa_mask = ARC_OPCODE_ARCv2HS | ARC_OPCODE_ARCv2EM;
isa_mask = ARC_OPCODE_ARCv2EM;
if ((header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
{
isa_mask = ARC_OPCODE_ARCv2HS;
/* FPU instructions are not extensions for HS. */
add_to_decodelist (FLOAT, SP);
add_to_decodelist (FLOAT, DP);
add_to_decodelist (FLOAT, CVT);
}
break;
}
@ -810,6 +1000,7 @@ print_insn_arc (bfd_vma memaddr,
insn_len = arc_insn_length (buffer[lowbyte], buffer[highbyte], info);
pr_debug ("instruction length = %d bytes\n", insn_len);
switch (insn_len)
{
case 2:
@ -1042,6 +1233,30 @@ arcAnalyzeInstr (bfd_vma memaddr,
return ret;
}
void
print_arc_disassembler_options (FILE *stream)
{
fprintf (stream, _("\n\
The following ARC specific disassembler options are supported for use \n\
with -M switch (multiple options should be separated by commas):\n"));
fprintf (stream, _("\
dsp Recognize DSP instructions.\n"));
fprintf (stream, _("\
spfp Recognize FPX SP instructions.\n"));
fprintf (stream, _("\
dpfp Recognize FPX DP instructions.\n"));
fprintf (stream, _("\
quarkse_em Recognize FPU QuarkSE-EM instructions.\n"));
fprintf (stream, _("\
fpuda Recognize double assist FPU instructions.\n"));
fprintf (stream, _("\
fpus Recognize single precision FPU instructions.\n"));
fprintf (stream, _("\
fpud Recognize double precision FPU instructions.\n"));
}
/* Local variables:
eval: (c-set-style "gnu")
indent-tabs-mode: t

View File

@ -547,6 +547,9 @@ disassembler_usage (FILE *stream ATTRIBUTE_UNUSED)
#ifdef ARCH_aarch64
print_aarch64_disassembler_options (stream);
#endif
#ifdef ARCH_arc
print_arc_disassembler_options (stream);
#endif
#ifdef ARCH_arm
print_arm_disassembler_options (stream);
#endif