From b240011aba98dd8a0c4736a51afcea38af814200 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 15 Mar 2012 12:58:48 +0000 Subject: [PATCH] include/ * dis-asm.h (disassemble_init_powerpc): Declare. opcodes/ * disassemble.c (disassemble_init_for_target): Handle ppc init. * ppc-dis.c (private): New var. (powerpc_init_dialect): Don't return calloc failure, instead use private. (PPC_OPCD_SEGS, PPC_OP_TO_SEG): Define. (powerpc_opcd_indices): New array. (disassemble_init_powerpc): New function. (print_insn_big_powerpc): Don't init dialect here. (print_insn_little_powerpc): Likewise. (print_insn_powerpc): Start search using powerpc_opcd_indices. --- include/ChangeLog | 4 ++++ include/dis-asm.h | 3 ++- opcodes/ChangeLog | 14 ++++++++++++ opcodes/disassemble.c | 13 ++++++++++- opcodes/ppc-dis.c | 51 ++++++++++++++++++++++++++++++++----------- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/include/ChangeLog b/include/ChangeLog index e722835785f..c5b84b57996 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2012-03-15 Alan Modra + + * dis-asm.h (disassemble_init_powerpc): Declare. + 2009-11-06 Jonas Maebe Add DWARF attribute value for the "Borland fastcall" calling diff --git a/include/dis-asm.h b/include/dis-asm.h index d2334c63c46..c9cbfbb321c 100644 --- a/include/dis-asm.h +++ b/include/dis-asm.h @@ -1,7 +1,7 @@ /* Interface between the opcode library and its callers. Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 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 @@ -314,6 +314,7 @@ extern int get_arm_regname_num_options (void); extern int set_arm_regname_option (int); extern int get_arm_regnames (int, const char **, const char **, const char *const **); extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *); +extern void disassemble_init_powerpc (struct disassemble_info *); /* Fetch the disassembler for a given BFD, if that support is available. */ extern disassembler_ftype disassembler (bfd *); diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 42a099692ef..3595faf5285 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,17 @@ +2012-03-15 Alan Modra + James Lemke + + * disassemble.c (disassemble_init_for_target): Handle ppc init. + * ppc-dis.c (private): New var. + (powerpc_init_dialect): Don't return calloc failure, instead use + private. + (PPC_OPCD_SEGS, PPC_OP_TO_SEG): Define. + (powerpc_opcd_indices): New array. + (disassemble_init_powerpc): New function. + (print_insn_big_powerpc): Don't init dialect here. + (print_insn_little_powerpc): Likewise. + (print_insn_powerpc): Start search using powerpc_opcd_indices. + 2012-03-10 Edmar Wienskoski * ppc-dis.c (ppc_opts): Add entries for "e5500" and "e6500". diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c index 0b6313537ca..43e1d53eb40 100644 --- a/opcodes/disassemble.c +++ b/opcodes/disassemble.c @@ -1,6 +1,7 @@ /* Select disassembly routine for specified architecture. Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Free Software Foundation, Inc. This file is part of the GNU opcodes library. @@ -565,6 +566,16 @@ disassemble_init_for_target (struct disassemble_info * info) cgen_bitset_set (info->insn_sets, ISA_M32C); } break; +#endif +#ifdef ARCH_powerpc + case bfd_arch_powerpc: +#endif +#ifdef ARCH_rs6000 + case bfd_arch_rs6000: +#endif +#if defined (ARCH_powerpc) || defined (ARCH_rs6000) + disassemble_init_powerpc (info); + break; #endif default: break; diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index e1c9f1b05c3..d2cd2e59166 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -38,7 +38,7 @@ struct dis_private { /* Stash the result of parsing disassembler_options here. */ ppc_cpu_t dialect; -}; +} private; #define POWERPC_DIALECT(INFO) \ (((struct dis_private *) ((INFO)->private_data))->dialect) @@ -217,7 +217,7 @@ ppc_parse_cpu (ppc_cpu_t ppc_cpu, const char *arg) /* Determine which set of machines to disassemble for. */ -static int +static void powerpc_init_dialect (struct disassemble_info *info) { ppc_cpu_t dialect = 0; @@ -225,7 +225,7 @@ powerpc_init_dialect (struct disassemble_info *info) struct dis_private *priv = calloc (sizeof (*priv), 1); if (priv == NULL) - return FALSE; + priv = &private; arg = info->disassembler_options; while (arg != NULL) @@ -263,8 +263,34 @@ powerpc_init_dialect (struct disassemble_info *info) info->private_data = priv; POWERPC_DIALECT(info) = dialect; +} + +#define PPC_OPCD_SEGS 64 +#define PPC_OP_TO_SEG(i) (i) +static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS]; + +/* Calculate opcode table indices to speed up disassembly, + and init dialect. */ + +void +disassemble_init_powerpc (struct disassemble_info *info) +{ + int i; + + for (i = 0; i < PPC_OPCD_SEGS; ++i) + powerpc_opcd_indices[i] = powerpc_num_opcodes; - return TRUE; + i = powerpc_num_opcodes; + while (--i >= 0) + { + unsigned op = PPC_OP (powerpc_opcodes[i].opcode); + unsigned seg = PPC_OP_TO_SEG (op); + + powerpc_opcd_indices[seg] = i; + } + + if (info->arch == bfd_arch_powerpc) + powerpc_init_dialect (info); } /* Print a big endian PowerPC instruction. */ @@ -272,8 +298,6 @@ powerpc_init_dialect (struct disassemble_info *info) int print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) { - if (info->private_data == NULL && !powerpc_init_dialect (info)) - return -1; return print_insn_powerpc (memaddr, info, 1, POWERPC_DIALECT(info)); } @@ -282,8 +306,6 @@ print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) int print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) { - if (info->private_data == NULL && !powerpc_init_dialect (info)) - return -1; return print_insn_powerpc (memaddr, info, 0, POWERPC_DIALECT(info)); } @@ -375,11 +397,14 @@ print_insn_powerpc (bfd_vma memaddr, /* Get the major opcode of the instruction. */ op = PPC_OP (insn); - /* Find the first match in the opcode table. We could speed this up - a bit by doing a binary search on the major opcode. */ + /* Find the first match in the opcode table. + We speed this up by segmenting the opcode table and starting the search + at one of the segment boundaries. */ opcode_end = powerpc_opcodes + powerpc_num_opcodes; again: - for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) + for (opcode = powerpc_opcodes + powerpc_opcd_indices[PPC_OP_TO_SEG (op)]; + opcode < opcode_end; + ++opcode) { unsigned long table_op; const unsigned char *opindex; @@ -390,10 +415,10 @@ print_insn_powerpc (bfd_vma memaddr, int skip_optional; table_op = PPC_OP (opcode->opcode); - if (op < table_op) - break; if (op > table_op) continue; + if (op < table_op) + break; if ((insn & opcode->mask) != opcode->opcode || (opcode->flags & dialect) == 0 -- 2.30.2