From 8ddfa96fcd388fb183d7aac8befd08c138e105dd Mon Sep 17 00:00:00 2001 From: nobody <> Date: Wed, 16 Apr 2003 04:55:32 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'carlton_dictionary-branch'. Cherrypick from master 2003-04-16 04:55:31 UTC DJ Delorie 'merge from gcc': bfd/cpu-xtensa.c bfd/elf32-xtensa.c bfd/po/zh_CN.po bfd/xtensa-isa.c bfd/xtensa-modules.c gdb/cp-namespace.c gdb/doc/observer.texi gdb/frame-base.c gdb/frame-base.h gdb/i386-cygwin-tdep.c gdb/infttrace.h gdb/mi/mi-cmd-file.c gdb/testsuite/gdb.arch/e500-abi.c gdb/testsuite/gdb.arch/e500-abi.exp gdb/testsuite/gdb.arch/e500-regs.c gdb/testsuite/gdb.arch/e500-regs.exp gdb/testsuite/gdb.asm/m68hc11.inc gdb/testsuite/gdb.base/gdb1090.c gdb/testsuite/gdb.base/gdb1090.exp gdb/testsuite/gdb.c++/maint.exp gdb/testsuite/gdb.gdb/observer.exp gdb/testsuite/gdb.mi/mi-file.exp include/elf/xtensa.h include/xtensa-config.h include/xtensa-isa-internal.h include/xtensa-isa.h libiberty/mempcpy.c libiberty/stpcpy.c libiberty/stpncpy.c opcodes/xtensa-dis.c sim/arm/iwmmxt.c sim/arm/iwmmxt.h sim/arm/maverick.c --- bfd/cpu-xtensa.c | 38 + bfd/elf32-xtensa.c | 5845 ++++++++++++++++++++++++++++++++ bfd/po/zh_CN.po | 2702 +++++++++++++++ bfd/xtensa-isa.c | 593 ++++ bfd/xtensa-modules.c | 6088 ++++++++++++++++++++++++++++++++++ gdb/cp-namespace.c | 266 ++ gdb/doc/observer.texi | 70 + gdb/frame-base.c | 154 + gdb/frame-base.h | 94 + gdb/i386-cygwin-tdep.c | 86 + gdb/infttrace.h | 28 + gdb/mi/mi-cmd-file.c | 67 + gdb/testsuite/gdb.arch/e500-abi.c | 106 + gdb/testsuite/gdb.arch/e500-abi.exp | 90 + gdb/testsuite/gdb.arch/e500-regs.c | 38 + gdb/testsuite/gdb.arch/e500-regs.exp | 229 ++ gdb/testsuite/gdb.asm/m68hc11.inc | 49 + gdb/testsuite/gdb.base/gdb1090.c | 48 + gdb/testsuite/gdb.base/gdb1090.exp | 67 + gdb/testsuite/gdb.c++/maint.exp | 79 + gdb/testsuite/gdb.gdb/observer.exp | 274 ++ gdb/testsuite/gdb.mi/mi-file.exp | 65 + include/elf/xtensa.h | 87 + include/xtensa-config.h | 64 + include/xtensa-isa-internal.h | 114 + include/xtensa-isa.h | 230 ++ libiberty/mempcpy.c | 48 + libiberty/stpcpy.c | 49 + libiberty/stpncpy.c | 54 + opcodes/xtensa-dis.c | 526 +++ sim/arm/iwmmxt.c | 3730 +++++++++++++++++++++ sim/arm/iwmmxt.h | 28 + sim/arm/maverick.c | 1291 +++++++ 33 files changed, 23297 insertions(+) create mode 100644 bfd/cpu-xtensa.c create mode 100644 bfd/elf32-xtensa.c create mode 100644 bfd/po/zh_CN.po create mode 100644 bfd/xtensa-isa.c create mode 100644 bfd/xtensa-modules.c create mode 100644 gdb/cp-namespace.c create mode 100644 gdb/doc/observer.texi create mode 100644 gdb/frame-base.c create mode 100644 gdb/frame-base.h create mode 100644 gdb/i386-cygwin-tdep.c create mode 100644 gdb/infttrace.h create mode 100644 gdb/mi/mi-cmd-file.c create mode 100644 gdb/testsuite/gdb.arch/e500-abi.c create mode 100644 gdb/testsuite/gdb.arch/e500-abi.exp create mode 100644 gdb/testsuite/gdb.arch/e500-regs.c create mode 100644 gdb/testsuite/gdb.arch/e500-regs.exp create mode 100644 gdb/testsuite/gdb.asm/m68hc11.inc create mode 100644 gdb/testsuite/gdb.base/gdb1090.c create mode 100644 gdb/testsuite/gdb.base/gdb1090.exp create mode 100644 gdb/testsuite/gdb.c++/maint.exp create mode 100644 gdb/testsuite/gdb.gdb/observer.exp create mode 100644 gdb/testsuite/gdb.mi/mi-file.exp create mode 100644 include/elf/xtensa.h create mode 100644 include/xtensa-config.h create mode 100644 include/xtensa-isa-internal.h create mode 100644 include/xtensa-isa.h create mode 100644 libiberty/mempcpy.c create mode 100644 libiberty/stpcpy.c create mode 100644 libiberty/stpncpy.c create mode 100644 opcodes/xtensa-dis.c create mode 100644 sim/arm/iwmmxt.c create mode 100644 sim/arm/iwmmxt.h create mode 100644 sim/arm/maverick.c diff --git a/bfd/cpu-xtensa.c b/bfd/cpu-xtensa.c new file mode 100644 index 0000000..fbfff64 --- /dev/null +++ b/bfd/cpu-xtensa.c @@ -0,0 +1,38 @@ +/* BFD support for the Xtensa processor. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_xtensa_arch = +{ + 32, /* Bits per word. */ + 32, /* Bits per address. */ + 8, /* Bits per byte. */ + bfd_arch_xtensa, /* Architecture. */ + bfd_mach_xtensa, /* Machine. */ + "xtensa", /* Architecture name. */ + "xtensa", /* Printable name. */ + 4, /* Section align power. */ + TRUE, /* The default? */ + bfd_default_compatible, /* Architecture comparison fn. */ + bfd_default_scan, /* String to architecture convert fn. */ + NULL /* Next in list. */ +}; diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c new file mode 100644 index 0000000..b991df4 --- /dev/null +++ b/bfd/elf32-xtensa.c @@ -0,0 +1,5845 @@ +/* Xtensa-specific support for 32-bit ELF. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#include + +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/xtensa.h" +#include "xtensa-isa.h" +#include "xtensa-config.h" + +/* Main interface functions. */ +static void elf_xtensa_info_to_howto_rela + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static reloc_howto_type *elf_xtensa_reloc_type_lookup + PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); +extern int xtensa_read_table_entries + PARAMS ((bfd *, asection *, property_table_entry **, const char *)); +static bfd_boolean elf_xtensa_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static void elf_xtensa_hide_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); +static void elf_xtensa_copy_indirect_symbol + PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *)); +static asection *elf_xtensa_gc_mark_hook + PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); +static bfd_boolean elf_xtensa_gc_sweep_hook + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static bfd_boolean elf_xtensa_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_xtensa_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static bfd_boolean elf_xtensa_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_xtensa_modify_segment_map + PARAMS ((bfd *)); +static bfd_boolean elf_xtensa_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static bfd_boolean elf_xtensa_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *again)); +static bfd_boolean elf_xtensa_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static bfd_boolean elf_xtensa_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_xtensa_merge_private_bfd_data + PARAMS ((bfd *, bfd *)); +static bfd_boolean elf_xtensa_set_private_flags + PARAMS ((bfd *, flagword)); +extern flagword elf_xtensa_get_private_bfd_flags + PARAMS ((bfd *)); +static bfd_boolean elf_xtensa_print_private_bfd_data + PARAMS ((bfd *, PTR)); +static bfd_boolean elf_xtensa_object_p + PARAMS ((bfd *)); +static void elf_xtensa_final_write_processing + PARAMS ((bfd *, bfd_boolean)); +static enum elf_reloc_type_class elf_xtensa_reloc_type_class + PARAMS ((const Elf_Internal_Rela *)); +static bfd_boolean elf_xtensa_discard_info + PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *)); +static bfd_boolean elf_xtensa_ignore_discarded_relocs + PARAMS ((asection *)); +static bfd_boolean elf_xtensa_grok_prstatus + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elf_xtensa_grok_psinfo + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elf_xtensa_new_section_hook + PARAMS ((bfd *, asection *)); + + +/* Local helper functions. */ + +static int property_table_compare + PARAMS ((const PTR, const PTR)); +static bfd_boolean elf_xtensa_in_literal_pool + PARAMS ((property_table_entry *, int, bfd_vma)); +static void elf_xtensa_make_sym_local + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static bfd_boolean add_extra_plt_sections + PARAMS ((bfd *, int)); +static bfd_boolean elf_xtensa_fix_refcounts + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_xtensa_allocate_plt_size + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_xtensa_allocate_got_size + PARAMS ((struct elf_link_hash_entry *, PTR)); +static void elf_xtensa_allocate_local_got_size + PARAMS ((struct bfd_link_info *, asection *)); +static bfd_reloc_status_type elf_xtensa_do_reloc + PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_vma, bfd_byte *, + bfd_vma, bfd_boolean, char **)); +static char * vsprint_msg + VPARAMS ((const char *, const char *, int, ...)); +static char *build_encoding_error_message + PARAMS ((xtensa_opcode, xtensa_encode_result)); +static bfd_reloc_status_type bfd_elf_xtensa_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +static void do_fix_for_relocateable_link + PARAMS ((Elf_Internal_Rela *, bfd *, asection *)); +static void do_fix_for_final_link + PARAMS ((Elf_Internal_Rela *, asection *, bfd_vma *)); +static bfd_boolean xtensa_elf_dynamic_symbol_p + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static bfd_vma elf_xtensa_create_plt_entry + PARAMS ((bfd *, bfd *, unsigned)); +static int elf_xtensa_combine_prop_entries + PARAMS ((bfd *, const char *)); +static bfd_boolean elf_xtensa_discard_info_for_section + PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *, + asection *)); + +/* Local functions to handle Xtensa configurability. */ + +static void init_call_opcodes + PARAMS ((void)); +static bfd_boolean is_indirect_call_opcode + PARAMS ((xtensa_opcode)); +static bfd_boolean is_direct_call_opcode + PARAMS ((xtensa_opcode)); +static bfd_boolean is_windowed_call_opcode + PARAMS ((xtensa_opcode)); +static xtensa_opcode get_l32r_opcode + PARAMS ((void)); +static bfd_vma l32r_offset + PARAMS ((bfd_vma, bfd_vma)); +static int get_relocation_opnd + PARAMS ((Elf_Internal_Rela *)); +static xtensa_opcode get_relocation_opcode + PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *)); +static bfd_boolean is_l32r_relocation + PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *)); + +/* Functions for link-time code simplifications. */ + +static bfd_reloc_status_type elf_xtensa_do_asm_simplify + PARAMS ((bfd_byte *, bfd_vma, bfd_vma)); +static bfd_reloc_status_type contract_asm_expansion + PARAMS ((bfd_byte *, bfd_vma, Elf_Internal_Rela *)); +static xtensa_opcode swap_callx_for_call_opcode + PARAMS ((xtensa_opcode)); +static xtensa_opcode get_expanded_call_opcode + PARAMS ((bfd_byte *, int)); + +/* Access to internal relocations, section contents and symbols. */ + +static Elf_Internal_Rela *retrieve_internal_relocs + PARAMS ((bfd *, asection *, bfd_boolean)); +static void pin_internal_relocs + PARAMS ((asection *, Elf_Internal_Rela *)); +static void release_internal_relocs + PARAMS ((asection *, Elf_Internal_Rela *)); +static bfd_byte *retrieve_contents + PARAMS ((bfd *, asection *, bfd_boolean)); +static void pin_contents + PARAMS ((asection *, bfd_byte *)); +static void release_contents + PARAMS ((asection *, bfd_byte *)); +static Elf_Internal_Sym *retrieve_local_syms + PARAMS ((bfd *)); + +/* Miscellaneous utility functions. */ + +static asection *elf_xtensa_get_plt_section + PARAMS ((bfd *, int)); +static asection *elf_xtensa_get_gotplt_section + PARAMS ((bfd *, int)); +static asection *get_elf_r_symndx_section + PARAMS ((bfd *, unsigned long)); +static struct elf_link_hash_entry *get_elf_r_symndx_hash_entry + PARAMS ((bfd *, unsigned long)); +static bfd_vma get_elf_r_symndx_offset + PARAMS ((bfd *, unsigned long)); +static bfd_boolean pcrel_reloc_fits + PARAMS ((xtensa_operand, bfd_vma, bfd_vma)); +static bfd_boolean xtensa_is_property_section + PARAMS ((asection *)); +static bfd_boolean is_literal_section + PARAMS ((asection *)); +static int internal_reloc_compare + PARAMS ((const PTR, const PTR)); +static bfd_boolean get_is_linkonce_section + PARAMS ((bfd *, asection *)); +extern char *xtensa_get_property_section_name + PARAMS ((bfd *, asection *, const char *)); + +/* Other functions called directly by the linker. */ + +typedef void (*deps_callback_t) + PARAMS ((asection *, bfd_vma, asection *, bfd_vma, PTR)); +extern bfd_boolean xtensa_callback_required_dependence + PARAMS ((bfd *, asection *, struct bfd_link_info *, + deps_callback_t, PTR)); + + +typedef struct xtensa_relax_info_struct xtensa_relax_info; + + +/* Total count of PLT relocations seen during check_relocs. + The actual PLT code must be split into multiple sections and all + the sections have to be created before size_dynamic_sections, + where we figure out the exact number of PLT entries that will be + needed. It is OK is this count is an overestimate, e.g., some + relocations may be removed by GC. */ + +static int plt_reloc_count = 0; + + +/* When this is true, relocations may have been modified to refer to + symbols from other input files. The per-section list of "fix" + records needs to be checked when resolving relocations. */ + +static bfd_boolean relaxing_section = FALSE; + + +static reloc_howto_type elf_howto_table[] = +{ + HOWTO (R_XTENSA_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_NONE", + FALSE, 0x00000000, 0x00000000, FALSE), + HOWTO (R_XTENSA_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_xtensa_reloc, "R_XTENSA_32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + /* Replace a 32-bit value with a value from the runtime linker (only + used by linker-generated stub functions). The r_addend value is + special: 1 means to substitute a pointer to the runtime linker's + dynamic resolver function; 2 means to substitute the link map for + the shared object. */ + HOWTO (R_XTENSA_RTLD, 0, 2, 32, FALSE, 0, complain_overflow_dont, + NULL, "R_XTENSA_RTLD", + FALSE, 0x00000000, 0x00000000, FALSE), + HOWTO (R_XTENSA_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_XTENSA_GLOB_DAT", + FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO (R_XTENSA_JMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_XTENSA_JMP_SLOT", + FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO (R_XTENSA_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_XTENSA_RELATIVE", + FALSE, 0xffffffff, 0xffffffff, FALSE), + HOWTO (R_XTENSA_PLT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_xtensa_reloc, "R_XTENSA_PLT", + FALSE, 0xffffffff, 0xffffffff, FALSE), + EMPTY_HOWTO (7), + HOWTO (R_XTENSA_OP0, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_OP0", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_OP1, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_OP1", + FALSE, 0x00000000, 0x00000000, TRUE), + HOWTO (R_XTENSA_OP2, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_OP2", + FALSE, 0x00000000, 0x00000000, TRUE), + /* Assembly auto-expansion. */ + HOWTO (R_XTENSA_ASM_EXPAND, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_ASM_EXPAND", + FALSE, 0x00000000, 0x00000000, FALSE), + /* Relax assembly auto-expansion. */ + HOWTO (R_XTENSA_ASM_SIMPLIFY, 0, 0, 0, TRUE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_ASM_SIMPLIFY", + FALSE, 0x00000000, 0x00000000, TRUE), + EMPTY_HOWTO (13), + EMPTY_HOWTO (14), + /* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_XTENSA_GNU_VTINHERIT, 0, 2, 0, FALSE, 0, complain_overflow_dont, + NULL, "R_XTENSA_GNU_VTINHERIT", + FALSE, 0x00000000, 0x00000000, FALSE), + /* GNU extension to record C++ vtable member usage. */ + HOWTO (R_XTENSA_GNU_VTENTRY, 0, 2, 0, FALSE, 0, complain_overflow_dont, + _bfd_elf_rel_vtable_reloc_fn, "R_XTENSA_GNU_VTENTRY", + FALSE, 0x00000000, 0x00000000, FALSE) +}; + +#ifdef DEBUG_GEN_RELOC +#define TRACE(str) \ + fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str) +#else +#define TRACE(str) +#endif + +static reloc_howto_type * +elf_xtensa_reloc_type_lookup (abfd, code) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_NONE: + TRACE ("BFD_RELOC_NONE"); + return &elf_howto_table[(unsigned) R_XTENSA_NONE ]; + + case BFD_RELOC_32: + TRACE ("BFD_RELOC_32"); + return &elf_howto_table[(unsigned) R_XTENSA_32 ]; + + case BFD_RELOC_XTENSA_RTLD: + TRACE ("BFD_RELOC_XTENSA_RTLD"); + return &elf_howto_table[(unsigned) R_XTENSA_RTLD ]; + + case BFD_RELOC_XTENSA_GLOB_DAT: + TRACE ("BFD_RELOC_XTENSA_GLOB_DAT"); + return &elf_howto_table[(unsigned) R_XTENSA_GLOB_DAT ]; + + case BFD_RELOC_XTENSA_JMP_SLOT: + TRACE ("BFD_RELOC_XTENSA_JMP_SLOT"); + return &elf_howto_table[(unsigned) R_XTENSA_JMP_SLOT ]; + + case BFD_RELOC_XTENSA_RELATIVE: + TRACE ("BFD_RELOC_XTENSA_RELATIVE"); + return &elf_howto_table[(unsigned) R_XTENSA_RELATIVE ]; + + case BFD_RELOC_XTENSA_PLT: + TRACE ("BFD_RELOC_XTENSA_PLT"); + return &elf_howto_table[(unsigned) R_XTENSA_PLT ]; + + case BFD_RELOC_XTENSA_OP0: + TRACE ("BFD_RELOC_XTENSA_OP0"); + return &elf_howto_table[(unsigned) R_XTENSA_OP0 ]; + + case BFD_RELOC_XTENSA_OP1: + TRACE ("BFD_RELOC_XTENSA_OP1"); + return &elf_howto_table[(unsigned) R_XTENSA_OP1 ]; + + case BFD_RELOC_XTENSA_OP2: + TRACE ("BFD_RELOC_XTENSA_OP2"); + return &elf_howto_table[(unsigned) R_XTENSA_OP2 ]; + + case BFD_RELOC_XTENSA_ASM_EXPAND: + TRACE ("BFD_RELOC_XTENSA_ASM_EXPAND"); + return &elf_howto_table[(unsigned) R_XTENSA_ASM_EXPAND ]; + + case BFD_RELOC_XTENSA_ASM_SIMPLIFY: + TRACE ("BFD_RELOC_XTENSA_ASM_SIMPLIFY"); + return &elf_howto_table[(unsigned) R_XTENSA_ASM_SIMPLIFY ]; + + case BFD_RELOC_VTABLE_INHERIT: + TRACE ("BFD_RELOC_VTABLE_INHERIT"); + return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTINHERIT ]; + + case BFD_RELOC_VTABLE_ENTRY: + TRACE ("BFD_RELOC_VTABLE_ENTRY"); + return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ]; + + default: + break; + } + + TRACE ("Unknown"); + return NULL; +} + + +/* Given an ELF "rela" relocation, find the corresponding howto and record + it in the BFD internal arelent representation of the relocation. */ + +static void +elf_xtensa_info_to_howto_rela (abfd, cache_ptr, dst) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + + BFD_ASSERT (r_type < (unsigned int) R_XTENSA_max); + cache_ptr->howto = &elf_howto_table[r_type]; +} + + +/* Functions for the Xtensa ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so" + +/* The size in bytes of an entry in the procedure linkage table. + (This does _not_ include the space for the literals associated with + the PLT entry.) */ + +#define PLT_ENTRY_SIZE 16 + +/* For _really_ large PLTs, we may need to alternate between literals + and code to keep the literals within the 256K range of the L32R + instructions in the code. It's unlikely that anyone would ever need + such a big PLT, but an arbitrary limit on the PLT size would be bad. + Thus, we split the PLT into chunks. Since there's very little + overhead (2 extra literals) for each chunk, the chunk size is kept + small so that the code for handling multiple chunks get used and + tested regularly. With 254 entries, there are 1K of literals for + each chunk, and that seems like a nice round number. */ + +#define PLT_ENTRIES_PER_CHUNK 254 + +/* PLT entries are actually used as stub functions for lazy symbol + resolution. Once the symbol is resolved, the stub function is never + invoked. Note: the 32-byte frame size used here cannot be changed + without a corresponding change in the runtime linker. */ + +static const bfd_byte elf_xtensa_be_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x6c, 0x10, 0x04, /* entry sp, 32 */ + 0x18, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ + 0x1a, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ + 0x1b, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ + 0x0a, 0x80, 0x00, /* jx a8 */ + 0 /* unused */ +}; + +static const bfd_byte elf_xtensa_le_plt_entry[PLT_ENTRY_SIZE] = +{ + 0x36, 0x41, 0x00, /* entry sp, 32 */ + 0x81, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */ + 0xa1, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */ + 0xb1, 0x00, 0x00, /* l32r a11, [literal for reloc index] */ + 0xa0, 0x08, 0x00, /* jx a8 */ + 0 /* unused */ +}; + + +static int +property_table_compare (ap, bp) + const PTR ap; + const PTR bp; +{ + const property_table_entry *a = (const property_table_entry *) ap; + const property_table_entry *b = (const property_table_entry *) bp; + + /* Check if one entry overlaps with the other; this shouldn't happen + except when searching for a match. */ + if ((b->address >= a->address && b->address < (a->address + a->size)) + || (a->address >= b->address && a->address < (b->address + b->size))) + return 0; + + return (a->address - b->address); +} + + +/* Get the literal table or instruction table entries for the given + section. Sets TABLE_P and returns the number of entries. On error, + returns a negative value. */ + +int +xtensa_read_table_entries (abfd, section, table_p, sec_name) + bfd *abfd; + asection *section; + property_table_entry **table_p; + const char *sec_name; +{ + asection *table_section; + char *table_section_name; + bfd_size_type table_size = 0; + bfd_byte *table_data; + property_table_entry *blocks; + int block_count; + bfd_size_type num_records; + Elf_Internal_Rela *internal_relocs; + + table_section_name = + xtensa_get_property_section_name (abfd, section, sec_name); + table_section = bfd_get_section_by_name (abfd, table_section_name); + if (table_section != NULL) + table_size = bfd_get_section_size_before_reloc (table_section); + + if (table_size == 0) + { + *table_p = NULL; + return 0; + } + + num_records = table_size / sizeof (property_table_entry); + table_data = retrieve_contents (abfd, table_section, TRUE); + blocks = (property_table_entry *) + bfd_malloc (num_records * sizeof (property_table_entry)); + block_count = 0; + + /* If the file has not yet been relocated, process the relocations + and sort out the table entries that apply to the specified section. */ + internal_relocs = retrieve_internal_relocs (abfd, table_section, TRUE); + if (internal_relocs) + { + unsigned i; + + for (i = 0; i < table_section->reloc_count; i++) + { + Elf_Internal_Rela *rel = &internal_relocs[i]; + unsigned long r_symndx; + + if (ELF32_R_TYPE (rel->r_info) == R_XTENSA_NONE) + continue; + + BFD_ASSERT (ELF32_R_TYPE (rel->r_info) == R_XTENSA_32); + r_symndx = ELF32_R_SYM (rel->r_info); + + if (get_elf_r_symndx_section (abfd, r_symndx) == section) + { + bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx); + blocks[block_count].address = + (section->vma + sym_off + rel->r_addend + + bfd_get_32 (abfd, table_data + rel->r_offset)); + blocks[block_count].size = + bfd_get_32 (abfd, table_data + rel->r_offset + 4); + block_count++; + } + } + } + else + { + /* No relocations. Presumably the file has been relocated + and the addresses are already in the table. */ + bfd_vma off; + + for (off = 0; off < table_size; off += sizeof (property_table_entry)) + { + bfd_vma address = bfd_get_32 (abfd, table_data + off); + + if (address >= section->vma + && address < ( section->vma + section->_raw_size)) + { + blocks[block_count].address = address; + blocks[block_count].size = + bfd_get_32 (abfd, table_data + off + 4); + block_count++; + } + } + } + + release_contents (table_section, table_data); + release_internal_relocs (table_section, internal_relocs); + + if (block_count > 0) + { + /* Now sort them into address order for easy reference. */ + qsort (blocks, block_count, sizeof (property_table_entry), + property_table_compare); + } + + *table_p = blocks; + return block_count; +} + + +static bfd_boolean +elf_xtensa_in_literal_pool (lit_table, lit_table_size, addr) + property_table_entry *lit_table; + int lit_table_size; + bfd_vma addr; +{ + property_table_entry entry; + + if (lit_table_size == 0) + return FALSE; + + entry.address = addr; + entry.size = 1; + + if (bsearch (&entry, lit_table, lit_table_size, + sizeof (property_table_entry), property_table_compare)) + return TRUE; + + return FALSE; +} + + +/* Look through the relocs for a section during the first phase, and + calculate needed space in the dynamic reloc sections. */ + +static bfd_boolean +elf_xtensa_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + property_table_entry *lit_table; + int ltblsize; + + if (info->relocateable) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + ltblsize = xtensa_read_table_entries (abfd, sec, &lit_table, + XTENSA_LIT_SEC_NAME); + if (ltblsize < 0) + return FALSE; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned int r_type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); + + if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) + { + (*_bfd_error_handler) (_("%s: bad symbol index: %d"), + bfd_archive_filename (abfd), + r_symndx); + return FALSE; + } + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + switch (r_type) + { + case R_XTENSA_32: + if (h == NULL) + goto local_literal; + + if ((sec->flags & SEC_ALLOC) != 0) + { + if ((sec->flags & SEC_READONLY) != 0 + && !elf_xtensa_in_literal_pool (lit_table, ltblsize, + sec->vma + rel->r_offset)) + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + if (h->got.refcount <= 0) + h->got.refcount = 1; + else + h->got.refcount += 1; + } + break; + + case R_XTENSA_PLT: + /* If this relocation is against a local symbol, then it's + exactly the same as a normal local GOT entry. */ + if (h == NULL) + goto local_literal; + + if ((sec->flags & SEC_ALLOC) != 0) + { + if ((sec->flags & SEC_READONLY) != 0 + && !elf_xtensa_in_literal_pool (lit_table, ltblsize, + sec->vma + rel->r_offset)) + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + if (h->plt.refcount <= 0) + { + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->plt.refcount = 1; + } + else + h->plt.refcount += 1; + + /* Keep track of the total PLT relocation count even if we + don't yet know whether the dynamic sections will be + created. */ + plt_reloc_count += 1; + + if (elf_hash_table (info)->dynamic_sections_created) + { + if (!add_extra_plt_sections (elf_hash_table (info)->dynobj, + plt_reloc_count)) + return FALSE; + } + } + break; + + local_literal: + if ((sec->flags & SEC_ALLOC) != 0) + { + bfd_signed_vma *local_got_refcounts; + + /* This is a global offset table entry for a local symbol. */ + local_got_refcounts = elf_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + size *= sizeof (bfd_signed_vma); + local_got_refcounts = ((bfd_signed_vma *) + bfd_zalloc (abfd, size)); + if (local_got_refcounts == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = local_got_refcounts; + } + local_got_refcounts[r_symndx] += 1; + + /* If the relocation is not inside the GOT, the DF_TEXTREL + flag needs to be set. */ + if (info->shared + && (sec->flags & SEC_READONLY) != 0 + && !elf_xtensa_in_literal_pool (lit_table, ltblsize, + sec->vma + rel->r_offset)) + info->flags |= DF_TEXTREL; + } + break; + + case R_XTENSA_OP0: + case R_XTENSA_OP1: + case R_XTENSA_OP2: + case R_XTENSA_ASM_EXPAND: + case R_XTENSA_ASM_SIMPLIFY: + /* Nothing to do for these. */ + break; + + case R_XTENSA_GNU_VTINHERIT: + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + case R_XTENSA_GNU_VTENTRY: + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + + default: + break; + } + } + + free (lit_table); + return TRUE; +} + + +static void +elf_xtensa_hide_symbol (info, h, force_local) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + bfd_boolean force_local; +{ + /* For a shared link, move the plt refcount to the got refcount to leave + space for RELATIVE relocs. */ + elf_xtensa_make_sym_local (info, h); + + _bfd_elf_link_hash_hide_symbol (info, h, force_local); +} + + +static void +elf_xtensa_copy_indirect_symbol (bed, dir, ind) + struct elf_backend_data *bed; + struct elf_link_hash_entry *dir, *ind; +{ + _bfd_elf_link_hash_copy_indirect (bed, dir, ind); + + /* The standard function doesn't copy the NEEDS_PLT flag. */ + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT); +} + + +/* Return the section that should be marked against GC for a given + relocation. */ + +static asection * +elf_xtensa_gc_mark_hook (sec, info, rel, h, sym) + asection *sec; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + Elf_Internal_Rela *rel; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + if (h != NULL) + { + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_XTENSA_GNU_VTINHERIT: + case R_XTENSA_GNU_VTENTRY: + break; + + default: + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + default: + break; + } + } + } + else + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); + + return NULL; +} + +/* Update the GOT & PLT entry reference counts + for the section being removed. */ + +static bfd_boolean +elf_xtensa_gc_sweep_hook (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel, *relend; + + if ((sec->flags & SEC_ALLOC) == 0) + return TRUE; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) + { + unsigned long r_symndx; + unsigned int r_type; + struct elf_link_hash_entry *h = NULL; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + r_type = ELF32_R_TYPE (rel->r_info); + switch (r_type) + { + case R_XTENSA_32: + if (h == NULL) + goto local_literal; + if (h->got.refcount > 0) + h->got.refcount--; + break; + + case R_XTENSA_PLT: + if (h == NULL) + goto local_literal; + if (h->plt.refcount > 0) + h->plt.refcount--; + break; + + local_literal: + if (local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + break; + + default: + break; + } + } + + return TRUE; +} + + +/* Create all the dynamic sections. */ + +static bfd_boolean +elf_xtensa_create_dynamic_sections (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + flagword flags; + asection *s; + + /* First do all the standard stuff. */ + if (! _bfd_elf_create_dynamic_sections (dynobj, info)) + return FALSE; + + /* Create any extra PLT sections in case check_relocs has already + been called on all the non-dynamic input files. */ + if (!add_extra_plt_sections (dynobj, plt_reloc_count)) + return FALSE; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY); + + /* Mark the ".got.plt" section READONLY. */ + s = bfd_get_section_by_name (dynobj, ".got.plt"); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags)) + return FALSE; + + /* Create ".rela.got". */ + s = bfd_make_section (dynobj, ".rela.got"); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return FALSE; + + /* Create ".xt.lit.plt" (literal table for ".got.plt*"). */ + s = bfd_make_section (dynobj, ".xt.lit.plt"); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return FALSE; + + return TRUE; +} + + +static bfd_boolean +add_extra_plt_sections (dynobj, count) + bfd *dynobj; + int count; +{ + int chunk; + + /* Iterate over all chunks except 0 which uses the standard ".plt" and + ".got.plt" sections. */ + for (chunk = count / PLT_ENTRIES_PER_CHUNK; chunk > 0; chunk--) + { + char *sname; + flagword flags; + asection *s; + + /* Stop when we find a section has already been created. */ + if (elf_xtensa_get_plt_section (dynobj, chunk)) + break; + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY); + + sname = (char *) bfd_malloc (10); + sprintf (sname, ".plt.%u", chunk); + s = bfd_make_section (dynobj, sname); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags | SEC_CODE) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return FALSE; + + sname = (char *) bfd_malloc (14); + sprintf (sname, ".got.plt.%u", chunk); + s = bfd_make_section (dynobj, sname); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags) + || ! bfd_set_section_alignment (dynobj, s, 2)) + return FALSE; + } + + return TRUE; +} + + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static bfd_boolean +elf_xtensa_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct elf_link_hash_entry *h; +{ + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + return TRUE; + } + + /* This is a reference to a symbol defined by a dynamic object. The + reference must go through the GOT, so there's no need for COPY relocs, + .dynbss, etc. */ + + return TRUE; +} + + +static void +elf_xtensa_make_sym_local (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (info->shared) + { + if (h->plt.refcount > 0) + { + /* Will use RELATIVE relocs instead of JMP_SLOT relocs. */ + if (h->got.refcount < 0) + h->got.refcount = 0; + h->got.refcount += h->plt.refcount; + h->plt.refcount = 0; + } + } + else + { + /* Don't need any dynamic relocations at all. */ + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + h->plt.refcount = 0; + h->got.refcount = 0; + } +} + + +static bfd_boolean +elf_xtensa_fix_refcounts (h, arg) + struct elf_link_hash_entry *h; + PTR arg; +{ + struct bfd_link_info *info = (struct bfd_link_info *) arg; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (! xtensa_elf_dynamic_symbol_p (info, h)) + elf_xtensa_make_sym_local (info, h); + + /* If the symbol has a relocation outside the GOT, set the + DF_TEXTREL flag. */ + if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) != 0) + info->flags |= DF_TEXTREL; + + return TRUE; +} + + +static bfd_boolean +elf_xtensa_allocate_plt_size (h, arg) + struct elf_link_hash_entry *h; + PTR arg; +{ + asection *srelplt = (asection *) arg; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->plt.refcount > 0) + srelplt->_raw_size += (h->plt.refcount * sizeof (Elf32_External_Rela)); + + return TRUE; +} + + +static bfd_boolean +elf_xtensa_allocate_got_size (h, arg) + struct elf_link_hash_entry *h; + PTR arg; +{ + asection *srelgot = (asection *) arg; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->got.refcount > 0) + srelgot->_raw_size += (h->got.refcount * sizeof (Elf32_External_Rela)); + + return TRUE; +} + + +static void +elf_xtensa_allocate_local_got_size (info, srelgot) + struct bfd_link_info *info; + asection *srelgot; +{ + bfd *i; + + for (i = info->input_bfds; i; i = i->link_next) + { + bfd_signed_vma *local_got_refcounts; + bfd_size_type j, cnt; + Elf_Internal_Shdr *symtab_hdr; + + local_got_refcounts = elf_local_got_refcounts (i); + if (!local_got_refcounts) + continue; + + symtab_hdr = &elf_tdata (i)->symtab_hdr; + cnt = symtab_hdr->sh_info; + + for (j = 0; j < cnt; ++j) + { + if (local_got_refcounts[j] > 0) + srelgot->_raw_size += (local_got_refcounts[j] + * sizeof (Elf32_External_Rela)); + } + } +} + + +/* Set the sizes of the dynamic sections. */ + +static bfd_boolean +elf_xtensa_size_dynamic_sections (output_bfd, info) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *s, *srelplt, *splt, *sgotplt, *srelgot, *spltlittbl; + bfd_boolean relplt, relgot; + int plt_entries, plt_chunks, chunk; + + plt_entries = 0; + plt_chunks = 0; + srelgot = 0; + + dynobj = elf_hash_table (info)->dynobj; + if (dynobj == NULL) + abort (); + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + if (s == NULL) + abort (); + s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + } + + /* Allocate room for one word in ".got". */ + s = bfd_get_section_by_name (dynobj, ".got"); + if (s == NULL) + abort (); + s->_raw_size = 4; + + /* Adjust refcounts for symbols that we now know are not "dynamic". */ + elf_link_hash_traverse (elf_hash_table (info), + elf_xtensa_fix_refcounts, + (PTR) info); + + /* Allocate space in ".rela.got" for literals that reference + global symbols. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + if (srelgot == NULL) + abort (); + elf_link_hash_traverse (elf_hash_table (info), + elf_xtensa_allocate_got_size, + (PTR) srelgot); + + /* If we are generating a shared object, we also need space in + ".rela.got" for R_XTENSA_RELATIVE relocs for literals that + reference local symbols. */ + if (info->shared) + elf_xtensa_allocate_local_got_size (info, srelgot); + + /* Allocate space in ".rela.plt" for literals that have PLT entries. */ + srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); + if (srelplt == NULL) + abort (); + elf_link_hash_traverse (elf_hash_table (info), + elf_xtensa_allocate_plt_size, + (PTR) srelplt); + + /* Allocate space in ".plt" to match the size of ".rela.plt". For + each PLT entry, we need the PLT code plus a 4-byte literal. + For each chunk of ".plt", we also need two more 4-byte + literals, two corresponding entries in ".rela.got", and an + 8-byte entry in ".xt.lit.plt". */ + spltlittbl = bfd_get_section_by_name (dynobj, ".xt.lit.plt"); + if (spltlittbl == NULL) + abort (); + + plt_entries = srelplt->_raw_size / sizeof (Elf32_External_Rela); + plt_chunks = + (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK; + + /* Iterate over all the PLT chunks, including any extra sections + created earlier because the initial count of PLT relocations + was an overestimate. */ + for (chunk = 0; + (splt = elf_xtensa_get_plt_section (dynobj, chunk)) != NULL; + chunk++) + { + int chunk_entries; + + sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk); + if (sgotplt == NULL) + abort (); + + if (chunk < plt_chunks - 1) + chunk_entries = PLT_ENTRIES_PER_CHUNK; + else if (chunk == plt_chunks - 1) + chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK); + else + chunk_entries = 0; + + if (chunk_entries != 0) + { + sgotplt->_raw_size = 4 * (chunk_entries + 2); + splt->_raw_size = PLT_ENTRY_SIZE * chunk_entries; + srelgot->_raw_size += 2 * sizeof (Elf32_External_Rela); + spltlittbl->_raw_size += 8; + } + else + { + sgotplt->_raw_size = 0; + splt->_raw_size = 0; + } + } + } + + /* Allocate memory for dynamic sections. */ + relplt = FALSE; + relgot = FALSE; + for (s = dynobj->sections; s != NULL; s = s->next) + { + const char *name; + bfd_boolean strip; + + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + /* It's OK to base decisions on the section name, because none + of the dynobj section names depend upon the input files. */ + name = bfd_get_section_name (dynobj, s); + + strip = FALSE; + + if (strncmp (name, ".rela", 5) == 0) + { + if (strcmp (name, ".rela.plt") == 0) + relplt = TRUE; + else if (strcmp (name, ".rela.got") == 0) + relgot = TRUE; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + else if (strncmp (name, ".plt.", 5) == 0 + || strncmp (name, ".got.plt.", 9) == 0) + { + if (s->_raw_size == 0) + { + /* If we don't need this section, strip it from the output + file. We must create the ".plt*" and ".got.plt*" + sections in create_dynamic_sections and/or check_relocs + based on a conservative estimate of the PLT relocation + count, because the sections must be created before the + linker maps input sections to output sections. The + linker does that before size_dynamic_sections, where we + compute the exact size of the PLT, so there may be more + of these sections than are actually needed. */ + strip = TRUE; + } + } + else if (strcmp (name, ".got") != 0 + && strcmp (name, ".plt") != 0 + && strcmp (name, ".got.plt") != 0 + && strcmp (name, ".xt.lit.plt") != 0) + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (strip) + _bfd_strip_section_from_output (info, s); + else + { + /* Allocate memory for the section contents. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return FALSE; + } + } + + if (elf_hash_table (info)->dynamic_sections_created) + { + /* Add the special XTENSA_RTLD relocations now. The offsets won't be + known until finish_dynamic_sections, but we need to get the relocs + in place before they are sorted. */ + if (srelgot == NULL) + abort (); + for (chunk = 0; chunk < plt_chunks; chunk++) + { + Elf_Internal_Rela irela; + bfd_byte *loc; + + irela.r_offset = 0; + irela.r_info = ELF32_R_INFO (0, R_XTENSA_RTLD); + irela.r_addend = 0; + + loc = (srelgot->contents + + srelgot->reloc_count * sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); + bfd_elf32_swap_reloca_out (output_bfd, &irela, + loc + sizeof (Elf32_External_Rela)); + srelgot->reloc_count += 2; + } + + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_xtensa_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for + the .dynamic section. The DT_DEBUG entry is filled in by the + dynamic linker and used by the debugger. */ +#define add_dynamic_entry(TAG, VAL) \ + bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) + + if (! info->shared) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (relplt) + { + if (!add_dynamic_entry (DT_PLTGOT, 0) + || !add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_RELA) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; + } + + if (relgot) + { + if (!add_dynamic_entry (DT_RELA, 0) + || !add_dynamic_entry (DT_RELASZ, 0) + || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) + return FALSE; + } + + if ((info->flags & DF_TEXTREL) != 0) + { + if (!add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + + if (!add_dynamic_entry (DT_XTENSA_GOT_LOC_OFF, 0) + || !add_dynamic_entry (DT_XTENSA_GOT_LOC_SZ, 0)) + return FALSE; + } +#undef add_dynamic_entry + + return TRUE; +} + + +/* Remove any PT_LOAD segments with no allocated sections. Prior to + binutils 2.13, this function used to remove the non-SEC_ALLOC + sections from PT_LOAD segments, but that task has now been moved + into elf.c. We still need this function to remove any empty + segments that result, but there's nothing Xtensa-specific about + this and it probably ought to be moved into elf.c as well. */ + +static bfd_boolean +elf_xtensa_modify_segment_map (abfd) + bfd *abfd; +{ + struct elf_segment_map **m_p; + + m_p = &elf_tdata (abfd)->segment_map; + while (*m_p != NULL) + { + if ((*m_p)->p_type == PT_LOAD && (*m_p)->count == 0) + *m_p = (*m_p)->next; + else + m_p = &(*m_p)->next; + } + return TRUE; +} + + +/* Perform the specified relocation. The instruction at (contents + address) + is modified to set one operand to represent the value in "relocation". The + operand position is determined by the relocation type recorded in the + howto. */ + +#define CALL_SEGMENT_BITS (30) +#define CALL_SEGMENT_SIZE (1<type) + { + case R_XTENSA_NONE: + return bfd_reloc_ok; + + case R_XTENSA_ASM_EXPAND: + if (!is_weak_undef) + { + /* Check for windowed CALL across a 1GB boundary. */ + xtensa_opcode opcode = + get_expanded_call_opcode (contents + address, + input_section->_raw_size - address); + if (is_windowed_call_opcode (opcode)) + { + self_address = (input_section->output_section->vma + + input_section->output_offset + + address); + if ((self_address >> CALL_SEGMENT_BITS) != + (relocation >> CALL_SEGMENT_BITS)) + { + *error_message = "windowed longcall crosses 1GB boundary; " + "return may fail"; + return bfd_reloc_dangerous; + } + } + } + return bfd_reloc_ok; + + case R_XTENSA_ASM_SIMPLIFY: + { + /* Convert the L32R/CALLX to CALL. */ + bfd_reloc_status_type retval = + elf_xtensa_do_asm_simplify (contents, address, + input_section->_raw_size); + if (retval != bfd_reloc_ok) + return retval; + + /* The CALL needs to be relocated. Continue below for that part. */ + address += 3; + howto = &elf_howto_table[(unsigned) R_XTENSA_OP0 ]; + } + break; + + case R_XTENSA_32: + case R_XTENSA_PLT: + { + bfd_vma x; + x = bfd_get_32 (abfd, contents + address); + x = x + relocation; + bfd_put_32 (abfd, x, contents + address); + } + return bfd_reloc_ok; + } + + /* Read the instruction into a buffer and decode the opcode. */ + ibuff = xtensa_insnbuf_alloc (isa); + xtensa_insnbuf_from_chars (isa, ibuff, contents + address); + opcode = xtensa_decode_insn (isa, ibuff); + + /* Determine which operand is being relocated. */ + if (opcode == XTENSA_UNDEFINED) + { + *error_message = "cannot decode instruction"; + return bfd_reloc_dangerous; + } + + if (howto->type < R_XTENSA_OP0 || howto->type > R_XTENSA_OP2) + { + *error_message = "unexpected relocation"; + return bfd_reloc_dangerous; + } + + opnd = howto->type - R_XTENSA_OP0; + + /* Calculate the PC address for this instruction. */ + if (!howto->pc_relative) + { + *error_message = "expected PC-relative relocation"; + return bfd_reloc_dangerous; + } + + self_address = (input_section->output_section->vma + + input_section->output_offset + + address); + + /* Apply the relocation. */ + operand = xtensa_get_operand (isa, opcode, opnd); + newval = xtensa_operand_do_reloc (operand, relocation, self_address); + encode_result = xtensa_operand_encode (operand, &newval); + xtensa_operand_set_field (operand, ibuff, newval); + + /* Write the modified instruction back out of the buffer. */ + xtensa_insnbuf_to_chars (isa, ibuff, contents + address); + free (ibuff); + + if (encode_result != xtensa_encode_result_ok) + { + char *message = build_encoding_error_message (opcode, encode_result); + *error_message = message; + return bfd_reloc_dangerous; + } + + /* Final check for call. */ + if (is_direct_call_opcode (opcode) + && is_windowed_call_opcode (opcode)) + { + if ((self_address >> CALL_SEGMENT_BITS) != + (relocation >> CALL_SEGMENT_BITS)) + { + *error_message = "windowed call crosses 1GB boundary; " + "return may fail"; + return bfd_reloc_dangerous; + } + } + + return bfd_reloc_ok; +} + + +static char * +vsprint_msg VPARAMS ((const char *origmsg, const char *fmt, int arglen, ...)) +{ + /* To reduce the size of the memory leak, + we only use a single message buffer. */ + static bfd_size_type alloc_size = 0; + static char *message = NULL; + bfd_size_type orig_len, len = 0; + bfd_boolean is_append; + + VA_OPEN (ap, arglen); + VA_FIXEDARG (ap, const char *, origmsg); + + is_append = (origmsg == message); + + orig_len = strlen (origmsg); + len = orig_len + strlen (fmt) + arglen + 20; + if (len > alloc_size) + { + message = (char *) bfd_realloc (message, len); + alloc_size = len; + } + if (!is_append) + memcpy (message, origmsg, orig_len); + vsprintf (message + orig_len, fmt, ap); + VA_CLOSE (ap); + return message; +} + + +static char * +build_encoding_error_message (opcode, encode_result) + xtensa_opcode opcode; + xtensa_encode_result encode_result; +{ + const char *opname = xtensa_opcode_name (xtensa_default_isa, opcode); + const char *msg = NULL; + + switch (encode_result) + { + case xtensa_encode_result_ok: + msg = "unexpected valid encoding"; + break; + case xtensa_encode_result_align: + msg = "misaligned encoding"; + break; + case xtensa_encode_result_not_in_table: + msg = "encoding not in lookup table"; + break; + case xtensa_encode_result_too_low: + msg = "encoding out of range: too low"; + break; + case xtensa_encode_result_too_high: + msg = "encoding out of range: too high"; + break; + case xtensa_encode_result_not_ok: + default: + msg = "could not encode"; + break; + } + + if (is_direct_call_opcode (opcode) + && (encode_result == xtensa_encode_result_too_low + || encode_result == xtensa_encode_result_too_high)) + + msg = "direct call out of range"; + + else if (opcode == get_l32r_opcode ()) + { + /* L32Rs have the strange interaction with encoding in that they + have an unsigned immediate field, so libisa returns "too high" + when the absolute value is out of range and never returns "too + low", but I leave the "too low" message in case anything + changes. */ + if (encode_result == xtensa_encode_result_too_low) + msg = "literal out of range"; + else if (encode_result == xtensa_encode_result_too_high) + msg = "literal placed after use"; + } + + return vsprint_msg (opname, ": %s", strlen (msg) + 2, msg); +} + + +/* This function is registered as the "special_function" in the + Xtensa howto for handling simplify operations. + bfd_perform_relocation / bfd_install_relocation use it to + perform (install) the specified relocation. Since this replaces the code + in bfd_perform_relocation, it is basically an Xtensa-specific, + stripped-down version of bfd_perform_relocation. */ + +static bfd_reloc_status_type +bfd_elf_xtensa_reloc (abfd, reloc_entry, symbol, data, input_section, + output_bfd, error_message) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_reloc_status_type flag; + bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + bfd_boolean is_weak_undef; + + /* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, the resulting + reloc will also be against the same symbol. In such a case, we + don't want to change anything about the way the reloc is handled, + since it will all be done at final link time. This test is similar + to what bfd_elf_generic_reloc does except that it lets relocs with + howto->partial_inplace go through even if the addend is non-zero. + (The real problem is that partial_inplace is set for XTENSA_32 + relocs to begin with, but that's a long story and there's little we + can do about it now....) */ + + if (output_bfd != (bfd *) NULL + && (symbol->flags & BSF_SECTION_SYM) == 0) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > (input_section->_cooked_size + / bfd_octets_per_byte (abfd))) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if ((output_bfd && !howto->partial_inplace) + || reloc_target_output_section == NULL) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + if (output_bfd) + { + if (!howto->partial_inplace) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Everything except + relocations against section symbols has already been handled + above. */ + + BFD_ASSERT (symbol->flags & BSF_SECTION_SYM); + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + else + { + reloc_entry->address += input_section->output_offset; + reloc_entry->addend = 0; + } + } + + is_weak_undef = (bfd_is_und_section (symbol->section) + && (symbol->flags & BSF_WEAK) != 0); + flag = elf_xtensa_do_reloc (howto, abfd, input_section, relocation, + (bfd_byte *) data, (bfd_vma) octets, + is_weak_undef, error_message); + + if (flag == bfd_reloc_dangerous) + { + /* Add the symbol name to the error message. */ + if (! *error_message) + *error_message = ""; + *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)", + strlen (symbol->name) + 17, + symbol->name, reloc_entry->addend); + } + + return flag; +} + + +/* Set up an entry in the procedure linkage table. */ + +static bfd_vma +elf_xtensa_create_plt_entry (dynobj, output_bfd, reloc_index) + bfd *dynobj; + bfd *output_bfd; + unsigned reloc_index; +{ + asection *splt, *sgotplt; + bfd_vma plt_base, got_base; + bfd_vma code_offset, lit_offset; + int chunk; + + chunk = reloc_index / PLT_ENTRIES_PER_CHUNK; + splt = elf_xtensa_get_plt_section (dynobj, chunk); + sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk); + BFD_ASSERT (splt != NULL && sgotplt != NULL); + + plt_base = splt->output_section->vma + splt->output_offset; + got_base = sgotplt->output_section->vma + sgotplt->output_offset; + + lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4; + code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE; + + /* Fill in the literal entry. This is the offset of the dynamic + relocation entry. */ + bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela), + sgotplt->contents + lit_offset); + + /* Fill in the entry in the procedure linkage table. */ + memcpy (splt->contents + code_offset, + (bfd_big_endian (output_bfd) + ? elf_xtensa_be_plt_entry + : elf_xtensa_le_plt_entry), + PLT_ENTRY_SIZE); + bfd_put_16 (output_bfd, l32r_offset (got_base + 0, + plt_base + code_offset + 3), + splt->contents + code_offset + 4); + bfd_put_16 (output_bfd, l32r_offset (got_base + 4, + plt_base + code_offset + 6), + splt->contents + code_offset + 7); + bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset, + plt_base + code_offset + 9), + splt->contents + code_offset + 10); + + return plt_base + code_offset; +} + + +static bfd_boolean +xtensa_elf_dynamic_symbol_p (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (h == NULL) + return FALSE; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->dynindx == -1) + return FALSE; + + if (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_defweak) + return TRUE; + + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_DEFAULT: + break; + case STV_HIDDEN: + case STV_INTERNAL: + return FALSE; + case STV_PROTECTED: + if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) + return FALSE; + break; + } + + if ((info->shared && !info->symbolic) + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + return TRUE; + + return FALSE; +} + + +/* Relocate an Xtensa ELF section. This is invoked by the linker for + both relocateable and final links. */ + +static bfd_boolean +elf_xtensa_relocate_section (output_bfd, info, input_bfd, + input_section, contents, relocs, + local_syms, local_sections) + bfd *output_bfd; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + struct elf_link_hash_entry **sym_hashes; + asection *srelgot, *srelplt; + bfd *dynobj; + char *error_message = NULL; + + if (xtensa_default_isa == NULL) + xtensa_isa_init (); + + dynobj = elf_hash_table (info)->dynobj; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + + srelgot = NULL; + srelplt = NULL; + if (dynobj != NULL) + { + srelgot = bfd_get_section_by_name (dynobj, ".rela.got");; + srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); + } + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma relocation; + bfd_reloc_status_type r; + bfd_boolean is_weak_undef; + bfd_boolean unresolved_reloc; + bfd_boolean warned; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type == (int) R_XTENSA_GNU_VTINHERIT + || r_type == (int) R_XTENSA_GNU_VTENTRY) + continue; + + if (r_type < 0 || r_type >= (int) R_XTENSA_max) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + howto = &elf_howto_table[r_type]; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. + 1) If the reloc is against a section symbol, adjust + according to the output section. + 2) If there is a new target for this relocation, + the new target will be in the same output section. + We adjust the relocation by the output section + difference. */ + + if (relaxing_section) + { + /* Check if this references a section in another input file. */ + do_fix_for_relocateable_link (rel, input_bfd, input_section); + r_type = ELF32_R_TYPE (rel->r_info); + } + + if (r_type == R_XTENSA_ASM_SIMPLIFY) + { + /* Convert ASM_SIMPLIFY into the simpler relocation + so that they never escape a relaxing link. */ + contract_asm_expansion (contents, input_section->_raw_size, rel); + r_type = ELF32_R_TYPE (rel->r_info); + } + + /* This is a relocateable link, so we don't have to change + anything unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections[r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + /* If there is an addend with a partial_inplace howto, + then move the addend to the contents. This is a hack + to work around problems with DWARF in relocateable links + with some previous version of BFD. Now we can't easily get + rid of the hack without breaking backward compatibility.... */ + if (rel->r_addend) + { + howto = &elf_howto_table[r_type]; + if (howto->partial_inplace) + { + r = elf_xtensa_do_reloc (howto, input_bfd, input_section, + rel->r_addend, contents, + rel->r_offset, FALSE, + &error_message); + if (r != bfd_reloc_ok) + { + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + rel->r_addend = 0; + } + } + + /* Done with work for relocateable link; continue with next reloc. */ + continue; + } + + /* This is a final link. */ + + h = NULL; + sym = NULL; + sec = NULL; + is_weak_undef = FALSE; + unresolved_reloc = FALSE; + warned = FALSE; + + if (howto->partial_inplace) + { + /* Because R_XTENSA_32 was made partial_inplace to fix some + problems with DWARF info in partial links, there may be + an addend stored in the contents. Take it out of there + and move it back into the addend field of the reloc. */ + rel->r_addend += bfd_get_32 (input_bfd, contents + rel->r_offset); + bfd_put_32 (input_bfd, 0, contents + rel->r_offset); + } + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); + } + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + relocation = 0; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + + if (sec->output_section == NULL) + /* Set a flag that will be cleared later if we find a + relocation value for this symbol. output_section + is typically NULL for symbols satisfied by a shared + library. */ + unresolved_reloc = TRUE; + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + is_weak_undef = TRUE; + else if (info->shared + && !info->no_undefined + && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) + ; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset, + (!info->shared || info->no_undefined + || ELF_ST_VISIBILITY (h->other))))) + return FALSE; + warned = TRUE; + } + } + + if (relaxing_section) + { + /* Check if this references a section in another input file. */ + do_fix_for_final_link (rel, input_section, &relocation); + + /* Update some already cached values. */ + r_type = ELF32_R_TYPE (rel->r_info); + howto = &elf_howto_table[r_type]; + } + + /* Sanity check the address. */ + if (rel->r_offset >= input_section->_raw_size + && ELF32_R_TYPE (rel->r_info) != R_XTENSA_NONE) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Generate dynamic relocations. */ + if (elf_hash_table (info)->dynamic_sections_created) + { + bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h); + + if (dynamic_symbol && (r_type == R_XTENSA_OP0 + || r_type == R_XTENSA_OP1 + || r_type == R_XTENSA_OP2)) + { + /* This is an error. The symbol's real value won't be known + until runtime and it's likely to be out of range anyway. */ + const char *name = h->root.root.string; + error_message = vsprint_msg ("invalid relocation for dynamic " + "symbol", ": %s", + strlen (name) + 2, name); + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + else if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT) + && (input_section->flags & SEC_ALLOC) != 0 + && (dynamic_symbol || info->shared)) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + asection *srel; + + if (dynamic_symbol && r_type == R_XTENSA_PLT) + srel = srelplt; + else + srel = srelgot; + + BFD_ASSERT (srel != NULL); + + outrel.r_offset = + _bfd_elf_section_offset (output_bfd, info, + input_section, rel->r_offset); + + if ((outrel.r_offset | 1) == (bfd_vma) -1) + memset (&outrel, 0, sizeof outrel); + else + { + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset); + + if (dynamic_symbol) + { + outrel.r_addend = rel->r_addend; + rel->r_addend = 0; + + if (r_type == R_XTENSA_32) + { + outrel.r_info = + ELF32_R_INFO (h->dynindx, R_XTENSA_GLOB_DAT); + relocation = 0; + } + else /* r_type == R_XTENSA_PLT */ + { + outrel.r_info = + ELF32_R_INFO (h->dynindx, R_XTENSA_JMP_SLOT); + + /* Create the PLT entry and set the initial + contents of the literal entry to the address of + the PLT entry. */ + relocation = + elf_xtensa_create_plt_entry (dynobj, output_bfd, + srel->reloc_count); + } + unresolved_reloc = FALSE; + } + else + { + /* Generate a RELATIVE relocation. */ + outrel.r_info = ELF32_R_INFO (0, R_XTENSA_RELATIVE); + outrel.r_addend = 0; + } + } + + loc = (srel->contents + + srel->reloc_count++ * sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count + <= srel->_cooked_size); + } + } + + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections + because such sections are not SEC_ALLOC and thus ld.so will + not process them. */ + if (unresolved_reloc + && !((input_section->flags & SEC_DEBUGGING) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) + (*_bfd_error_handler) + (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, + h->root.root.string); + + /* There's no point in calling bfd_perform_relocation here. + Just go directly to our "special function". */ + r = elf_xtensa_do_reloc (howto, input_bfd, input_section, + relocation + rel->r_addend, + contents, rel->r_offset, is_weak_undef, + &error_message); + + if (r != bfd_reloc_ok && !warned) + { + const char *name; + + BFD_ASSERT (r == bfd_reloc_dangerous); + BFD_ASSERT (error_message != (char *) NULL); + + if (h != NULL) + name = h->root.root.string; + else + { + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + if (name && *name == '\0') + name = bfd_section_name (input_bfd, sec); + } + if (name) + error_message = vsprint_msg (error_message, ": %s", + strlen (name), name); + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + } + + return TRUE; +} + + +/* Finish up dynamic symbol handling. There's not much to do here since + the PLT and GOT entries are all set up by relocate_section. */ + +static bfd_boolean +elf_xtensa_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + sym->st_shndx = SHN_ABS; + + return TRUE; +} + + +/* Combine adjacent literal table entries in the output. Adjacent + entries within each input section may have been removed during + relaxation, but we repeat the process here, even though it's too late + to shrink the output section, because it's important to minimize the + number of literal table entries to reduce the start-up work for the + runtime linker. Returns the number of remaining table entries or -1 + on error. */ + +static int +elf_xtensa_combine_prop_entries (output_bfd, secname) + bfd *output_bfd; + const char *secname; +{ + asection *sec; + bfd_byte *contents; + property_table_entry *table; + bfd_size_type section_size; + bfd_vma offset; + int n, m, num; + + sec = bfd_get_section_by_name (output_bfd, secname); + if (!sec) + return -1; + + section_size = (sec->_cooked_size != 0 ? sec->_cooked_size : sec->_raw_size); + BFD_ASSERT (section_size % 8 == 0); + num = section_size / 8; + + contents = (bfd_byte *) bfd_malloc (section_size); + table = (property_table_entry *) + bfd_malloc (num * sizeof (property_table_entry)); + if (contents == 0 || table == 0) + return -1; + + /* The ".xt.lit.plt" section has the SEC_IN_MEMORY flag set and this + propagates to the output section, where it doesn't really apply and + where it breaks the following call to bfd_get_section_contents. */ + sec->flags &= ~SEC_IN_MEMORY; + + if (! bfd_get_section_contents (output_bfd, sec, contents, 0, section_size)) + return -1; + + /* There should never be any relocations left at this point, so this + is quite a bit easier than what is done during relaxation. */ + + /* Copy the raw contents into a property table array and sort it. */ + offset = 0; + for (n = 0; n < num; n++) + { + table[n].address = bfd_get_32 (output_bfd, &contents[offset]); + table[n].size = bfd_get_32 (output_bfd, &contents[offset + 4]); + offset += 8; + } + qsort (table, num, sizeof (property_table_entry), property_table_compare); + + for (n = 0; n < num; n++) + { + bfd_boolean remove = FALSE; + + if (table[n].size == 0) + remove = TRUE; + else if (n > 0 && + (table[n-1].address + table[n-1].size == table[n].address)) + { + table[n-1].size += table[n].size; + remove = TRUE; + } + + if (remove) + { + for (m = n; m < num - 1; m++) + { + table[m].address = table[m+1].address; + table[m].size = table[m+1].size; + } + + n--; + num--; + } + } + + /* Copy the data back to the raw contents. */ + offset = 0; + for (n = 0; n < num; n++) + { + bfd_put_32 (output_bfd, table[n].address, &contents[offset]); + bfd_put_32 (output_bfd, table[n].size, &contents[offset + 4]); + offset += 8; + } + + /* Clear the removed bytes. */ + if ((bfd_size_type) (num * 8) < section_size) + { + memset (&contents[num * 8], 0, section_size - num * 8); + sec->_cooked_size = num * 8; + } + + if (! bfd_set_section_contents (output_bfd, sec, contents, 0, section_size)) + return -1; + + free (contents); + return num; +} + + +/* Finish up the dynamic sections. */ + +static bfd_boolean +elf_xtensa_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + bfd *dynobj; + asection *sdyn, *srelplt, *sgot; + Elf32_External_Dyn *dyncon, *dynconend; + int num_xtlit_entries; + + if (! elf_hash_table (info)->dynamic_sections_created) + return TRUE; + + dynobj = elf_hash_table (info)->dynobj; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + /* Set the first entry in the global offset table to the address of + the dynamic section. */ + sgot = bfd_get_section_by_name (dynobj, ".got"); + if (sgot) + { + BFD_ASSERT (sgot->_raw_size == 4); + if (sdyn == NULL) + bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); + else + bfd_put_32 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + sgot->contents); + } + + srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); + if (srelplt != NULL && srelplt->_raw_size != 0) + { + asection *sgotplt, *srelgot, *spltlittbl; + int chunk, plt_chunks, plt_entries; + Elf_Internal_Rela irela; + bfd_byte *loc; + unsigned rtld_reloc; + + srelgot = bfd_get_section_by_name (dynobj, ".rela.got");; + BFD_ASSERT (srelgot != NULL); + + spltlittbl = bfd_get_section_by_name (dynobj, ".xt.lit.plt"); + BFD_ASSERT (spltlittbl != NULL); + + /* Find the first XTENSA_RTLD relocation. Presumably the rest + of them follow immediately after.... */ + for (rtld_reloc = 0; rtld_reloc < srelgot->reloc_count; rtld_reloc++) + { + loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); + if (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD) + break; + } + BFD_ASSERT (rtld_reloc < srelgot->reloc_count); + + plt_entries = (srelplt->_raw_size / sizeof (Elf32_External_Rela)); + plt_chunks = + (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK; + + for (chunk = 0; chunk < plt_chunks; chunk++) + { + int chunk_entries = 0; + + sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk); + BFD_ASSERT (sgotplt != NULL); + + /* Emit special RTLD relocations for the first two entries in + each chunk of the .got.plt section. */ + + loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); + BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD); + irela.r_offset = (sgotplt->output_section->vma + + sgotplt->output_offset); + irela.r_addend = 1; /* tell rtld to set value to resolver function */ + bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); + rtld_reloc += 1; + BFD_ASSERT (rtld_reloc <= srelgot->reloc_count); + + /* Next literal immediately follows the first. */ + loc += sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_in (output_bfd, loc, &irela); + BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD); + irela.r_offset = (sgotplt->output_section->vma + + sgotplt->output_offset + 4); + /* Tell rtld to set value to object's link map. */ + irela.r_addend = 2; + bfd_elf32_swap_reloca_out (output_bfd, &irela, loc); + rtld_reloc += 1; + BFD_ASSERT (rtld_reloc <= srelgot->reloc_count); + + /* Fill in the literal table. */ + if (chunk < plt_chunks - 1) + chunk_entries = PLT_ENTRIES_PER_CHUNK; + else + chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK); + + BFD_ASSERT ((unsigned) (chunk + 1) * 8 <= spltlittbl->_cooked_size); + bfd_put_32 (output_bfd, + sgotplt->output_section->vma + sgotplt->output_offset, + spltlittbl->contents + (chunk * 8) + 0); + bfd_put_32 (output_bfd, + 8 + (chunk_entries * 4), + spltlittbl->contents + (chunk * 8) + 4); + } + + /* All the dynamic relocations have been emitted at this point. + Make sure the relocation sections are the correct size. */ + if (srelgot->_cooked_size != (sizeof (Elf32_External_Rela) + * srelgot->reloc_count) + || srelplt->_cooked_size != (sizeof (Elf32_External_Rela) + * srelplt->reloc_count)) + abort (); + + /* The .xt.lit.plt section has just been modified. This must + happen before the code below which combines adjacent literal + table entries, and the .xt.lit.plt contents have to be forced to + the output here. */ + if (! bfd_set_section_contents (output_bfd, + spltlittbl->output_section, + spltlittbl->contents, + spltlittbl->output_offset, + spltlittbl->_raw_size)) + return FALSE; + /* Clear SEC_HAS_CONTENTS so the contents won't be output again. */ + spltlittbl->flags &= ~SEC_HAS_CONTENTS; + } + + /* Combine adjacent literal table entries. */ + BFD_ASSERT (! info->relocateable); + num_xtlit_entries = elf_xtensa_combine_prop_entries (output_bfd, ".xt.lit"); + if (num_xtlit_entries < 0) + return FALSE; + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + asection *s; + + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + + case DT_XTENSA_GOT_LOC_SZ: + s = bfd_get_section_by_name (output_bfd, ".xt.lit"); + BFD_ASSERT (s); + dyn.d_un.d_val = num_xtlit_entries; + break; + + case DT_XTENSA_GOT_LOC_OFF: + name = ".xt.lit"; + goto get_vma; + case DT_PLTGOT: + name = ".got"; + goto get_vma; + case DT_JMPREL: + name = ".rela.plt"; + get_vma: + s = bfd_get_section_by_name (output_bfd, name); + BFD_ASSERT (s); + dyn.d_un.d_ptr = s->vma; + break; + + case DT_PLTRELSZ: + s = bfd_get_section_by_name (output_bfd, ".rela.plt"); + BFD_ASSERT (s); + dyn.d_un.d_val = (s->_cooked_size ? s->_cooked_size : s->_raw_size); + break; + + case DT_RELASZ: + /* Adjust RELASZ to not include JMPREL. This matches what + glibc expects and what is done for several other ELF + targets (e.g., i386, alpha), but the "correct" behavior + seems to be unresolved. Since the linker script arranges + for .rela.plt to follow all other relocation sections, we + don't have to worry about changing the DT_RELA entry. */ + s = bfd_get_section_by_name (output_bfd, ".rela.plt"); + if (s) + { + dyn.d_un.d_val -= + (s->_cooked_size ? s->_cooked_size : s->_raw_size); + } + break; + } + + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + return TRUE; +} + + +/* Functions for dealing with the e_flags field. */ + +/* Merge backend specific data from an object file to the output + object file when linking. */ + +static bfd_boolean +elf_xtensa_merge_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + unsigned out_mach, in_mach; + flagword out_flag, in_flag; + + /* Check if we have the same endianess. */ + if (!_bfd_generic_verify_endian_match (ibfd, obfd)) + return FALSE; + + /* Don't even pretend to support mixed-format linking. */ + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return FALSE; + + out_flag = elf_elfheader (obfd)->e_flags; + in_flag = elf_elfheader (ibfd)->e_flags; + + out_mach = out_flag & EF_XTENSA_MACH; + in_mach = in_flag & EF_XTENSA_MACH; + if (out_mach != in_mach) + { + (*_bfd_error_handler) + ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x\n", + bfd_archive_filename (ibfd), out_mach, in_mach); + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + if (! elf_flags_init (obfd)) + { + elf_flags_init (obfd) = TRUE; + elf_elfheader (obfd)->e_flags = in_flag; + + if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) + && bfd_get_arch_info (obfd)->the_default) + return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), + bfd_get_mach (ibfd)); + + return TRUE; + } + + if ((out_flag & EF_XTENSA_XT_INSN) != + (in_flag & EF_XTENSA_XT_INSN)) + elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_INSN); + + if ((out_flag & EF_XTENSA_XT_LIT) != + (in_flag & EF_XTENSA_XT_LIT)) + elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_LIT); + + return TRUE; +} + + +static bfd_boolean +elf_xtensa_set_private_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + BFD_ASSERT (!elf_flags_init (abfd) + || elf_elfheader (abfd)->e_flags == flags); + + elf_elfheader (abfd)->e_flags |= flags; + elf_flags_init (abfd) = TRUE; + + return TRUE; +} + + +extern flagword +elf_xtensa_get_private_bfd_flags (abfd) + bfd *abfd; +{ + return elf_elfheader (abfd)->e_flags; +} + + +static bfd_boolean +elf_xtensa_print_private_bfd_data (abfd, farg) + bfd *abfd; + PTR farg; +{ + FILE *f = (FILE *) farg; + flagword e_flags = elf_elfheader (abfd)->e_flags; + + fprintf (f, "\nXtensa header:\n"); + if ((e_flags & EF_XTENSA_MACH) == E_XTENSA_MACH) + fprintf (f, "\nMachine = Base\n"); + else + fprintf (f, "\nMachine Id = 0x%x\n", e_flags & EF_XTENSA_MACH); + + fprintf (f, "Insn tables = %s\n", + (e_flags & EF_XTENSA_XT_INSN) ? "true" : "false"); + + fprintf (f, "Literal tables = %s\n", + (e_flags & EF_XTENSA_XT_LIT) ? "true" : "false"); + + return _bfd_elf_print_private_bfd_data (abfd, farg); +} + + +/* Set the right machine number for an Xtensa ELF file. */ + +static bfd_boolean +elf_xtensa_object_p (abfd) + bfd *abfd; +{ + int mach; + unsigned long arch = elf_elfheader (abfd)->e_flags & EF_XTENSA_MACH; + + switch (arch) + { + case E_XTENSA_MACH: + mach = bfd_mach_xtensa; + break; + default: + return FALSE; + } + + (void) bfd_default_set_arch_mach (abfd, bfd_arch_xtensa, mach); + return TRUE; +} + + +/* The final processing done just before writing out an Xtensa ELF object + file. This gets the Xtensa architecture right based on the machine + number. */ + +static void +elf_xtensa_final_write_processing (abfd, linker) + bfd *abfd; + bfd_boolean linker ATTRIBUTE_UNUSED; +{ + int mach; + unsigned long val; + + switch (mach = bfd_get_mach (abfd)) + { + case bfd_mach_xtensa: + val = E_XTENSA_MACH; + break; + default: + return; + } + + elf_elfheader (abfd)->e_flags &= (~ EF_XTENSA_MACH); + elf_elfheader (abfd)->e_flags |= val; +} + + +static enum elf_reloc_type_class +elf_xtensa_reloc_type_class (rela) + const Elf_Internal_Rela *rela; +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_XTENSA_RELATIVE: + return reloc_class_relative; + case R_XTENSA_JMP_SLOT: + return reloc_class_plt; + default: + return reloc_class_normal; + } +} + + +static bfd_boolean +elf_xtensa_discard_info_for_section (abfd, cookie, info, sec) + bfd *abfd; + struct elf_reloc_cookie *cookie; + struct bfd_link_info *info; + asection *sec; +{ + bfd_byte *contents; + bfd_vma section_size; + bfd_vma offset, actual_offset; + size_t removed_bytes = 0; + + section_size = (sec->_cooked_size ? sec->_cooked_size : sec->_raw_size); + if (section_size == 0 || section_size % 8 != 0) + return FALSE; + + if (sec->output_section + && bfd_is_abs_section (sec->output_section)) + return FALSE; + + contents = retrieve_contents (abfd, sec, info->keep_memory); + if (!contents) + return FALSE; + + cookie->rels = retrieve_internal_relocs (abfd, sec, info->keep_memory); + if (!cookie->rels) + { + release_contents (sec, contents); + return FALSE; + } + + cookie->rel = cookie->rels; + cookie->relend = cookie->rels + sec->reloc_count; + + for (offset = 0; offset < section_size; offset += 8) + { + actual_offset = offset - removed_bytes; + + /* The ...symbol_deleted_p function will skip over relocs but it + won't adjust their offsets, so do that here. */ + while (cookie->rel < cookie->relend + && cookie->rel->r_offset < offset) + { + cookie->rel->r_offset -= removed_bytes; + cookie->rel++; + } + + while (cookie->rel < cookie->relend + && cookie->rel->r_offset == offset) + { + if (_bfd_elf32_reloc_symbol_deleted_p (offset, cookie)) + { + /* Remove the table entry. (If the reloc type is NONE, then + the entry has already been merged with another and deleted + during relaxation.) */ + if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE) + { + /* Shift the contents up. */ + if (offset + 8 < section_size) + memmove (&contents[actual_offset], + &contents[actual_offset+8], + section_size - offset - 8); + removed_bytes += 8; + } + + /* Remove this relocation. */ + cookie->rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + } + + /* Adjust the relocation offset for previous removals. This + should not be done before calling ...symbol_deleted_p + because it might mess up the offset comparisons there. + Make sure the offset doesn't underflow in the case where + the first entry is removed. */ + if (cookie->rel->r_offset >= removed_bytes) + cookie->rel->r_offset -= removed_bytes; + else + cookie->rel->r_offset = 0; + + cookie->rel++; + } + } + + if (removed_bytes != 0) + { + /* Adjust any remaining relocs (shouldn't be any). */ + for (; cookie->rel < cookie->relend; cookie->rel++) + { + if (cookie->rel->r_offset >= removed_bytes) + cookie->rel->r_offset -= removed_bytes; + else + cookie->rel->r_offset = 0; + } + + /* Clear the removed bytes. */ + memset (&contents[section_size - removed_bytes], 0, removed_bytes); + + pin_contents (sec, contents); + pin_internal_relocs (sec, cookie->rels); + + sec->_cooked_size = section_size - removed_bytes; + /* Also shrink _raw_size. See comments in relax_property_section. */ + sec->_raw_size = sec->_cooked_size; + } + else + { + release_contents (sec, contents); + release_internal_relocs (sec, cookie->rels); + } + + return (removed_bytes != 0); +} + + +static bfd_boolean +elf_xtensa_discard_info (abfd, cookie, info) + bfd *abfd; + struct elf_reloc_cookie *cookie; + struct bfd_link_info *info; +{ + asection *sec; + bfd_boolean changed = FALSE; + + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (xtensa_is_property_section (sec)) + { + if (elf_xtensa_discard_info_for_section (abfd, cookie, info, sec)) + changed = TRUE; + } + } + + return changed; +} + + +static bfd_boolean +elf_xtensa_ignore_discarded_relocs (sec) + asection *sec; +{ + return xtensa_is_property_section (sec); +} + + +/* Support for core dump NOTE sections. */ + +static bfd_boolean +elf_xtensa_grok_prstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + int offset; + unsigned int raw_size; + + /* The size for Xtensa is variable, so don't try to recognize the format + based on the size. Just assume this is GNU/Linux. */ + + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 72; + raw_size = note->descsz - offset - 4; + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + raw_size, note->descpos + offset); +} + + +static bfd_boolean +elf_xtensa_grok_psinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + switch (note->descsz) + { + default: + return FALSE; + + case 128: /* GNU/Linux elf_prpsinfo */ + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); + } + + /* Note that for some reason, a spurious space is tacked + onto the end of the args in some (at least one anyway) + implementations, so strip it off if it exists. */ + + { + char *command = elf_tdata (abfd)->core_command; + int n = strlen (command); + + if (0 < n && command[n - 1] == ' ') + command[n - 1] = '\0'; + } + + return TRUE; +} + + +/* Generic Xtensa configurability stuff. */ + +static xtensa_opcode callx0_op = XTENSA_UNDEFINED; +static xtensa_opcode callx4_op = XTENSA_UNDEFINED; +static xtensa_opcode callx8_op = XTENSA_UNDEFINED; +static xtensa_opcode callx12_op = XTENSA_UNDEFINED; +static xtensa_opcode call0_op = XTENSA_UNDEFINED; +static xtensa_opcode call4_op = XTENSA_UNDEFINED; +static xtensa_opcode call8_op = XTENSA_UNDEFINED; +static xtensa_opcode call12_op = XTENSA_UNDEFINED; + +static void +init_call_opcodes () +{ + if (callx0_op == XTENSA_UNDEFINED) + { + callx0_op = xtensa_opcode_lookup (xtensa_default_isa, "callx0"); + callx4_op = xtensa_opcode_lookup (xtensa_default_isa, "callx4"); + callx8_op = xtensa_opcode_lookup (xtensa_default_isa, "callx8"); + callx12_op = xtensa_opcode_lookup (xtensa_default_isa, "callx12"); + call0_op = xtensa_opcode_lookup (xtensa_default_isa, "call0"); + call4_op = xtensa_opcode_lookup (xtensa_default_isa, "call4"); + call8_op = xtensa_opcode_lookup (xtensa_default_isa, "call8"); + call12_op = xtensa_opcode_lookup (xtensa_default_isa, "call12"); + } +} + + +static bfd_boolean +is_indirect_call_opcode (opcode) + xtensa_opcode opcode; +{ + init_call_opcodes (); + return (opcode == callx0_op + || opcode == callx4_op + || opcode == callx8_op + || opcode == callx12_op); +} + + +static bfd_boolean +is_direct_call_opcode (opcode) + xtensa_opcode opcode; +{ + init_call_opcodes (); + return (opcode == call0_op + || opcode == call4_op + || opcode == call8_op + || opcode == call12_op); +} + + +static bfd_boolean +is_windowed_call_opcode (opcode) + xtensa_opcode opcode; +{ + init_call_opcodes (); + return (opcode == call4_op + || opcode == call8_op + || opcode == call12_op + || opcode == callx4_op + || opcode == callx8_op + || opcode == callx12_op); +} + + +static xtensa_opcode +get_l32r_opcode (void) +{ + static xtensa_opcode l32r_opcode = XTENSA_UNDEFINED; + if (l32r_opcode == XTENSA_UNDEFINED) + { + l32r_opcode = xtensa_opcode_lookup (xtensa_default_isa, "l32r"); + BFD_ASSERT (l32r_opcode != XTENSA_UNDEFINED); + } + return l32r_opcode; +} + + +static bfd_vma +l32r_offset (addr, pc) + bfd_vma addr; + bfd_vma pc; +{ + bfd_vma offset; + + offset = addr - ((pc+3) & -4); + BFD_ASSERT ((offset & ((1 << 2) - 1)) == 0); + offset = (signed int) offset >> 2; + BFD_ASSERT ((signed int) offset >> 16 == -1); + return offset; +} + + +/* Get the operand number for a PC-relative relocation. + If the relocation is not a PC-relative one, return (-1). */ + +static int +get_relocation_opnd (irel) + Elf_Internal_Rela *irel; +{ + if (ELF32_R_TYPE (irel->r_info) < R_XTENSA_OP0 + || ELF32_R_TYPE (irel->r_info) >= R_XTENSA_max) + return -1; + return ELF32_R_TYPE (irel->r_info) - R_XTENSA_OP0; +} + + +/* Get the opcode for a relocation. */ + +static xtensa_opcode +get_relocation_opcode (sec, contents, irel) + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *irel; +{ + static xtensa_insnbuf ibuff = NULL; + xtensa_isa isa = xtensa_default_isa; + + if (get_relocation_opnd (irel) == -1) + return XTENSA_UNDEFINED; + + if (contents == NULL) + return XTENSA_UNDEFINED; + + if (sec->_raw_size <= irel->r_offset) + return XTENSA_UNDEFINED; + + if (ibuff == NULL) + ibuff = xtensa_insnbuf_alloc (isa); + + /* Decode the instruction. */ + xtensa_insnbuf_from_chars (isa, ibuff, &contents[irel->r_offset]); + return xtensa_decode_insn (isa, ibuff); +} + + +bfd_boolean +is_l32r_relocation (sec, contents, irel) + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *irel; +{ + xtensa_opcode opcode; + + if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_OP1) + return FALSE; + + opcode = get_relocation_opcode (sec, contents, irel); + return (opcode == get_l32r_opcode ()); +} + + +/* Code for transforming CALLs at link-time. */ + +static bfd_reloc_status_type +elf_xtensa_do_asm_simplify (contents, address, content_length) + bfd_byte *contents; + bfd_vma address; + bfd_vma content_length; +{ + static xtensa_insnbuf insnbuf = NULL; + xtensa_opcode opcode; + xtensa_operand operand; + xtensa_opcode direct_call_opcode; + xtensa_isa isa = xtensa_default_isa; + bfd_byte *chbuf = contents + address; + int opn; + + if (insnbuf == NULL) + insnbuf = xtensa_insnbuf_alloc (isa); + + if (content_length < address) + { + (*_bfd_error_handler) + ("Attempt to convert L32R/CALLX to CALL failed\n"); + return bfd_reloc_other; + } + + opcode = get_expanded_call_opcode (chbuf, content_length - address); + direct_call_opcode = swap_callx_for_call_opcode (opcode); + if (direct_call_opcode == XTENSA_UNDEFINED) + { + (*_bfd_error_handler) + ("Attempt to convert L32R/CALLX to CALL failed\n"); + return bfd_reloc_other; + } + + /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */ + opcode = xtensa_opcode_lookup (isa, "or"); + xtensa_encode_insn (isa, opcode, insnbuf); + for (opn = 0; opn < 3; opn++) + { + operand = xtensa_get_operand (isa, opcode, opn); + xtensa_operand_set_field (operand, insnbuf, 1); + } + xtensa_insnbuf_to_chars (isa, insnbuf, chbuf); + + /* Assemble a CALL ("callN 0") into the 3 byte offset. */ + xtensa_encode_insn (isa, direct_call_opcode, insnbuf); + operand = xtensa_get_operand (isa, opcode, 0); + xtensa_operand_set_field (operand, insnbuf, 0); + xtensa_insnbuf_to_chars (isa, insnbuf, chbuf + 3); + + return bfd_reloc_ok; +} + + +static bfd_reloc_status_type +contract_asm_expansion (contents, content_length, irel) + bfd_byte *contents; + bfd_vma content_length; + Elf_Internal_Rela *irel; +{ + bfd_reloc_status_type retval = + elf_xtensa_do_asm_simplify (contents, irel->r_offset, content_length); + + if (retval != bfd_reloc_ok) + return retval; + + /* Update the irel->r_offset field so that the right immediate and + the right instruction are modified during the relocation. */ + irel->r_offset += 3; + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_XTENSA_OP0); + return bfd_reloc_ok; +} + + +static xtensa_opcode +swap_callx_for_call_opcode (opcode) + xtensa_opcode opcode; +{ + init_call_opcodes (); + + if (opcode == callx0_op) return call0_op; + if (opcode == callx4_op) return call4_op; + if (opcode == callx8_op) return call8_op; + if (opcode == callx12_op) return call12_op; + + /* Return XTENSA_UNDEFINED if the opcode is not an indirect call. */ + return XTENSA_UNDEFINED; +} + + +/* Check if "buf" is pointing to a "L32R aN; CALLX aN" sequence, and + if so, return the CALLX opcode. If not, return XTENSA_UNDEFINED. */ + +#define L32R_TARGET_REG_OPERAND 0 +#define CALLN_SOURCE_OPERAND 0 + +static xtensa_opcode +get_expanded_call_opcode (buf, bufsize) + bfd_byte *buf; + int bufsize; +{ + static xtensa_insnbuf insnbuf = NULL; + xtensa_opcode opcode; + xtensa_operand operand; + xtensa_isa isa = xtensa_default_isa; + uint32 regno, call_regno; + + /* Buffer must be at least 6 bytes. */ + if (bufsize < 6) + return XTENSA_UNDEFINED; + + if (insnbuf == NULL) + insnbuf = xtensa_insnbuf_alloc (isa); + + xtensa_insnbuf_from_chars (isa, insnbuf, buf); + opcode = xtensa_decode_insn (isa, insnbuf); + + if (opcode != get_l32r_opcode ()) + return XTENSA_UNDEFINED; + + operand = xtensa_get_operand (isa, opcode, L32R_TARGET_REG_OPERAND); + regno = xtensa_operand_decode + (operand, xtensa_operand_get_field (operand, insnbuf)); + + /* Next instruction should be an CALLXn with operand 0 == regno. */ + xtensa_insnbuf_from_chars (isa, insnbuf, + buf + xtensa_insn_length (isa, opcode)); + opcode = xtensa_decode_insn (isa, insnbuf); + + if (!is_indirect_call_opcode (opcode)) + return XTENSA_UNDEFINED; + + operand = xtensa_get_operand (isa, opcode, CALLN_SOURCE_OPERAND); + call_regno = xtensa_operand_decode + (operand, xtensa_operand_get_field (operand, insnbuf)); + if (call_regno != regno) + return XTENSA_UNDEFINED; + + return opcode; +} + + +/* Data structures used during relaxation. */ + +/* r_reloc: relocation values. */ + +/* Through the relaxation process, we need to keep track of the values + that will result from evaluating relocations. The standard ELF + relocation structure is not sufficient for this purpose because we're + operating on multiple input files at once, so we need to know which + input file a relocation refers to. The r_reloc structure thus + records both the input file (bfd) and ELF relocation. + + For efficiency, an r_reloc also contains a "target_offset" field to + cache the target-section-relative offset value that is represented by + the relocation. */ + +typedef struct r_reloc_struct r_reloc; + +struct r_reloc_struct +{ + bfd *abfd; + Elf_Internal_Rela rela; + bfd_vma target_offset; +}; + +static bfd_boolean r_reloc_is_const + PARAMS ((const r_reloc *)); +static void r_reloc_init + PARAMS ((r_reloc *, bfd *, Elf_Internal_Rela *)); +static bfd_vma r_reloc_get_target_offset + PARAMS ((const r_reloc *)); +static asection *r_reloc_get_section + PARAMS ((const r_reloc *)); +static bfd_boolean r_reloc_is_defined + PARAMS ((const r_reloc *)); +static struct elf_link_hash_entry *r_reloc_get_hash_entry + PARAMS ((const r_reloc *)); + + +/* The r_reloc structure is included by value in literal_value, but not + every literal_value has an associated relocation -- some are simple + constants. In such cases, we set all the fields in the r_reloc + struct to zero. The r_reloc_is_const function should be used to + detect this case. */ + +static bfd_boolean +r_reloc_is_const (r_rel) + const r_reloc *r_rel; +{ + return (r_rel->abfd == NULL); +} + + +static void +r_reloc_init (r_rel, abfd, irel) + r_reloc *r_rel; + bfd *abfd; + Elf_Internal_Rela *irel; +{ + if (irel != NULL) + { + r_rel->rela = *irel; + r_rel->abfd = abfd; + r_rel->target_offset = r_reloc_get_target_offset (r_rel); + } + else + memset (r_rel, 0, sizeof (r_reloc)); +} + + +static bfd_vma +r_reloc_get_target_offset (r_rel) + const r_reloc *r_rel; +{ + bfd_vma target_offset; + unsigned long r_symndx; + + BFD_ASSERT (!r_reloc_is_const (r_rel)); + r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + target_offset = get_elf_r_symndx_offset (r_rel->abfd, r_symndx); + return (target_offset + r_rel->rela.r_addend); +} + + +static struct elf_link_hash_entry * +r_reloc_get_hash_entry (r_rel) + const r_reloc *r_rel; +{ + unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + return get_elf_r_symndx_hash_entry (r_rel->abfd, r_symndx); +} + + +static asection * +r_reloc_get_section (r_rel) + const r_reloc *r_rel; +{ + unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info); + return get_elf_r_symndx_section (r_rel->abfd, r_symndx); +} + + +static bfd_boolean +r_reloc_is_defined (r_rel) + const r_reloc *r_rel; +{ + asection *sec = r_reloc_get_section (r_rel); + if (sec == bfd_abs_section_ptr + || sec == bfd_com_section_ptr + || sec == bfd_und_section_ptr) + return FALSE; + return TRUE; +} + + +/* source_reloc: relocations that reference literal sections. */ + +/* To determine whether literals can be coalesced, we need to first + record all the relocations that reference the literals. The + source_reloc structure below is used for this purpose. The + source_reloc entries are kept in a per-literal-section array, sorted + by offset within the literal section (i.e., target offset). + + The source_sec and r_rel.rela.r_offset fields identify the source of + the relocation. The r_rel field records the relocation value, i.e., + the offset of the literal being referenced. The opnd field is needed + to determine the range of the immediate field to which the relocation + applies, so we can determine whether another literal with the same + value is within range. The is_null field is true when the relocation + is being removed (e.g., when an L32R is being removed due to a CALLX + that is converted to a direct CALL). */ + +typedef struct source_reloc_struct source_reloc; + +struct source_reloc_struct +{ + asection *source_sec; + r_reloc r_rel; + xtensa_operand opnd; + bfd_boolean is_null; +}; + + +static void init_source_reloc + PARAMS ((source_reloc *, asection *, const r_reloc *, xtensa_operand)); +static source_reloc *find_source_reloc + PARAMS ((source_reloc *, int, asection *, Elf_Internal_Rela *)); +static int source_reloc_compare + PARAMS ((const PTR, const PTR)); + + +static void +init_source_reloc (reloc, source_sec, r_rel, opnd) + source_reloc *reloc; + asection *source_sec; + const r_reloc *r_rel; + xtensa_operand opnd; +{ + reloc->source_sec = source_sec; + reloc->r_rel = *r_rel; + reloc->opnd = opnd; + reloc->is_null = FALSE; +} + + +/* Find the source_reloc for a particular source offset and relocation + type. Note that the array is sorted by _target_ offset, so this is + just a linear search. */ + +static source_reloc * +find_source_reloc (src_relocs, src_count, sec, irel) + source_reloc *src_relocs; + int src_count; + asection *sec; + Elf_Internal_Rela *irel; +{ + int i; + + for (i = 0; i < src_count; i++) + { + if (src_relocs[i].source_sec == sec + && src_relocs[i].r_rel.rela.r_offset == irel->r_offset + && (ELF32_R_TYPE (src_relocs[i].r_rel.rela.r_info) + == ELF32_R_TYPE (irel->r_info))) + return &src_relocs[i]; + } + + return NULL; +} + + +static int +source_reloc_compare (ap, bp) + const PTR ap; + const PTR bp; +{ + const source_reloc *a = (const source_reloc *) ap; + const source_reloc *b = (const source_reloc *) bp; + + return (a->r_rel.target_offset - b->r_rel.target_offset); +} + + +/* Literal values and value hash tables. */ + +/* Literals with the same value can be coalesced. The literal_value + structure records the value of a literal: the "r_rel" field holds the + information from the relocation on the literal (if there is one) and + the "value" field holds the contents of the literal word itself. + + The value_map structure records a literal value along with the + location of a literal holding that value. The value_map hash table + is indexed by the literal value, so that we can quickly check if a + particular literal value has been seen before and is thus a candidate + for coalescing. */ + +typedef struct literal_value_struct literal_value; +typedef struct value_map_struct value_map; +typedef struct value_map_hash_table_struct value_map_hash_table; + +struct literal_value_struct +{ + r_reloc r_rel; + unsigned long value; +}; + +struct value_map_struct +{ + literal_value val; /* The literal value. */ + r_reloc loc; /* Location of the literal. */ + value_map *next; +}; + +struct value_map_hash_table_struct +{ + unsigned bucket_count; + value_map **buckets; + unsigned count; +}; + + +static bfd_boolean is_same_value + PARAMS ((const literal_value *, const literal_value *)); +static value_map_hash_table *value_map_hash_table_init + PARAMS ((void)); +static unsigned hash_literal_value + PARAMS ((const literal_value *)); +static unsigned hash_bfd_vma + PARAMS ((bfd_vma)); +static value_map *get_cached_value + PARAMS ((value_map_hash_table *, const literal_value *)); +static value_map *add_value_map + PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *)); + + +static bfd_boolean +is_same_value (src1, src2) + const literal_value *src1; + const literal_value *src2; +{ + if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) + return FALSE; + + if (r_reloc_is_const (&src1->r_rel)) + return (src1->value == src2->value); + + if (ELF32_R_TYPE (src1->r_rel.rela.r_info) + != ELF32_R_TYPE (src2->r_rel.rela.r_info)) + return FALSE; + + if (r_reloc_get_target_offset (&src1->r_rel) + != r_reloc_get_target_offset (&src2->r_rel)) + return FALSE; + + if (src1->value != src2->value) + return FALSE; + + /* Now check for the same section and the same elf_hash. */ + if (r_reloc_is_defined (&src1->r_rel)) + { + if (r_reloc_get_section (&src1->r_rel) + != r_reloc_get_section (&src2->r_rel)) + return FALSE; + } + else + { + if (r_reloc_get_hash_entry (&src1->r_rel) + != r_reloc_get_hash_entry (&src2->r_rel)) + return FALSE; + + if (r_reloc_get_hash_entry (&src1->r_rel) == 0) + return FALSE; + } + + return TRUE; +} + + +/* Must be power of 2. */ +#define INITIAL_HASH_RELOC_BUCKET_COUNT 1024 + +static value_map_hash_table * +value_map_hash_table_init () +{ + value_map_hash_table *values; + + values = (value_map_hash_table *) + bfd_malloc (sizeof (value_map_hash_table)); + + values->bucket_count = INITIAL_HASH_RELOC_BUCKET_COUNT; + values->count = 0; + values->buckets = (value_map **) + bfd_zmalloc (sizeof (value_map *) * values->bucket_count); + + return values; +} + + +static unsigned +hash_bfd_vma (val) + bfd_vma val; +{ + return (val >> 2) + (val >> 10); +} + + +static unsigned +hash_literal_value (src) + const literal_value *src; +{ + unsigned hash_val; + if (r_reloc_is_const (&src->r_rel)) + return hash_bfd_vma (src->value); + + hash_val = (hash_bfd_vma (r_reloc_get_target_offset (&src->r_rel)) + + hash_bfd_vma (src->value)); + + /* Now check for the same section and the same elf_hash. */ + if (r_reloc_is_defined (&src->r_rel)) + hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_section (&src->r_rel)); + else + hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_hash_entry (&src->r_rel)); + + return hash_val; +} + + +/* Check if the specified literal_value has been seen before. */ + +static value_map * +get_cached_value (map, val) + value_map_hash_table *map; + const literal_value *val; +{ + value_map *map_e; + value_map *bucket; + unsigned idx; + + idx = hash_literal_value (val); + idx = idx & (map->bucket_count - 1); + bucket = map->buckets[idx]; + for (map_e = bucket; map_e; map_e = map_e->next) + { + if (is_same_value (&map_e->val, val)) + return map_e; + } + return NULL; +} + + +/* Record a new literal value. It is illegal to call this if VALUE + already has an entry here. */ + +static value_map * +add_value_map (map, val, loc) + value_map_hash_table *map; + const literal_value *val; + const r_reloc *loc; +{ + value_map **bucket_p; + unsigned idx; + + value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map)); + + BFD_ASSERT (get_cached_value (map, val) == NULL); + val_e->val = *val; + val_e->loc = *loc; + + idx = hash_literal_value (val); + idx = idx & (map->bucket_count - 1); + bucket_p = &map->buckets[idx]; + + val_e->next = *bucket_p; + *bucket_p = val_e; + map->count++; + /* FIXME: consider resizing the hash table if we get too many entries */ + + return val_e; +} + + +/* Lists of literals being coalesced or removed. */ + +/* In the usual case, the literal identified by "from" is being + coalesced with another literal identified by "to". If the literal is + unused and is being removed altogether, "to.abfd" will be NULL. + The removed_literal entries are kept on a per-section list, sorted + by the "from" offset field. */ + +typedef struct removed_literal_struct removed_literal; +typedef struct removed_literal_list_struct removed_literal_list; + +struct removed_literal_struct +{ + r_reloc from; + r_reloc to; + removed_literal *next; +}; + +struct removed_literal_list_struct +{ + removed_literal *head; + removed_literal *tail; +}; + + +static void add_removed_literal + PARAMS ((removed_literal_list *, const r_reloc *, const r_reloc *)); +static removed_literal *find_removed_literal + PARAMS ((removed_literal_list *, bfd_vma)); +static bfd_vma offset_with_removed_literals + PARAMS ((removed_literal_list *, bfd_vma)); + + +/* Record that the literal at "from" is being removed. If "to" is not + NULL, the "from" literal is being coalesced with the "to" literal. */ + +static void +add_removed_literal (removed_list, from, to) + removed_literal_list *removed_list; + const r_reloc *from; + const r_reloc *to; +{ + removed_literal *r, *new_r, *next_r; + + new_r = (removed_literal *) bfd_zmalloc (sizeof (removed_literal)); + + new_r->from = *from; + if (to) + new_r->to = *to; + else + new_r->to.abfd = NULL; + new_r->next = NULL; + + r = removed_list->head; + if (r == NULL) + { + removed_list->head = new_r; + removed_list->tail = new_r; + } + /* Special check for common case of append. */ + else if (removed_list->tail->from.target_offset < from->target_offset) + { + removed_list->tail->next = new_r; + removed_list->tail = new_r; + } + else + { + while (r->from.target_offset < from->target_offset + && r->next != NULL) + { + r = r->next; + } + next_r = r->next; + r->next = new_r; + new_r->next = next_r; + if (next_r == NULL) + removed_list->tail = new_r; + } +} + + +/* Check if the list of removed literals contains an entry for the + given address. Return the entry if found. */ + +static removed_literal * +find_removed_literal (removed_list, addr) + removed_literal_list *removed_list; + bfd_vma addr; +{ + removed_literal *r = removed_list->head; + while (r && r->from.target_offset < addr) + r = r->next; + if (r && r->from.target_offset == addr) + return r; + return NULL; +} + + +/* Adjust an offset in a section to compensate for literals that are + being removed. Search the list of removed literals and subtract + 4 bytes for every removed literal prior to the given address. */ + +static bfd_vma +offset_with_removed_literals (removed_list, addr) + removed_literal_list *removed_list; + bfd_vma addr; +{ + removed_literal *r = removed_list->head; + unsigned num_bytes = 0; + + if (r == NULL) + return addr; + + while (r && r->from.target_offset <= addr) + { + num_bytes += 4; + r = r->next; + } + if (num_bytes > addr) + return 0; + return (addr - num_bytes); +} + + +/* Coalescing literals may require a relocation to refer to a section in + a different input file, but the standard relocation information + cannot express that. Instead, the reloc_bfd_fix structures are used + to "fix" the relocations that refer to sections in other input files. + These structures are kept on per-section lists. The "src_type" field + records the relocation type in case there are multiple relocations on + the same location. FIXME: This is ugly; an alternative might be to + add new symbols with the "owner" field to some other input file. */ + +typedef struct reloc_bfd_fix_struct reloc_bfd_fix; + +struct reloc_bfd_fix_struct +{ + asection *src_sec; + bfd_vma src_offset; + unsigned src_type; /* Relocation type. */ + + bfd *target_abfd; + asection *target_sec; + bfd_vma target_offset; + + reloc_bfd_fix *next; +}; + + +static reloc_bfd_fix *reloc_bfd_fix_init + PARAMS ((asection *, bfd_vma, unsigned, bfd *, asection *, bfd_vma)); +static reloc_bfd_fix *get_bfd_fix + PARAMS ((reloc_bfd_fix *, asection *, bfd_vma, unsigned)); + + +static reloc_bfd_fix * +reloc_bfd_fix_init (src_sec, src_offset, src_type, + target_abfd, target_sec, target_offset) + asection *src_sec; + bfd_vma src_offset; + unsigned src_type; + bfd *target_abfd; + asection *target_sec; + bfd_vma target_offset; +{ + reloc_bfd_fix *fix; + + fix = (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix)); + fix->src_sec = src_sec; + fix->src_offset = src_offset; + fix->src_type = src_type; + fix->target_abfd = target_abfd; + fix->target_sec = target_sec; + fix->target_offset = target_offset; + + return fix; +} + + +static reloc_bfd_fix * +get_bfd_fix (fix_list, sec, offset, type) + reloc_bfd_fix *fix_list; + asection *sec; + bfd_vma offset; + unsigned type; +{ + reloc_bfd_fix *r; + + for (r = fix_list; r != NULL; r = r->next) + { + if (r->src_sec == sec + && r->src_offset == offset + && r->src_type == type) + return r; + } + return NULL; +} + + +/* Per-section data for relaxation. */ + +struct xtensa_relax_info_struct +{ + bfd_boolean is_relaxable_literal_section; + int visited; /* Number of times visited. */ + + source_reloc *src_relocs; /* Array[src_count]. */ + int src_count; + int src_next; /* Next src_relocs entry to assign. */ + + removed_literal_list removed_list; + + reloc_bfd_fix *fix_list; +}; + +struct elf_xtensa_section_data +{ + struct bfd_elf_section_data elf; + xtensa_relax_info relax_info; +}; + +static void init_xtensa_relax_info + PARAMS ((asection *)); +static xtensa_relax_info *get_xtensa_relax_info + PARAMS ((asection *)); +static void add_fix + PARAMS ((asection *, reloc_bfd_fix *)); + + +static bfd_boolean +elf_xtensa_new_section_hook (abfd, sec) + bfd *abfd; + asection *sec; +{ + struct elf_xtensa_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); + + sdata = (struct elf_xtensa_section_data *) bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = (PTR) sdata; + + return _bfd_elf_new_section_hook (abfd, sec); +} + + +static void +init_xtensa_relax_info (sec) + asection *sec; +{ + xtensa_relax_info *relax_info = get_xtensa_relax_info (sec); + + relax_info->is_relaxable_literal_section = FALSE; + relax_info->visited = 0; + + relax_info->src_relocs = NULL; + relax_info->src_count = 0; + relax_info->src_next = 0; + + relax_info->removed_list.head = NULL; + relax_info->removed_list.tail = NULL; + + relax_info->fix_list = NULL; +} + + +static xtensa_relax_info * +get_xtensa_relax_info (sec) + asection *sec; +{ + struct elf_xtensa_section_data *section_data; + + /* No info available if no section or if it is an output section. */ + if (!sec || sec == sec->output_section) + return NULL; + + section_data = (struct elf_xtensa_section_data *) elf_section_data (sec); + return §ion_data->relax_info; +} + + +static void +add_fix (src_sec, fix) + asection *src_sec; + reloc_bfd_fix *fix; +{ + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (src_sec); + fix->next = relax_info->fix_list; + relax_info->fix_list = fix; +} + + +/* Access to internal relocations, section contents and symbols. */ + +/* During relaxation, we need to modify relocations, section contents, + and symbol definitions, and we need to keep the original values from + being reloaded from the input files, i.e., we need to "pin" the + modified values in memory. We also want to continue to observe the + setting of the "keep-memory" flag. The following functions wrap the + standard BFD functions to take care of this for us. */ + +static Elf_Internal_Rela * +retrieve_internal_relocs (abfd, sec, keep_memory) + bfd *abfd; + asection *sec; + bfd_boolean keep_memory; +{ + Elf_Internal_Rela *internal_relocs; + + if ((sec->flags & SEC_LINKER_CREATED) != 0) + return NULL; + + internal_relocs = elf_section_data (sec)->relocs; + if (internal_relocs == NULL) + internal_relocs = (_bfd_elf32_link_read_relocs + (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, + keep_memory)); + return internal_relocs; +} + + +static void +pin_internal_relocs (sec, internal_relocs) + asection *sec; + Elf_Internal_Rela *internal_relocs; +{ + elf_section_data (sec)->relocs = internal_relocs; +} + + +static void +release_internal_relocs (sec, internal_relocs) + asection *sec; + Elf_Internal_Rela *internal_relocs; +{ + if (internal_relocs + && elf_section_data (sec)->relocs != internal_relocs) + free (internal_relocs); +} + + +static bfd_byte * +retrieve_contents (abfd, sec, keep_memory) + bfd *abfd; + asection *sec; + bfd_boolean keep_memory; +{ + bfd_byte *contents; + + contents = elf_section_data (sec)->this_hdr.contents; + + if (contents == NULL && sec->_raw_size != 0) + { + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents != NULL) + { + if (! bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + { + free (contents); + return NULL; + } + if (keep_memory) + elf_section_data (sec)->this_hdr.contents = contents; + } + } + return contents; +} + + +static void +pin_contents (sec, contents) + asection *sec; + bfd_byte *contents; +{ + elf_section_data (sec)->this_hdr.contents = contents; +} + + +static void +release_contents (sec, contents) + asection *sec; + bfd_byte *contents; +{ + if (contents && + elf_section_data (sec)->this_hdr.contents != contents) + free (contents); +} + + +static Elf_Internal_Sym * +retrieve_local_syms (input_bfd) + bfd *input_bfd; +{ + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isymbuf; + size_t locsymcount; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL && locsymcount != 0) + isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, + NULL, NULL, NULL); + + /* Save the symbols for this input file so they won't be read again. */ + if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents) + symtab_hdr->contents = (unsigned char *) isymbuf; + + return isymbuf; +} + + +/* Code for link-time relaxation. */ + +/* Local helper functions. */ +static bfd_boolean analyze_relocations + PARAMS ((struct bfd_link_info *)); +static bfd_boolean find_relaxable_sections + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); +static bfd_boolean collect_source_relocs + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean is_resolvable_asm_expansion + PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, + struct bfd_link_info *, bfd_boolean *)); +static bfd_boolean remove_literals + PARAMS ((bfd *, asection *, struct bfd_link_info *, value_map_hash_table *)); +static bfd_boolean relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean relax_property_section + PARAMS ((bfd *, asection *, struct bfd_link_info *)); +static bfd_boolean relax_section_symbols + PARAMS ((bfd *, asection *)); +static bfd_boolean relocations_reach + PARAMS ((source_reloc *, int, const r_reloc *)); +static void translate_reloc + PARAMS ((const r_reloc *, r_reloc *)); +static Elf_Internal_Rela *get_irel_at_offset + PARAMS ((asection *, Elf_Internal_Rela *, bfd_vma)); +static Elf_Internal_Rela *find_associated_l32r_irel + PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *, + Elf_Internal_Rela *)); +static void shrink_dynamic_reloc_sections + PARAMS ((struct bfd_link_info *, bfd *, asection *, Elf_Internal_Rela *)); + + +static bfd_boolean +elf_xtensa_relax_section (abfd, sec, link_info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + bfd_boolean *again; +{ + static value_map_hash_table *values = NULL; + xtensa_relax_info *relax_info; + + if (!values) + { + /* Do some overall initialization for relaxation. */ + values = value_map_hash_table_init (); + relaxing_section = TRUE; + if (!analyze_relocations (link_info)) + return FALSE; + } + *again = FALSE; + + /* Don't mess with linker-created sections. */ + if ((sec->flags & SEC_LINKER_CREATED) != 0) + return TRUE; + + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info != NULL); + + switch (relax_info->visited) + { + case 0: + /* Note: It would be nice to fold this pass into + analyze_relocations, but it is important for this step that the + sections be examined in link order. */ + if (!remove_literals (abfd, sec, link_info, values)) + return FALSE; + *again = TRUE; + break; + + case 1: + if (!relax_section (abfd, sec, link_info)) + return FALSE; + *again = TRUE; + break; + + case 2: + if (!relax_section_symbols (abfd, sec)) + return FALSE; + break; + } + + relax_info->visited++; + return TRUE; +} + +/* Initialization for relaxation. */ + +/* This function is called once at the start of relaxation. It scans + all the input sections and marks the ones that are relaxable (i.e., + literal sections with L32R relocations against them). It then + collect source_reloc information for all the relocations against + those relaxable sections. */ + +static bfd_boolean +analyze_relocations (link_info) + struct bfd_link_info *link_info; +{ + bfd *abfd; + asection *sec; + bfd_boolean is_relaxable = FALSE; + + /* Initialize the per-section relaxation info. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + init_xtensa_relax_info (sec); + } + + /* Mark relaxable sections (and count relocations against each one). */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (!find_relaxable_sections (abfd, sec, link_info, &is_relaxable)) + return FALSE; + } + + /* Bail out if there are no relaxable sections. */ + if (!is_relaxable) + return TRUE; + + /* Allocate space for source_relocs. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + xtensa_relax_info *relax_info; + + relax_info = get_xtensa_relax_info (sec); + if (relax_info->is_relaxable_literal_section) + { + relax_info->src_relocs = (source_reloc *) + bfd_malloc (relax_info->src_count * sizeof (source_reloc)); + } + } + + /* Collect info on relocations against each relaxable section. */ + for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (!collect_source_relocs (abfd, sec, link_info)) + return FALSE; + } + + return TRUE; +} + + +/* Find all the literal sections that might be relaxed. The motivation + for this pass is that collect_source_relocs() needs to record _all_ + the relocations that target each relaxable section. That is + expensive and unnecessary unless the target section is actually going + to be relaxed. This pass identifies all such sections by checking if + they have L32Rs pointing to them. In the process, the total number + of relocations targetting each section is also counted so that we + know how much space to allocate for source_relocs against each + relaxable literal section. */ + +static bfd_boolean +find_relaxable_sections (abfd, sec, link_info, is_relaxable_p) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + bfd_boolean *is_relaxable_p; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + bfd_boolean ok = TRUE; + unsigned i; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + if (internal_relocs == NULL) + return ok; + + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + r_reloc_init (&r_rel, abfd, irel); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + if (!target_relax_info) + continue; + + /* Count relocations against the target section. */ + target_relax_info->src_count++; + + if (is_literal_section (target_sec) + && is_l32r_relocation (sec, contents, irel) + && r_reloc_is_defined (&r_rel)) + { + /* Mark the target section as relaxable. */ + target_relax_info->is_relaxable_literal_section = TRUE; + *is_relaxable_p = TRUE; + } + } + + error_return: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +/* Record _all_ the relocations that point to relaxable literal + sections, and get rid of ASM_EXPAND relocs by either converting them + to ASM_SIMPLIFY or by removing them. */ + +static bfd_boolean +collect_source_relocs (abfd, sec, link_info) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + bfd_boolean ok = TRUE; + unsigned i; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + if (internal_relocs == NULL) + return ok; + + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + /* Record relocations against relaxable literal sections. */ + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + r_reloc_init (&r_rel, abfd, irel); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && target_relax_info->is_relaxable_literal_section) + { + xtensa_opcode opcode; + xtensa_operand opnd; + source_reloc *s_reloc; + int src_next; + + src_next = target_relax_info->src_next++; + s_reloc = &target_relax_info->src_relocs[src_next]; + + opcode = get_relocation_opcode (sec, contents, irel); + if (opcode == XTENSA_UNDEFINED) + opnd = NULL; + else + opnd = xtensa_get_operand (xtensa_default_isa, opcode, + get_relocation_opnd (irel)); + + init_source_reloc (s_reloc, sec, &r_rel, opnd); + } + } + + /* Now get rid of ASM_EXPAND relocations. At this point, the + src_relocs array for the target literal section may still be + incomplete, but it must at least contain the entries for the L32R + relocations associated with ASM_EXPANDs because they were just + added in the preceding loop over the relocations. */ + + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + bfd_boolean is_reachable; + + if (!is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, + &is_reachable)) + continue; + + if (is_reachable) + { + Elf_Internal_Rela *l32r_irel; + r_reloc r_rel; + asection *target_sec; + xtensa_relax_info *target_relax_info; + + /* Mark the source_reloc for the L32R so that it will be + removed in remove_literals(), along with the associated + literal. */ + l32r_irel = find_associated_l32r_irel (sec, contents, + irel, internal_relocs); + if (l32r_irel == NULL) + continue; + + r_reloc_init (&r_rel, abfd, l32r_irel); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && target_relax_info->is_relaxable_literal_section) + { + source_reloc *s_reloc; + + /* Search the source_relocs for the entry corresponding to + the l32r_irel. Note: The src_relocs array is not yet + sorted, but it wouldn't matter anyway because we're + searching by source offset instead of target offset. */ + s_reloc = find_source_reloc (target_relax_info->src_relocs, + target_relax_info->src_next, + sec, l32r_irel); + BFD_ASSERT (s_reloc); + s_reloc->is_null = TRUE; + } + + /* Convert this reloc to ASM_SIMPLIFY. */ + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), + R_XTENSA_ASM_SIMPLIFY); + l32r_irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + + pin_internal_relocs (sec, internal_relocs); + } + else + { + /* It is resolvable but doesn't reach. We resolve now + by eliminating the relocation -- the call will remain + expanded into L32R/CALLX. */ + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + pin_internal_relocs (sec, internal_relocs); + } + } + + error_return: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +/* Return TRUE if the asm expansion can be resolved. Generally it can + be resolved on a final link or when a partial link locates it in the + same section as the target. Set "is_reachable" flag if the target of + the call is within the range of a direct call, given the current VMA + for this section and the target section. */ + +bfd_boolean +is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info, + is_reachable_p) + bfd *abfd; + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *irel; + struct bfd_link_info *link_info; + bfd_boolean *is_reachable_p; +{ + asection *target_sec; + bfd_vma target_offset; + r_reloc r_rel; + xtensa_opcode opcode, direct_call_opcode; + bfd_vma self_address; + bfd_vma dest_address; + + *is_reachable_p = FALSE; + + if (contents == NULL) + return FALSE; + + if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) + return FALSE; + + opcode = get_expanded_call_opcode (contents + irel->r_offset, + sec->_raw_size - irel->r_offset); + + direct_call_opcode = swap_callx_for_call_opcode (opcode); + if (direct_call_opcode == XTENSA_UNDEFINED) + return FALSE; + + /* Check and see that the target resolves. */ + r_reloc_init (&r_rel, abfd, irel); + if (!r_reloc_is_defined (&r_rel)) + return FALSE; + + target_sec = r_reloc_get_section (&r_rel); + target_offset = r_reloc_get_target_offset (&r_rel); + + /* If the target is in a shared library, then it doesn't reach. This + isn't supposed to come up because the compiler should never generate + non-PIC calls on systems that use shared libraries, but the linker + shouldn't crash regardless. */ + if (!target_sec->output_section) + return FALSE; + + /* For relocateable sections, we can only simplify when the output + section of the target is the same as the output section of the + source. */ + if (link_info->relocateable + && (target_sec->output_section != sec->output_section)) + return FALSE; + + self_address = (sec->output_section->vma + + sec->output_offset + irel->r_offset + 3); + dest_address = (target_sec->output_section->vma + + target_sec->output_offset + target_offset); + + *is_reachable_p = pcrel_reloc_fits + (xtensa_get_operand (xtensa_default_isa, direct_call_opcode, 0), + self_address, dest_address); + + if ((self_address >> CALL_SEGMENT_BITS) != + (dest_address >> CALL_SEGMENT_BITS)) + return FALSE; + + return TRUE; +} + + +static Elf_Internal_Rela * +find_associated_l32r_irel (sec, contents, other_irel, internal_relocs) + asection *sec; + bfd_byte *contents; + Elf_Internal_Rela *other_irel; + Elf_Internal_Rela *internal_relocs; +{ + unsigned i; + + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + + if (irel == other_irel) + continue; + if (irel->r_offset != other_irel->r_offset) + continue; + if (is_l32r_relocation (sec, contents, irel)) + return irel; + } + + return NULL; +} + +/* First relaxation pass. */ + +/* If the section is relaxable (i.e., a literal section), check each + literal to see if it has the same value as another literal that has + already been seen, either in the current section or a previous one. + If so, add an entry to the per-section list of removed literals. The + actual changes are deferred until the next pass. */ + +static bfd_boolean +remove_literals (abfd, sec, link_info, values) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + value_map_hash_table *values; +{ + xtensa_relax_info *relax_info; + bfd_byte *contents; + Elf_Internal_Rela *internal_relocs; + source_reloc *src_relocs; + bfd_boolean ok = TRUE; + int i; + + /* Do nothing if it is not a relaxable literal section. */ + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info); + + if (!relax_info->is_relaxable_literal_section) + return ok; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + /* Sort the source_relocs by target offset. */ + src_relocs = relax_info->src_relocs; + qsort (src_relocs, relax_info->src_count, + sizeof (source_reloc), source_reloc_compare); + + for (i = 0; i < relax_info->src_count; i++) + { + source_reloc *rel; + Elf_Internal_Rela *irel = NULL; + literal_value val; + value_map *val_map; + + rel = &src_relocs[i]; + irel = get_irel_at_offset (sec, internal_relocs, + rel->r_rel.target_offset); + + /* If the target_offset for this relocation is the same as the + previous relocation, then we've already considered whether the + literal can be coalesced. Skip to the next one.... */ + if (i != 0 && (src_relocs[i-1].r_rel.target_offset + == rel->r_rel.target_offset)) + continue; + + /* Check if the relocation was from an L32R that is being removed + because a CALLX was converted to a direct CALL, and check if + there are no other relocations to the literal. */ + if (rel->is_null + && (i == relax_info->src_count - 1 + || (src_relocs[i+1].r_rel.target_offset + != rel->r_rel.target_offset))) + { + /* Mark the unused literal so that it will be removed. */ + add_removed_literal (&relax_info->removed_list, &rel->r_rel, NULL); + + /* Zero out the relocation on this literal location. */ + if (irel) + { + if (elf_hash_table (link_info)->dynamic_sections_created) + shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); + + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + } + + continue; + } + + /* Find the literal value. */ + r_reloc_init (&val.r_rel, abfd, irel); + BFD_ASSERT (rel->r_rel.target_offset < sec->_raw_size); + val.value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset); + + /* Check if we've seen another literal with the same value. */ + val_map = get_cached_value (values, &val); + if (val_map != NULL) + { + /* First check that THIS and all the other relocs to this + literal will FIT if we move them to the new address. */ + + if (relocations_reach (rel, relax_info->src_count - i, + &val_map->loc)) + { + /* Mark that the literal will be coalesced. */ + add_removed_literal (&relax_info->removed_list, + &rel->r_rel, &val_map->loc); + } + else + { + /* Relocations do not reach -- do not remove this literal. */ + val_map->loc = rel->r_rel; + } + } + else + { + /* This is the first time we've seen this literal value. */ + BFD_ASSERT (sec == r_reloc_get_section (&rel->r_rel)); + add_value_map (values, &val, &rel->r_rel); + } + } + +error_return: + release_contents (sec, contents); + release_internal_relocs (sec, internal_relocs); + return ok; +} + + +/* Check if the original relocations (presumably on L32R instructions) + identified by reloc[0..N] can be changed to reference the literal + identified by r_rel. If r_rel is out of range for any of the + original relocations, then we don't want to coalesce the original + literal with the one at r_rel. We only check reloc[0..N], where the + offsets are all the same as for reloc[0] (i.e., they're all + referencing the same literal) and where N is also bounded by the + number of remaining entries in the "reloc" array. The "reloc" array + is sorted by target offset so we know all the entries for the same + literal will be contiguous. */ + +static bfd_boolean +relocations_reach (reloc, remaining_relocs, r_rel) + source_reloc *reloc; + int remaining_relocs; + const r_reloc *r_rel; +{ + bfd_vma from_offset, source_address, dest_address; + asection *sec; + int i; + + if (!r_reloc_is_defined (r_rel)) + return FALSE; + + sec = r_reloc_get_section (r_rel); + from_offset = reloc[0].r_rel.target_offset; + + for (i = 0; i < remaining_relocs; i++) + { + if (reloc[i].r_rel.target_offset != from_offset) + break; + + /* Ignore relocations that have been removed. */ + if (reloc[i].is_null) + continue; + + /* The original and new output section for these must be the same + in order to coalesce. */ + if (r_reloc_get_section (&reloc[i].r_rel)->output_section + != sec->output_section) + return FALSE; + + /* A NULL operand means it is not a PC-relative relocation, so + the literal can be moved anywhere. */ + if (reloc[i].opnd) + { + /* Otherwise, check to see that it fits. */ + source_address = (reloc[i].source_sec->output_section->vma + + reloc[i].source_sec->output_offset + + reloc[i].r_rel.rela.r_offset); + dest_address = (sec->output_section->vma + + sec->output_offset + + r_rel->target_offset); + + if (!pcrel_reloc_fits (reloc[i].opnd, source_address, dest_address)) + return FALSE; + } + } + + return TRUE; +} + + +/* WARNING: linear search here. If the relocation are in order by + address, we can use a faster binary search. ALSO, we assume that + there is only 1 non-NONE relocation per address. */ + +static Elf_Internal_Rela * +get_irel_at_offset (sec, internal_relocs, offset) + asection *sec; + Elf_Internal_Rela *internal_relocs; + bfd_vma offset; +{ + unsigned i; + if (!internal_relocs) + return NULL; + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + if (irel->r_offset == offset + && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE) + return irel; + } + return NULL; +} + + +/* Second relaxation pass. */ + +/* Modify all of the relocations to point to the right spot, and if this + is a relaxable section, delete the unwanted literals and fix the + cooked_size. */ + +bfd_boolean +relax_section (abfd, sec, link_info) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; +{ + Elf_Internal_Rela *internal_relocs; + xtensa_relax_info *relax_info; + bfd_byte *contents; + bfd_boolean ok = TRUE; + unsigned i; + + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info); + + /* Handle property sections (e.g., literal tables) specially. */ + if (xtensa_is_property_section (sec)) + { + BFD_ASSERT (!relax_info->is_relaxable_literal_section); + return relax_property_section (abfd, sec, link_info); + } + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + if (internal_relocs) + { + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel; + xtensa_relax_info *target_relax_info; + bfd_vma source_offset; + r_reloc r_rel; + unsigned r_type; + asection *target_sec; + + /* Locally change the source address. + Translate the target to the new target address. + If it points to this section and has been removed, + NULLify it. + Write it back. */ + + irel = &internal_relocs[i]; + source_offset = irel->r_offset; + + r_type = ELF32_R_TYPE (irel->r_info); + r_reloc_init (&r_rel, abfd, irel); + + if (relax_info->is_relaxable_literal_section) + { + if (r_type != R_XTENSA_NONE + && find_removed_literal (&relax_info->removed_list, + irel->r_offset)) + { + /* Remove this relocation. */ + if (elf_hash_table (link_info)->dynamic_sections_created) + shrink_dynamic_reloc_sections (link_info, abfd, sec, irel); + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + irel->r_offset = offset_with_removed_literals + (&relax_info->removed_list, irel->r_offset); + continue; + } + source_offset = + offset_with_removed_literals (&relax_info->removed_list, + irel->r_offset); + irel->r_offset = source_offset; + } + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && target_relax_info->is_relaxable_literal_section) + { + r_reloc new_rel; + reloc_bfd_fix *fix; + + translate_reloc (&r_rel, &new_rel); + + /* FIXME: If the relocation still references a section in + the same input file, the relocation should be modified + directly instead of adding a "fix" record. */ + + fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0, + r_reloc_get_section (&new_rel), + new_rel.target_offset); + add_fix (sec, fix); + } + + pin_internal_relocs (sec, internal_relocs); + } + } + + if (relax_info->is_relaxable_literal_section) + { + /* Walk through the contents and delete literals that are not needed + anymore. */ + + unsigned long size = sec->_cooked_size; + unsigned long removed = 0; + + removed_literal *reloc = relax_info->removed_list.head; + for (; reloc; reloc = reloc->next) + { + unsigned long upper = sec->_raw_size; + bfd_vma start = reloc->from.target_offset + 4; + if (reloc->next) + upper = reloc->next->from.target_offset; + if (upper - start != 0) + { + BFD_ASSERT (start <= upper); + memmove (contents + start - removed - 4, + contents + start, + upper - start ); + pin_contents (sec, contents); + } + removed += 4; + size -= 4; + } + + /* Change the section size. */ + sec->_cooked_size = size; + /* Also shrink _raw_size. (The code in relocate_section that + checks that relocations are within the section must use + _raw_size because of the way the stabs sections are relaxed; + shrinking _raw_size means that these checks will not be + unnecessarily lax.) */ + sec->_raw_size = size; + } + + error_return: + release_internal_relocs (sec, internal_relocs); + release_contents (sec, contents); + return ok; +} + + +/* Fix up a relocation to take account of removed literals. */ + +static void +translate_reloc (orig_rel, new_rel) + const r_reloc *orig_rel; + r_reloc *new_rel; +{ + asection *sec; + xtensa_relax_info *relax_info; + removed_literal *removed; + unsigned long new_offset; + + *new_rel = *orig_rel; + + if (!r_reloc_is_defined (orig_rel)) + return; + sec = r_reloc_get_section (orig_rel); + + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info); + + if (!relax_info->is_relaxable_literal_section) + return; + + /* Check if the original relocation is against a literal being removed. */ + removed = find_removed_literal (&relax_info->removed_list, + orig_rel->target_offset); + if (removed) + { + asection *new_sec; + + /* The fact that there is still a relocation to this literal indicates + that the literal is being coalesced, not simply removed. */ + BFD_ASSERT (removed->to.abfd != NULL); + + /* This was moved to some other address (possibly in another section). */ + *new_rel = removed->to; + new_sec = r_reloc_get_section (new_rel); + if (new_sec != sec) + { + sec = new_sec; + relax_info = get_xtensa_relax_info (sec); + if (!relax_info || !relax_info->is_relaxable_literal_section) + return; + } + } + + /* ...and the target address may have been moved within its section. */ + new_offset = offset_with_removed_literals (&relax_info->removed_list, + new_rel->target_offset); + + /* Modify the offset and addend. */ + new_rel->target_offset = new_offset; + new_rel->rela.r_addend += (new_offset - new_rel->target_offset); +} + + +/* For dynamic links, there may be a dynamic relocation for each + literal. The number of dynamic relocations must be computed in + size_dynamic_sections, which occurs before relaxation. When a + literal is removed, this function checks if there is a corresponding + dynamic relocation and shrinks the size of the appropriate dynamic + relocation section accordingly. At this point, the contents of the + dynamic relocation sections have not yet been filled in, so there's + nothing else that needs to be done. */ + +static void +shrink_dynamic_reloc_sections (info, abfd, input_section, rel) + struct bfd_link_info *info; + bfd *abfd; + asection *input_section; + Elf_Internal_Rela *rel; +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + unsigned long r_symndx; + int r_type; + struct elf_link_hash_entry *h; + bfd_boolean dynamic_symbol; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + r_type = ELF32_R_TYPE (rel->r_info); + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h); + + if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT) + && (input_section->flags & SEC_ALLOC) != 0 + && (dynamic_symbol || info->shared)) + { + bfd *dynobj; + const char *srel_name; + asection *srel; + bfd_boolean is_plt = FALSE; + + dynobj = elf_hash_table (info)->dynobj; + BFD_ASSERT (dynobj != NULL); + + if (dynamic_symbol && r_type == R_XTENSA_PLT) + { + srel_name = ".rela.plt"; + is_plt = TRUE; + } + else + srel_name = ".rela.got"; + + /* Reduce size of the .rela.* section by one reloc. */ + srel = bfd_get_section_by_name (dynobj, srel_name); + BFD_ASSERT (srel != NULL); + BFD_ASSERT (srel->_cooked_size >= sizeof (Elf32_External_Rela)); + srel->_cooked_size -= sizeof (Elf32_External_Rela); + + /* Also shrink _raw_size. (This seems wrong but other bfd code seems + to assume that linker-created sections will never be relaxed and + hence _raw_size must always equal _cooked_size.) */ + srel->_raw_size = srel->_cooked_size; + + if (is_plt) + { + asection *splt, *sgotplt, *srelgot; + int reloc_index, chunk; + + /* Find the PLT reloc index of the entry being removed. This + is computed from the size of ".rela.plt". It is needed to + figure out which PLT chunk to resize. Usually "last index + = size - 1" since the index starts at zero, but in this + context, the size has just been decremented so there's no + need to subtract one. */ + reloc_index = srel->_cooked_size / sizeof (Elf32_External_Rela); + + chunk = reloc_index / PLT_ENTRIES_PER_CHUNK; + splt = elf_xtensa_get_plt_section (dynobj, chunk); + sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk); + BFD_ASSERT (splt != NULL && sgotplt != NULL); + + /* Check if an entire PLT chunk has just been eliminated. */ + if (reloc_index % PLT_ENTRIES_PER_CHUNK == 0) + { + /* The two magic GOT entries for that chunk can go away. */ + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srelgot != NULL); + srelgot->reloc_count -= 2; + srelgot->_cooked_size -= 2 * sizeof (Elf32_External_Rela); + /* Shrink _raw_size (see comment above). */ + srelgot->_raw_size = srelgot->_cooked_size; + + sgotplt->_cooked_size -= 8; + + /* There should be only one entry left (and it will be + removed below). */ + BFD_ASSERT (sgotplt->_cooked_size == 4); + BFD_ASSERT (splt->_cooked_size == PLT_ENTRY_SIZE); + } + + BFD_ASSERT (sgotplt->_cooked_size >= 4); + BFD_ASSERT (splt->_cooked_size >= PLT_ENTRY_SIZE); + + sgotplt->_cooked_size -= 4; + splt->_cooked_size -= PLT_ENTRY_SIZE; + + /* Shrink _raw_sizes (see comment above). */ + sgotplt->_raw_size = sgotplt->_cooked_size; + splt->_raw_size = splt->_cooked_size; + } + } +} + + +/* This is similar to relax_section except that when a target is moved, + we shift addresses up. We also need to modify the size. This + algorithm does NOT allow for relocations into the middle of the + property sections. */ + +static bfd_boolean +relax_property_section (abfd, sec, link_info) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + unsigned i, nexti; + bfd_boolean ok = TRUE; + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + if (internal_relocs) + { + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel; + xtensa_relax_info *target_relax_info; + r_reloc r_rel; + unsigned r_type; + asection *target_sec; + + /* Locally change the source address. + Translate the target to the new target address. + If it points to this section and has been removed, MOVE IT. + Also, don't forget to modify the associated SIZE at + (offset + 4). */ + + irel = &internal_relocs[i]; + r_type = ELF32_R_TYPE (irel->r_info); + if (r_type == R_XTENSA_NONE) + continue; + + r_reloc_init (&r_rel, abfd, irel); + + target_sec = r_reloc_get_section (&r_rel); + target_relax_info = get_xtensa_relax_info (target_sec); + + if (target_relax_info + && target_relax_info->is_relaxable_literal_section) + { + /* Translate the relocation's destination. */ + bfd_vma new_offset; + bfd_vma new_end_offset; + bfd_byte *size_p; + long old_size, new_size; + + new_offset = + offset_with_removed_literals (&target_relax_info->removed_list, + r_rel.target_offset); + + /* Assert that we are not out of bounds. */ + size_p = &contents[irel->r_offset + 4]; + old_size = bfd_get_32 (abfd, &contents[irel->r_offset + 4]); + + new_end_offset = + offset_with_removed_literals (&target_relax_info->removed_list, + r_rel.target_offset + old_size); + + new_size = new_end_offset - new_offset; + if (new_size != old_size) + { + bfd_put_32 (abfd, new_size, size_p); + pin_contents (sec, contents); + } + + if (new_offset != r_rel.target_offset) + { + bfd_vma diff = new_offset - r_rel.target_offset; + irel->r_addend += diff; + pin_internal_relocs (sec, internal_relocs); + } + } + } + } + + /* Combine adjacent property table entries. This is also done in + finish_dynamic_sections() but at that point it's too late to + reclaim the space in the output section, so we do this twice. */ + + if (internal_relocs) + { + Elf_Internal_Rela *last_irel = NULL; + int removed_bytes = 0; + bfd_vma offset, last_irel_offset; + bfd_vma section_size; + + /* Walk over memory and irels at the same time. + This REQUIRES that the internal_relocs be sorted by offset. */ + qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela), + internal_reloc_compare); + nexti = 0; /* Index into internal_relocs. */ + + pin_internal_relocs (sec, internal_relocs); + pin_contents (sec, contents); + + last_irel_offset = (bfd_vma) -1; + section_size = (sec->_cooked_size ? sec->_cooked_size : sec->_raw_size); + BFD_ASSERT (section_size % 8 == 0); + + for (offset = 0; offset < section_size; offset += 8) + { + Elf_Internal_Rela *irel, *next_irel; + bfd_vma bytes_to_remove, size, actual_offset; + bfd_boolean remove_this_irel; + + irel = NULL; + next_irel = NULL; + + /* Find the next two relocations (if there are that many left), + skipping over any R_XTENSA_NONE relocs. On entry, "nexti" is + the starting reloc index. After these two loops, "i" + is the index of the first non-NONE reloc past that starting + index, and "nexti" is the index for the next non-NONE reloc + after "i". */ + + for (i = nexti; i < sec->reloc_count; i++) + { + if (ELF32_R_TYPE (internal_relocs[i].r_info) != R_XTENSA_NONE) + { + irel = &internal_relocs[i]; + break; + } + internal_relocs[i].r_offset -= removed_bytes; + } + + for (nexti = i + 1; nexti < sec->reloc_count; nexti++) + { + if (ELF32_R_TYPE (internal_relocs[nexti].r_info) + != R_XTENSA_NONE) + { + next_irel = &internal_relocs[nexti]; + break; + } + internal_relocs[nexti].r_offset -= removed_bytes; + } + + remove_this_irel = FALSE; + bytes_to_remove = 0; + actual_offset = offset - removed_bytes; + size = bfd_get_32 (abfd, &contents[actual_offset + 4]); + + /* Check that the irels are sorted by offset, + with only one per address. */ + BFD_ASSERT (!irel || (int) irel->r_offset > (int) last_irel_offset); + BFD_ASSERT (!next_irel || next_irel->r_offset > irel->r_offset); + + /* Make sure there isn't a reloc on the size field. */ + if (irel && irel->r_offset == offset + 4) + { + irel->r_offset -= removed_bytes; + last_irel_offset = irel->r_offset; + } + else if (next_irel && next_irel->r_offset == offset + 4) + { + nexti += 1; + irel->r_offset -= removed_bytes; + next_irel->r_offset -= removed_bytes; + last_irel_offset = next_irel->r_offset; + } + else if (size == 0) + { + /* Always remove entries with zero size. */ + bytes_to_remove = 8; + if (irel && irel->r_offset == offset) + { + remove_this_irel = TRUE; + + irel->r_offset -= removed_bytes; + last_irel_offset = irel->r_offset; + } + } + else if (irel && irel->r_offset == offset) + { + if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32) + { + if (last_irel) + { + bfd_vma old_size = + bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]); + bfd_vma old_address = + (last_irel->r_addend + + bfd_get_32 (abfd, &contents[last_irel->r_offset])); + bfd_vma new_address = + (irel->r_addend + + bfd_get_32 (abfd, &contents[actual_offset])); + + if ((ELF32_R_SYM (irel->r_info) == + ELF32_R_SYM (last_irel->r_info)) + && (old_address + old_size == new_address)) + { + /* fix the old size */ + bfd_put_32 (abfd, old_size + size, + &contents[last_irel->r_offset + 4]); + bytes_to_remove = 8; + remove_this_irel = TRUE; + } + else + last_irel = irel; + } + else + last_irel = irel; + } + + irel->r_offset -= removed_bytes; + last_irel_offset = irel->r_offset; + } + + if (remove_this_irel) + { + irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); + irel->r_offset -= bytes_to_remove; + } + + if (bytes_to_remove != 0) + { + removed_bytes += bytes_to_remove; + if (offset + 8 < section_size) + memmove (&contents[actual_offset], + &contents[actual_offset+8], + section_size - offset - 8); + } + } + + if (removed_bytes) + { + /* Clear the removed bytes. */ + memset (&contents[section_size - removed_bytes], 0, removed_bytes); + + sec->_cooked_size = section_size - removed_bytes; + /* Also shrink _raw_size. (The code in relocate_section that + checks that relocations are within the section must use + _raw_size because of the way the stabs sections are + relaxed; shrinking _raw_size means that these checks will + not be unnecessarily lax.) */ + sec->_raw_size = sec->_cooked_size; + } + } + + error_return: + release_internal_relocs (sec, internal_relocs); + release_contents (sec, contents); + return ok; +} + + +/* Third relaxation pass. */ + +/* Change symbol values to account for removed literals. */ + +bfd_boolean +relax_section_symbols (abfd, sec) + bfd *abfd; + asection *sec; +{ + xtensa_relax_info *relax_info; + unsigned int sec_shndx; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Sym *isymbuf; + unsigned i, num_syms, num_locals; + + relax_info = get_xtensa_relax_info (sec); + BFD_ASSERT (relax_info); + + if (!relax_info->is_relaxable_literal_section) + return TRUE; + + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + isymbuf = retrieve_local_syms (abfd); + + num_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym); + num_locals = symtab_hdr->sh_info; + + /* Adjust the local symbols defined in this section. */ + for (i = 0; i < num_locals; i++) + { + Elf_Internal_Sym *isym = &isymbuf[i]; + + if (isym->st_shndx == sec_shndx) + { + bfd_vma new_address = offset_with_removed_literals + (&relax_info->removed_list, isym->st_value); + if (new_address != isym->st_value) + isym->st_value = new_address; + } + } + + /* Now adjust the global symbols defined in this section. */ + for (i = 0; i < (num_syms - num_locals); i++) + { + struct elf_link_hash_entry *sym_hash; + + sym_hash = elf_sym_hashes (abfd)[i]; + + if (sym_hash->root.type == bfd_link_hash_warning) + sym_hash = (struct elf_link_hash_entry *) sym_hash->root.u.i.link; + + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec) + { + bfd_vma new_address = offset_with_removed_literals + (&relax_info->removed_list, sym_hash->root.u.def.value); + if (new_address != sym_hash->root.u.def.value) + sym_hash->root.u.def.value = new_address; + } + } + + return TRUE; +} + + +/* "Fix" handling functions, called while performing relocations. */ + +static void +do_fix_for_relocateable_link (rel, input_bfd, input_section) + Elf_Internal_Rela *rel; + bfd *input_bfd; + asection *input_section; +{ + r_reloc r_rel; + asection *sec, *old_sec; + bfd_vma old_offset; + int r_type = ELF32_R_TYPE (rel->r_info); + reloc_bfd_fix *fix_list; + reloc_bfd_fix *fix; + + if (r_type == R_XTENSA_NONE) + return; + + fix_list = (get_xtensa_relax_info (input_section))->fix_list; + if (fix_list == NULL) + return; + + fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type); + if (fix == NULL) + return; + + r_reloc_init (&r_rel, input_bfd, rel); + old_sec = r_reloc_get_section (&r_rel); + old_offset = r_reloc_get_target_offset (&r_rel); + + if (old_sec == NULL || !r_reloc_is_defined (&r_rel)) + { + BFD_ASSERT (r_type == R_XTENSA_ASM_EXPAND); + /* Leave it be. Resolution will happen in a later stage. */ + } + else + { + sec = fix->target_sec; + rel->r_addend += ((sec->output_offset + fix->target_offset) + - (old_sec->output_offset + old_offset)); + } +} + + +static void +do_fix_for_final_link (rel, input_section, relocationp) + Elf_Internal_Rela *rel; + asection *input_section; + bfd_vma *relocationp; +{ + asection *sec; + int r_type = ELF32_R_TYPE (rel->r_info); + reloc_bfd_fix *fix_list; + reloc_bfd_fix *fix; + + if (r_type == R_XTENSA_NONE) + return; + + fix_list = (get_xtensa_relax_info (input_section))->fix_list; + if (fix_list == NULL) + return; + + fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type); + if (fix == NULL) + return; + + sec = fix->target_sec; + *relocationp = (sec->output_section->vma + + sec->output_offset + + fix->target_offset - rel->r_addend); +} + + +/* Miscellaneous utility functions.... */ + +static asection * +elf_xtensa_get_plt_section (dynobj, chunk) + bfd *dynobj; + int chunk; +{ + char plt_name[10]; + + if (chunk == 0) + return bfd_get_section_by_name (dynobj, ".plt"); + + sprintf (plt_name, ".plt.%u", chunk); + return bfd_get_section_by_name (dynobj, plt_name); +} + + +static asection * +elf_xtensa_get_gotplt_section (dynobj, chunk) + bfd *dynobj; + int chunk; +{ + char got_name[14]; + + if (chunk == 0) + return bfd_get_section_by_name (dynobj, ".got.plt"); + + sprintf (got_name, ".got.plt.%u", chunk); + return bfd_get_section_by_name (dynobj, got_name); +} + + +/* Get the input section for a given symbol index. + If the symbol is: + . a section symbol, return the section; + . a common symbol, return the common section; + . an undefined symbol, return the undefined section; + . an indirect symbol, follow the links; + . an absolute value, return the absolute section. */ + +static asection * +get_elf_r_symndx_section (abfd, r_symndx) + bfd *abfd; + unsigned long r_symndx; +{ + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + asection *target_sec = NULL; + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isymbuf; + unsigned int section_index; + + isymbuf = retrieve_local_syms (abfd); + section_index = isymbuf[r_symndx].st_shndx; + + if (section_index == SHN_UNDEF) + target_sec = bfd_und_section_ptr; + else if (section_index > 0 && section_index < SHN_LORESERVE) + target_sec = bfd_section_from_elf_index (abfd, section_index); + else if (section_index == SHN_ABS) + target_sec = bfd_abs_section_ptr; + else if (section_index == SHN_COMMON) + target_sec = bfd_com_section_ptr; + else + /* Who knows? */ + target_sec = NULL; + } + else + { + unsigned long indx = r_symndx - symtab_hdr->sh_info; + struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + target_sec = h->root.u.def.section; + break; + case bfd_link_hash_common: + target_sec = bfd_com_section_ptr; + break; + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + target_sec = bfd_und_section_ptr; + break; + default: /* New indirect warning. */ + target_sec = bfd_und_section_ptr; + break; + } + } + return target_sec; +} + + +static struct elf_link_hash_entry * +get_elf_r_symndx_hash_entry (abfd, r_symndx) + bfd *abfd; + unsigned long r_symndx; +{ + unsigned long indx; + struct elf_link_hash_entry *h; + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + if (r_symndx < symtab_hdr->sh_info) + return NULL; + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + return h; +} + + +/* Get the section-relative offset for a symbol number. */ + +static bfd_vma +get_elf_r_symndx_offset (abfd, r_symndx) + bfd *abfd; + unsigned long r_symndx; +{ + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + bfd_vma offset = 0; + + if (r_symndx < symtab_hdr->sh_info) + { + Elf_Internal_Sym *isymbuf; + isymbuf = retrieve_local_syms (abfd); + offset = isymbuf[r_symndx].st_value; + } + else + { + unsigned long indx = r_symndx - symtab_hdr->sh_info; + struct elf_link_hash_entry *h = + elf_sym_hashes (abfd)[indx]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + offset = h->root.u.def.value; + } + return offset; +} + + +static bfd_boolean +pcrel_reloc_fits (opnd, self_address, dest_address) + xtensa_operand opnd; + bfd_vma self_address; + bfd_vma dest_address; +{ + uint32 new_address = + xtensa_operand_do_reloc (opnd, dest_address, self_address); + return (xtensa_operand_encode (opnd, &new_address) + == xtensa_encode_result_ok); +} + + +static bfd_boolean +xtensa_is_property_section (sec) + asection *sec; +{ + static int len = sizeof (".gnu.linkonce.t.") - 1; + + return (strcmp (".xt.insn", sec->name) == 0 + || strcmp (".xt.lit", sec->name) == 0 + || strncmp (".gnu.linkonce.x.", sec->name, len) == 0 + || strncmp (".gnu.linkonce.p.", sec->name, len) == 0); +} + + +static bfd_boolean +is_literal_section (sec) + asection *sec; +{ + /* FIXME: the current definition of this leaves a lot to be desired.... */ + if (sec == NULL || sec->name == NULL) + return FALSE; + return (strstr (sec->name, "literal") != NULL); +} + + +static int +internal_reloc_compare (ap, bp) + const PTR ap; + const PTR bp; +{ + const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap; + const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp; + + return (a->r_offset - b->r_offset); +} + + +static bfd_boolean +get_is_linkonce_section (abfd, sec) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; +{ + flagword flags, link_once_flags; + bfd_boolean is_linkonce = FALSE;; + + flags = bfd_get_section_flags (abfd, sec); + link_once_flags = (flags & SEC_LINK_ONCE); + if (link_once_flags != 0) + is_linkonce = TRUE; + + /* In order for this to be useful to the assembler + before the linkonce flag is set we need to + check for the GNU extension name. */ + if (!is_linkonce && + strncmp (sec->name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0) + is_linkonce = TRUE; + + return is_linkonce; +} + + +char * +xtensa_get_property_section_name (abfd, sec, base_name) + bfd *abfd; + asection *sec; + const char * base_name; +{ + char *table_sec_name = NULL; + bfd_boolean is_linkonce; + + is_linkonce = get_is_linkonce_section (abfd, sec); + + if (!is_linkonce) + { + table_sec_name = strdup (base_name); + } + else + { + static size_t prefix_len = sizeof (".gnu.linkonce.t.") - 1; + size_t len = strlen (sec->name) + 1; + char repl_char = '\0'; + const char *segname = sec->name; + + if (strncmp (segname, ".gnu.linkonce.t.", prefix_len) == 0) + { + if (strcmp (base_name, ".xt.insn") == 0) + repl_char = 'x'; + else if (strcmp (base_name, ".xt.lit") == 0) + repl_char = 'p'; + } + + if (repl_char != '\0') + { + char *name = (char *) bfd_malloc (len); + memcpy (name, sec->name, len); + name[prefix_len - 2] = repl_char; + table_sec_name = name; + } + else + { + size_t base_len = strlen (base_name) + 1; + char *name = (char *) bfd_malloc (len + base_len); + memcpy (name, sec->name, len - 1); + memcpy (name + len - 1, base_name, base_len); + table_sec_name = name; + } + } + + return table_sec_name; +} + + +/* Other functions called directly by the linker. */ + +bfd_boolean +xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + deps_callback_t callback; + PTR closure; +{ + Elf_Internal_Rela *internal_relocs; + bfd_byte *contents; + unsigned i; + bfd_boolean ok = TRUE; + + /* ".plt*" sections have no explicit relocations but they contain L32R + instructions that reference the corresponding ".got.plt*" sections. */ + if ((sec->flags & SEC_LINKER_CREATED) != 0 + && strncmp (sec->name, ".plt", 4) == 0) + { + asection *sgotplt; + + /* Find the corresponding ".got.plt*" section. */ + if (sec->name[4] == '\0') + sgotplt = bfd_get_section_by_name (sec->owner, ".got.plt"); + else + { + char got_name[14]; + int chunk = 0; + + BFD_ASSERT (sec->name[4] == '.'); + chunk = strtol (&sec->name[5], NULL, 10); + + sprintf (got_name, ".got.plt.%u", chunk); + sgotplt = bfd_get_section_by_name (sec->owner, got_name); + } + BFD_ASSERT (sgotplt); + + /* Assume worst-case offsets: L32R at the very end of the ".plt" + section referencing a literal at the very beginning of + ".got.plt". This is very close to the real dependence, anyway. */ + (*callback) (sec, sec->_raw_size, sgotplt, 0, closure); + } + + internal_relocs = retrieve_internal_relocs (abfd, sec, + link_info->keep_memory); + if (internal_relocs == NULL + || sec->reloc_count == 0) + return ok; + + /* Cache the contents for the duration of this scan. */ + contents = retrieve_contents (abfd, sec, link_info->keep_memory); + if (contents == NULL && sec->_raw_size != 0) + { + ok = FALSE; + goto error_return; + } + + if (xtensa_default_isa == NULL) + xtensa_isa_init (); + + for (i = 0; i < sec->reloc_count; i++) + { + Elf_Internal_Rela *irel = &internal_relocs[i]; + if (is_l32r_relocation (sec, contents, irel)) + { + r_reloc l32r_rel; + asection *target_sec; + bfd_vma target_offset; + + r_reloc_init (&l32r_rel, abfd, irel); + target_sec = NULL; + target_offset = 0; + /* L32Rs must be local to the input file. */ + if (r_reloc_is_defined (&l32r_rel)) + { + target_sec = r_reloc_get_section (&l32r_rel); + target_offset = r_reloc_get_target_offset (&l32r_rel); + } + (*callback) (sec, irel->r_offset, target_sec, target_offset, + closure); + } + } + + error_return: + release_internal_relocs (sec, internal_relocs); + release_contents (sec, contents); + return ok; +} + + +#ifndef ELF_ARCH +#define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec +#define TARGET_LITTLE_NAME "elf32-xtensa-le" +#define TARGET_BIG_SYM bfd_elf32_xtensa_be_vec +#define TARGET_BIG_NAME "elf32-xtensa-be" +#define ELF_ARCH bfd_arch_xtensa + +/* The new EM_XTENSA value will be recognized beginning in the Xtensa T1040 + release. However, we still have to generate files with the EM_XTENSA_OLD + value so that pre-T1040 tools can read the files. As soon as we stop + caring about pre-T1040 tools, the following two values should be + swapped. At the same time, any other code that uses EM_XTENSA_OLD + (e.g., prep_headers() in elf.c) should be changed to use EM_XTENSA. */ +#define ELF_MACHINE_CODE EM_XTENSA_OLD +#define ELF_MACHINE_ALT1 EM_XTENSA + +#if XCHAL_HAVE_MMU +#define ELF_MAXPAGESIZE (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE) +#else /* !XCHAL_HAVE_MMU */ +#define ELF_MAXPAGESIZE 1 +#endif /* !XCHAL_HAVE_MMU */ +#endif /* ELF_ARCH */ + +#define elf_backend_can_gc_sections 1 +#define elf_backend_can_refcount 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_got_header_size 4 +#define elf_backend_want_dynbss 0 +#define elf_backend_want_got_plt 1 + +#define elf_info_to_howto elf_xtensa_info_to_howto_rela + +#define bfd_elf32_bfd_final_link bfd_elf32_bfd_final_link +#define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data +#define bfd_elf32_new_section_hook elf_xtensa_new_section_hook +#define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data +#define bfd_elf32_bfd_relax_section elf_xtensa_relax_section +#define bfd_elf32_bfd_reloc_type_lookup elf_xtensa_reloc_type_lookup +#define bfd_elf32_bfd_set_private_flags elf_xtensa_set_private_flags + +#define elf_backend_adjust_dynamic_symbol elf_xtensa_adjust_dynamic_symbol +#define elf_backend_check_relocs elf_xtensa_check_relocs +#define elf_backend_copy_indirect_symbol elf_xtensa_copy_indirect_symbol +#define elf_backend_create_dynamic_sections elf_xtensa_create_dynamic_sections +#define elf_backend_discard_info elf_xtensa_discard_info +#define elf_backend_ignore_discarded_relocs elf_xtensa_ignore_discarded_relocs +#define elf_backend_final_write_processing elf_xtensa_final_write_processing +#define elf_backend_finish_dynamic_sections elf_xtensa_finish_dynamic_sections +#define elf_backend_finish_dynamic_symbol elf_xtensa_finish_dynamic_symbol +#define elf_backend_gc_mark_hook elf_xtensa_gc_mark_hook +#define elf_backend_gc_sweep_hook elf_xtensa_gc_sweep_hook +#define elf_backend_grok_prstatus elf_xtensa_grok_prstatus +#define elf_backend_grok_psinfo elf_xtensa_grok_psinfo +#define elf_backend_hide_symbol elf_xtensa_hide_symbol +#define elf_backend_modify_segment_map elf_xtensa_modify_segment_map +#define elf_backend_object_p elf_xtensa_object_p +#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class +#define elf_backend_relocate_section elf_xtensa_relocate_section +#define elf_backend_size_dynamic_sections elf_xtensa_size_dynamic_sections + +#include "elf32-target.h" diff --git a/bfd/po/zh_CN.po b/bfd/po/zh_CN.po new file mode 100644 index 0000000..a7ca6d7 --- /dev/null +++ b/bfd/po/zh_CN.po @@ -0,0 +1,2702 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2003 Free Software Foundation, Inc. +# Wang Li , 2003. +# +msgid "" +msgstr "" +"Project-Id-Version: bfd 2.12.91\n" +"POT-Creation-Date: 2002-07-23 15:55-0400\n" +"PO-Revision-Date: 2003-03-11 09:46+0800\n" +"Last-Translator: Wang Li \n" +"Language-Team: Chinese (simplified) \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=gb2312\n" +"Content-Transfer-Encoding: 8bit\n" + +#: aout-adobe.c:197 +#, c-format +msgid "%s: Unknown section type in a.out.adobe file: %x\n" +msgstr "%s£ºa.out.adobe ÎļþÖнڵÄÀàÐÍδ֪£º%x\n" + +#: aout-cris.c:208 +#, c-format +msgid "%s: Invalid relocation type exported: %d" +msgstr "%s£ºµ¼³öÎÞЧµÄÖض¨Î»ÀàÐÍ£º%d" + +#: aout-cris.c:252 +#, c-format +msgid "%s: Invalid relocation type imported: %d" +msgstr "%s£ºµ¼ÈëÎÞЧµÄÖض¨Î»ÀàÐÍ£º%d" + +#: aout-cris.c:263 +#, c-format +msgid "%s: Bad relocation record imported: %d" +msgstr "%s£ºµ¼Èë´íÎóµÄÖض¨Î»¼Ç¼£º%d" + +#: aoutx.h:1282 aoutx.h:1699 +#, c-format +msgid "%s: can not represent section `%s' in a.out object file format" +msgstr "%s£ºÎÞ·¨ÔÚ a.out ¶ÔÏóÎļþ¸ñʽÖбíʾ½Ú¡°%s¡±" + +#: aoutx.h:1669 +#, c-format +msgid "%s: can not represent section for symbol `%s' in a.out object file format" +msgstr "%s£ºÎÞ·¨ÔÚ a.out ¶ÔÏóÎļþ¸ñʽÖÐΪ·ûºÅ¡°%s¡±±íʾ½Ú" + +#: aoutx.h:1671 +msgid "*unknown*" +msgstr "*δ֪*" + +#: aoutx.h:3732 +#, c-format +msgid "%s: relocateable link from %s to %s not supported" +msgstr "%s£º²»Ö§³Ö´Ó %s µ½ %s µÄ¿ÉÖض¨Î»µÄÁ¬½Ó" + +#: archive.c:1826 +msgid "Warning: writing archive was slow: rewriting timestamp\n" +msgstr "¾¯¸æ£ºÐ´Èë¹éµµ¹ýÂý£ºÖØÐÂдÈëʱ¼ä´Á\n" + +#: archive.c:2093 +msgid "Reading archive file mod timestamp" +msgstr "ÕýÔÚ¶ÁÈëÎļþÐÞ¸Äʱ¼ä´Á" + +#. FIXME: bfd can't call perror. +#: archive.c:2120 +msgid "Writing updated armap timestamp" +msgstr "ÕýÔÚ¸üРarmap ʱ¼ä´Á" + +#: bfd.c:274 +msgid "No error" +msgstr "ÎÞ´íÎó" + +#: bfd.c:275 +msgid "System call error" +msgstr "ϵͳµ÷ÓôíÎó" + +#: bfd.c:276 +msgid "Invalid bfd target" +msgstr "ÎÞЧµÄ bfd Ä¿±ê" + +#: bfd.c:277 +msgid "File in wrong format" +msgstr "Îļþ¸ñʽ´íÎó" + +#: bfd.c:278 +msgid "Archive object file in wrong format" +msgstr "¹éµµÄ¿±êÎļþ¸ñʽ´íÎó" + +#: bfd.c:279 +msgid "Invalid operation" +msgstr "ÎÞЧµÄ²Ù×÷" + +#: bfd.c:280 +msgid "Memory exhausted" +msgstr "ÄÚ´æºÄ¾¡" + +#: bfd.c:281 +msgid "No symbols" +msgstr "ÎÞ·ûºÅ" + +#: bfd.c:282 +msgid "Archive has no index; run ranlib to add one" +msgstr "¹éµµÃ»ÓÐË÷Òý£»ÔËÐÐ ranlib ÒÔÌí¼ÓÒ»¸ö" + +#: bfd.c:283 +msgid "No more archived files" +msgstr "ûÓиü¶àµÄ¹éµµÎļþ" + +#: bfd.c:284 +msgid "Malformed archive" +msgstr "»ûÐεĹ鵵" + +#: bfd.c:285 +msgid "File format not recognized" +msgstr "²»¿Éʶ±ðµÄÎļþ¸ñʽ" + +#: bfd.c:286 +msgid "File format is ambiguous" +msgstr "¶þÒåÐÔµÄÎļþ¸ñʽ" + +#: bfd.c:287 +msgid "Section has no contents" +msgstr "½ÚûÓÐÄÚÈÝ" + +#: bfd.c:288 +msgid "Nonrepresentable section on output" +msgstr "Êä³ö²»¿É±íʾµÄ½Ú" + +#: bfd.c:289 +msgid "Symbol needs debug section which does not exist" +msgstr "·ûºÅÐèÒª²»´æÔڵĵ÷ÊÔ½Ú" + +#: bfd.c:290 +msgid "Bad value" +msgstr "´íÎóµÄÖµ" + +#: bfd.c:291 +msgid "File truncated" +msgstr "Îļþ±»½Ø¶Ï" + +#: bfd.c:292 +msgid "File too big" +msgstr "Îļþ¹ý´ó" + +#: bfd.c:293 +msgid "#" +msgstr "#<ÎÞЧµÄ´íÎóÂë>" + +#: bfd.c:700 +#, c-format +msgid "BFD %s assertion fail %s:%d" +msgstr "BFD %s ¶ÏÑÔʧ°Ü %s£º%d" + +#: bfd.c:719 +#, c-format +msgid "BFD %s internal error, aborting at %s line %d in %s\n" +msgstr "BFD %1$s ÄÚ²¿´íÎó£¬Òì³£ÖÐÖ¹ÓÚ %4$s µÄ %3$d ÐÐµÄ %2$s\n" + +#: bfd.c:723 +#, c-format +msgid "BFD %s internal error, aborting at %s line %d\n" +msgstr "BFD %1$s ÄÚ²¿´íÎó£¬Òì³£ÖÐÖ¹ÓÚ %3$d ÐÐµÄ %2$s\n" + +#: bfd.c:725 +msgid "Please report this bug.\n" +msgstr "Ç뱨¸æ¸Ã BUG¡£\n" + +#: binary.c:306 +#, c-format +msgid "Warning: Writing section `%s' to huge (ie negative) file offset 0x%lx." +msgstr "¾¯¸æ£º½«½Ú¡°%s¡±Ð´Èë¹ý´ó(ÀýÈ縺Êý)ÎļþÆ«ÒÆÁ¿µÄλÖà 0x%lx¡£" + +#: coff-a29k.c:119 +msgid "Missing IHCONST" +msgstr "ÒÅʧ IHCONST" + +#: coff-a29k.c:180 +msgid "Missing IHIHALF" +msgstr "ÒÅʧ IHIHALF" + +#: coff-a29k.c:212 coff-or32.c:229 +msgid "Unrecognized reloc" +msgstr "ÎÞ·¨Ê¶±ðµÄÖض¨Î»" + +#: coff-a29k.c:408 +msgid "missing IHCONST reloc" +msgstr "ÒÅʧ IHCONST Öض¨Î»" + +#: coff-a29k.c:498 +msgid "missing IHIHALF reloc" +msgstr "ÒÅʧ IHIHALF Öض¨Î»" + +#: coff-alpha.c:881 coff-alpha.c:918 coff-alpha.c:1989 coff-mips.c:1432 +msgid "GP relative relocation used when GP not defined" +msgstr "ÔÚ GP 䶨ÒåµÄÇé¿öÏÂʹÓÃÁË GP Ïà¶ÔÖض¨Î»" + +#: coff-alpha.c:1485 +msgid "using multiple gp values" +msgstr "ʹÓÃÁ˶à¸ö GP Öµ" + +#: coff-arm.c:1066 elf32-arm.h:285 +#, c-format +msgid "%s: unable to find THUMB glue '%s' for `%s'" +msgstr "" + +#: coff-arm.c:1096 elf32-arm.h:320 +#, c-format +msgid "%s: unable to find ARM glue '%s' for `%s'" +msgstr "" + +#: coff-arm.c:1391 coff-arm.c:1486 elf32-arm.h:887 elf32-arm.h:991 +#, c-format +msgid "%s(%s): warning: interworking not enabled." +msgstr "" + +#: coff-arm.c:1395 elf32-arm.h:994 +#, c-format +msgid " first occurrence: %s: arm call to thumb" +msgstr "" + +#: coff-arm.c:1490 elf32-arm.h:890 +#, c-format +msgid " first occurrence: %s: thumb call to arm" +msgstr "" + +#: coff-arm.c:1493 +msgid " consider relinking with --support-old-code enabled" +msgstr " ³¢ÊÔÆôÓà --support-old-code ÖØÐÂÁ¬½Ó" + +#: coff-arm.c:1785 coff-tic80.c:686 cofflink.c:3031 +#, c-format +msgid "%s: bad reloc address 0x%lx in section `%s'" +msgstr "" + +#: coff-arm.c:2127 +#, c-format +msgid "%s: illegal symbol index in reloc: %d" +msgstr "%s£ºÖض¨Î»ÖзǷ¨µÄ·ûºÅË÷Òý£º%d" + +#: coff-arm.c:2255 +#, c-format +msgid "ERROR: %s is compiled for APCS-%d, whereas %s is compiled for APCS-%d" +msgstr "´íÎó£º%s ÊÇΪ APCS-%d ±àÒëµÄ£¬¶ø %s ÊÇΪ APCS-%d ±àÒëµÄ" + +#: coff-arm.c:2270 elf32-arm.h:2297 +#, c-format +msgid "ERROR: %s passes floats in float registers, whereas %s passes them in integer registers" +msgstr "´íÎó£º%s ÔÚ¸¡µã¼Ä´æÆ÷Öд«µÝ¸¡µãÊý£¬¶ø %s ÔÚÕûÊý¼Ä´æÆ÷Öд«µÝËüÃÇ" + +#: coff-arm.c:2273 elf32-arm.h:2302 +#, c-format +msgid "ERROR: %s passes floats in integer registers, whereas %s passes them in float registers" +msgstr "´íÎó£º%s ÔÚÕûÊý¼Ä´æÆ÷Öд«µÝ¸¡µãÊý£¬¶ø %s ÔÚ¸¡µãÊý¼Ä´æÆ÷Öд«µÝËüÃÇ" + +#: coff-arm.c:2288 +#, c-format +msgid "ERROR: %s is compiled as position independent code, whereas target %s is absolute position" +msgstr "´íÎó£º%s ±»±àÒëΪλÖÃÎ޹شúÂ룬¶øÄ¿±ê %s ²ÉÓþø¶ÔλÖÃ" + +#: coff-arm.c:2291 +#, c-format +msgid "ERROR: %s is compiled as absolute position code, whereas target %s is position independent" +msgstr "´íÎó£º%s ±»±àÒëΪ¾ø¶ÔλÖôúÂ룬¶øÄ¿±ê %s ÊÇλÖÃÎ޹صÄ" + +#: coff-arm.c:2320 elf32-arm.h:2358 +#, c-format +msgid "Warning: %s supports interworking, whereas %s does not" +msgstr "¾¯¸æ£º%s Ö§³Ö»¥²Ù×÷£¬¶ø %s ²»Ö§³Ö" + +#: coff-arm.c:2323 elf32-arm.h:2365 +#, c-format +msgid "Warning: %s does not support interworking, whereas %s does" +msgstr "¾¯¸æ£º%s ²»Ö§³Ö»¥²Ù×÷£¬¶ø %s Ö§³Ö" + +#: coff-arm.c:2350 +#, c-format +msgid "private flags = %x:" +msgstr "˽ÓбêÖ¾ = %x£º" + +#: coff-arm.c:2358 elf32-arm.h:2418 +msgid " [floats passed in float registers]" +msgstr " [ÔÚ¸¡µã¼Ä´æÆ÷Öд«µÝ¸¡µãÊý]" + +#: coff-arm.c:2360 +msgid " [floats passed in integer registers]" +msgstr " [ÔÚÕûÊý¼Ä´æÆ÷Öд«µÝ¸¡µãÊý]" + +#: coff-arm.c:2363 elf32-arm.h:2421 +msgid " [position independent]" +msgstr " [λÖÃÎÞ¹Ø]" + +#: coff-arm.c:2365 +msgid " [absolute position]" +msgstr " [¾ø¶ÔλÖÃ]" + +#: coff-arm.c:2369 +msgid " [interworking flag not initialised]" +msgstr " [»¥²Ù×÷±ê־δ³õʼ»¯]" + +#: coff-arm.c:2371 +msgid " [interworking supported]" +msgstr " [Ö§³Ö»¥²Ù×÷]" + +#: coff-arm.c:2373 +msgid " [interworking not supported]" +msgstr " [²»Ö§³Ö»¥²Ù×÷]" + +#: coff-arm.c:2421 elf32-arm.h:2124 +#, c-format +msgid "Warning: Not setting interworking flag of %s since it has already been specified as non-interworking" +msgstr "¾¯¸æ£ºÓÉÓÚ %s ÒѾ­±»Ö¸¶¨Îª²»¿É»¥²Ù×÷µÄ£¬Òò¶øûÓÐÉ趨»¥²Ù×÷±êÖ¾" + +#: coff-arm.c:2425 elf32-arm.h:2128 +#, c-format +msgid "Warning: Clearing the interworking flag of %s due to outside request" +msgstr "¾¯¸æ£ºÕýÔÚ¸ù¾ÝÍâ½çÇëÇóÇå³ý %s µÄ»¥²Ù×÷±êÖ¾" + +#: coff-i960.c:136 coff-i960.c:485 +msgid "uncertain calling convention for non-COFF symbol" +msgstr "¹ØÓÚ·Ç-COFF ·ûºÅ²»È·¶¨µÄµ÷ÓÃÔ¼¶¨" + +#: coff-m68k.c:481 coff-mips.c:2429 elf32-m68k.c:2157 elf32-mips.c:1844 +msgid "unsupported reloc type" +msgstr "²»Ö§³ÖµÄÖض¨Î»ÀàÐÍ" + +#: coff-mips.c:874 elf32-mips.c:1062 elf64-mips.c:1609 +msgid "GP relative relocation when _gp not defined" +msgstr "" + +#. No other sections should appear in -membedded-pic +#. code. +#: coff-mips.c:2466 +msgid "reloc against unsupported section" +msgstr "¹ØÓÚ²»Ö§³Ö½ÚµÄÖض¨Î»" + +#: coff-mips.c:2474 +msgid "reloc not properly aligned" +msgstr "Öض¨Î»Ã»ÓÐÕýÈ·¶ÔÆë" + +#: coff-rs6000.c:2766 +#, c-format +msgid "%s: unsupported relocation type 0x%02x" +msgstr "%s£º²»Ö§³ÖµÄÖض¨Î»ÀàÐÍ 0x%02x" + +#: coff-rs6000.c:2859 +#, c-format +msgid "%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry" +msgstr "" + +#: coff-rs6000.c:3590 coff64-rs6000.c:2091 +#, c-format +msgid "%s: symbol `%s' has unrecognized smclas %d" +msgstr "" + +#: coff-tic54x.c:279 coff-tic80.c:449 +#, c-format +msgid "Unrecognized reloc type 0x%x" +msgstr "ÎÞ·¨Ê¶±ðµÄÖض¨Î»ÀàÐÍ 0x%x" + +#: coff-tic54x.c:390 coffcode.h:4974 +#, c-format +msgid "%s: warning: illegal symbol index %ld in relocs" +msgstr "%s£º¾¯¸æ£ºÖض¨Î»ÖзǷ¨µÄ·ûºÅË÷Òý %ld" + +#: coff-w65.c:363 +#, c-format +msgid "ignoring reloc %s\n" +msgstr "ÕýÔÚºöÂÔÖض¨Î» %s\n" + +#: coffcode.h:1086 +#, c-format +msgid "%s (%s): Section flag %s (0x%x) ignored" +msgstr "%s (%s)£ººöÂÔ½Ú±êÖ¾ %s (0x%x)" + +#: coffcode.h:2143 +#, c-format +msgid "Unrecognized TI COFF target id '0x%x'" +msgstr "ÎÞ·¨Ê¶±ðµÄ TI COFF Ä¿±ê id ¡°0x%x¡±" + +#: coffcode.h:4365 +#, c-format +msgid "%s: warning: illegal symbol index %ld in line numbers" +msgstr "%s£º¾¯¸æ£ºÐкÅÖеķǷ¨·ûºÅË÷Òý %ld" + +#: coffcode.h:4379 +#, c-format +msgid "%s: warning: duplicate line number information for `%s'" +msgstr "%s£º¾¯¸æ£ºÎª¡°%s¡±¸´ÖÆÐкÅÐÅÏ¢" + +#: coffcode.h:4736 +#, c-format +msgid "%s: Unrecognized storage class %d for %s symbol `%s'" +msgstr "" + +#: coffcode.h:4867 +#, c-format +msgid "warning: %s: local symbol `%s' has no section" +msgstr "¾¯¸æ£º%s£º±¾µØ·ûºÅ¡°%s¡±Ã»ÓнÚ" + +#: coffcode.h:5012 +#, c-format +msgid "%s: illegal relocation type %d at address 0x%lx" +msgstr "%1$s£ºÎ»ÓÚµØÖ· 0x%3$lx ´¦µÄ·Ç·¨Öض¨Î»ÀàÐÍ %2$d" + +#: coffgen.c:1661 +#, c-format +msgid "%s: bad string table size %lu" +msgstr "%s£º×Ö·û´®±íµÄ´óС´íÎó %lu" + +#: cofflink.c:534 elflink.h:1912 +#, c-format +msgid "Warning: type of symbol `%s' changed from %d to %d in %s" +msgstr "¾¯¸æ£º%4$s ÖеķûºÅ¡°%1$s¡±µÄÀàÐÍÓÉ %2$d ±äΪ %3$d" + +#: cofflink.c:2321 +#, c-format +msgid "%s: relocs in section `%s', but it has no contents" +msgstr "" + +#: cofflink.c:2664 coffswap.h:877 +#, c-format +msgid "%s: %s: reloc overflow: 0x%lx > 0xffff" +msgstr "%s£º%s£ºÖض¨Î»Òç³ö£º0x%lx > 0xffff" + +#: cofflink.c:2673 coffswap.h:864 +#, c-format +msgid "%s: warning: %s: line number overflow: 0x%lx > 0xffff" +msgstr "%s£º¾¯¸æ£º%s£ºÐкÅÒç³ö£º0x%lx > 0xffff" + +#: dwarf2.c:382 +msgid "Dwarf Error: Can't find .debug_str section." +msgstr "С´íÎó£ºÎÞ·¨ÕÒµ½ .debug_str ½Ú¡£" + +#: dwarf2.c:399 +#, c-format +msgid "Dwarf Error: DW_FORM_strp offset (%lu) greater than or equal to .debug_str size (%lu)." +msgstr "" + +#: dwarf2.c:543 +msgid "Dwarf Error: Can't find .debug_abbrev section." +msgstr "С´íÎó£ºÎÞ·¨ÕÒµ½ .debug_abbrev ½Ú¡£" + +#: dwarf2.c:560 +#, c-format +msgid "Dwarf Error: Abbrev offset (%lu) greater than or equal to .debug_abbrev size (%lu)." +msgstr "" + +#: dwarf2.c:757 +#, c-format +msgid "Dwarf Error: Invalid or unhandled FORM value: %u." +msgstr "С´íÎó£ºÎÞЧ»òδ´¦ÀíµÄ±íµ¥Öµ£º%u¡£" + +#: dwarf2.c:852 +msgid "Dwarf Error: mangled line number section (bad file number)." +msgstr "" + +#: dwarf2.c:938 +msgid "Dwarf Error: Can't find .debug_line section." +msgstr "С´íÎó£ºÎÞ·¨ÕÒµ½ .debug_line ½Ú¡£" + +#: dwarf2.c:961 +#, c-format +msgid "Dwarf Error: Line offset (%lu) greater than or equal to .debug_line size (%lu)." +msgstr "" + +#: dwarf2.c:1159 +msgid "Dwarf Error: mangled line number section." +msgstr "" + +#: dwarf2.c:1355 dwarf2.c:1566 +#, c-format +msgid "Dwarf Error: Could not find abbrev number %u." +msgstr "" + +#: dwarf2.c:1527 +#, c-format +msgid "Dwarf Error: found dwarf version '%u', this reader only handles version 2 information." +msgstr "" + +#: dwarf2.c:1534 +#, c-format +msgid "Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'." +msgstr "" + +#: dwarf2.c:1557 +#, c-format +msgid "Dwarf Error: Bad abbrev number: %u." +msgstr "С´íÎ󣺴íÎóµÄËõд±àºÅ£º%u¡£" + +#: ecoff.c:1318 +#, c-format +msgid "Unknown basic type %d" +msgstr "δ֪µÄ»ù±¾ÀàÐÍ %d" + +#: ecoff.c:1578 +#, c-format +msgid "" +"\n" +" End+1 symbol: %ld" +msgstr "" +"\n" +" End+1 ·ûºÅ£º%ld" + +#: ecoff.c:1585 ecoff.c:1588 +#, c-format +msgid "" +"\n" +" First symbol: %ld" +msgstr "" +"\n" +" µÚÒ»¸ö·ûºÅ£º%ld" + +#: ecoff.c:1600 +#, c-format +msgid "" +"\n" +" End+1 symbol: %-7ld Type: %s" +msgstr "" +"\n" +" End+1 ·ûºÅ£º%-7ld ÀàÐÍ£º%s" + +#: ecoff.c:1607 +#, c-format +msgid "" +"\n" +" Local symbol: %ld" +msgstr "" +"\n" +" ±¾µØ·ûºÅ£º%ld" + +#: ecoff.c:1615 +#, c-format +msgid "" +"\n" +" struct; End+1 symbol: %ld" +msgstr "" +"\n" +" ½á¹¹£»End+1 ·ûºÅ£º%ld" + +#: ecoff.c:1620 +#, c-format +msgid "" +"\n" +" union; End+1 symbol: %ld" +msgstr "" +"\n" +" ÁªºÏ£»End+1 ·ûºÅ£º%ld" + +#: ecoff.c:1625 +#, c-format +msgid "" +"\n" +" enum; End+1 symbol: %ld" +msgstr "" +"\n" +" ö¾Ù£»End+1 ·ûºÅ£º%ld" + +#: ecoff.c:1631 +#, c-format +msgid "" +"\n" +" Type: %s" +msgstr "" +"\n" +" ÀàÐÍ£º%s" + +#: elf-hppa.h:1476 elf-hppa.h:1509 elf32-ppc.c:3091 elf32-sh.c:4213 +#: elf64-sh64.c:1659 +#, c-format +msgid "%s: warning: unresolvable relocation against symbol `%s' from %s section" +msgstr "%1$s£º¾¯¸æ£ºÀ´×Ô %3$s ½ÚµÄ¹ØÓÚ·ûºÅ¡°%2$s¡±µÄ²»¿É½âÎöµÄÖض¨Î»" + +#: elf-m10200.c:446 elf-m10300.c:656 elf32-arm.h:2084 elf32-avr.c:833 +#: elf32-cris.c:1403 elf32-d10v.c:481 elf32-fr30.c:635 elf32-frv.c:809 +#: elf32-h8300.c:548 elf32-i860.c:1031 elf32-m32r.c:1278 elf32-openrisc.c:439 +#: elf32-v850.c:1691 elf32-xstormy16.c:933 elf64-mmix.c:1302 +msgid "internal error: out of range error" +msgstr "ÄÚ²¿´íÎ󣺳¬³ö·¶Î§´íÎó" + +#: elf-m10200.c:450 elf-m10300.c:660 elf32-arm.h:2088 elf32-avr.c:837 +#: elf32-cris.c:1407 elf32-d10v.c:485 elf32-fr30.c:639 elf32-frv.c:813 +#: elf32-h8300.c:552 elf32-i860.c:1035 elf32-m32r.c:1282 elf32-openrisc.c:443 +#: elf32-v850.c:1695 elf32-xstormy16.c:937 elf64-mmix.c:1306 elfxx-mips.c:5264 +msgid "internal error: unsupported relocation error" +msgstr "ÄÚ²¿´íÎ󣺲»Ö§³ÖµÄÖض¨Î»´íÎó" + +#: elf-m10200.c:454 elf-m10300.c:664 elf32-arm.h:2092 elf32-d10v.c:489 +#: elf32-h8300.c:556 elf32-m32r.c:1286 +msgid "internal error: dangerous error" +msgstr "ÄÚ²¿´íÎó£ºÎ£ÏյĴíÎó" + +#: elf-m10200.c:458 elf-m10300.c:668 elf32-arm.h:2096 elf32-avr.c:845 +#: elf32-cris.c:1415 elf32-d10v.c:493 elf32-fr30.c:647 elf32-frv.c:821 +#: elf32-h8300.c:560 elf32-i860.c:1043 elf32-m32r.c:1290 elf32-openrisc.c:451 +#: elf32-v850.c:1715 elf32-xstormy16.c:945 elf64-mmix.c:1314 +msgid "internal error: unknown error" +msgstr "ÄÚ²¿´íÎó£ºÎ´ÖªµÄ´íÎó" + +#: elf.c:343 +#, c-format +msgid "%s: invalid string offset %u >= %lu for section `%s'" +msgstr "" + +#: elf.c:589 +#, c-format +msgid "%s: invalid SHT_GROUP entry" +msgstr "%s£ºÎÞЧµÄ SHT_GROUP ÌõÄ¿" + +#: elf.c:660 +#, c-format +msgid "%s: no group info for section %s" +msgstr "%s£ºÃ»ÓйØÓÚ½Ú %s µÄ×éÐÅÏ¢" + +#: elf.c:1023 +msgid "" +"\n" +"Program Header:\n" +msgstr "" +"\n" +"³ÌÐòÍ·£º\n" + +#: elf.c:1073 +msgid "" +"\n" +"Dynamic Section:\n" +msgstr "" +"\n" +"¶¯Ì¬½Ú£º\n" + +#: elf.c:1202 +msgid "" +"\n" +"Version definitions:\n" +msgstr "" +"\n" +"°æ±¾¶¨Ò壺\n" + +#: elf.c:1225 +msgid "" +"\n" +"Version References:\n" +msgstr "" +"\n" +"°æ±¾ÒýÓãº\n" + +#: elf.c:1230 +#, c-format +msgid " required from %s:\n" +msgstr "" + +#: elf.c:1902 +#, c-format +msgid "%s: invalid link %lu for reloc section %s (index %u)" +msgstr "" + +#: elf.c:3603 +#, c-format +msgid "%s: Not enough room for program headers (allocated %u, need %u)" +msgstr "%s£ºÃ»ÓÐ×ã¹»µÄ¿Õ¼ä±£´æ³ÌÐòÍ·£¨·ÖÅä %u£¬ÐèÒª %u£©" + +#: elf.c:3708 +#, c-format +msgid "%s: Not enough room for program headers, try linking with -N" +msgstr "%s£ºÃ»ÓÐ×ã¹»µÄ¿Õ¼ä±£´æ³ÌÐòÍ·£¬ÊÔÓà -N ½øÐÐÁ¬½Ó" + +#: elf.c:3833 +#, c-format +msgid "Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x" +msgstr "´íÎ󣺶Π(%s) ÖеĵÚÒ»¸ö½Ú¿ªÊ¼ÓÚ 0x%x£¬È»¶ø¶Î¿ªÊ¼ÓÚ 0x%x" + +#: elf.c:4148 +#, c-format +msgid "%s: warning: allocated section `%s' not in segment" +msgstr "%s£º¾¯¸æ£ºÒÑ·ÖÅäµÄ½Ú¡°%s¡±²»ÔÚ¶ÎÖÐ" + +#: elf.c:4472 +#, c-format +msgid "%s: symbol `%s' required but not present" +msgstr "%s£º±ØÐèµÄ·ûºÅ¡°%s¡±²»´æÔÚ" + +#: elf.c:4749 +#, c-format +msgid "%s: warning: Empty loadable segment detected, is this intentional ?\n" +msgstr "%s£º¾¯¸æ£º·¢ÏֿյĿÉ×°Èë¶Î£¬ËüÊÇÄÚ²¿µÄ£¿\n" + +#: elf.c:6193 +#, c-format +msgid "%s: unsupported relocation type %s" +msgstr "%s£º²»Ö§³ÖµÄÖض¨Î»µÄÀàÐÍ %s" + +#: elf32-arm.h:1221 +#, c-format +msgid "%s: Warning: Arm BLX instruction targets Arm function '%s'." +msgstr "" + +#: elf32-arm.h:1417 +#, c-format +msgid "%s: Warning: Thumb BLX instruction targets thumb function '%s'." +msgstr "" + +#: elf32-arm.h:1914 elf32-sh.c:4125 +#, c-format +msgid "%s(%s+0x%lx): %s relocation against SEC_MERGE section" +msgstr "%s(%s+0x%lx)£º¹ØÓÚ SEC_MERGE ½ÚµÄÖض¨Î» %s" + +#: elf32-arm.h:2008 +#, c-format +msgid "%s: warning: unresolvable relocation %d against symbol `%s' from %s section" +msgstr "" + +#: elf32-arm.h:2176 +#, c-format +msgid "Warning: Clearing the interworking flag of %s because non-interworking code in %s has been linked with it" +msgstr "" + +#: elf32-arm.h:2271 +#, c-format +msgid "ERROR: %s is compiled for EABI version %d, whereas %s is compiled for version %d" +msgstr "´íÎó£º%s ÊÇΪ EABI °æ±¾ %d ±àÒëµÄ£¬¶ø %s ÔòÊÇΪ°æ±¾ %d ±àÒëµÄ" + +#: elf32-arm.h:2285 +#, c-format +msgid "ERROR: %s is compiled for APCS-%d, whereas target %s uses APCS-%d" +msgstr "´íÎó£º%s ÊÇΪ APCS-%d ±àÒëµÄ£¬¶øÄ¿±ê %s ʹÓà APCS-%d" + +#: elf32-arm.h:2313 +#, c-format +msgid "ERROR: %s uses VFP instructions, whereas %s uses FPA instructions" +msgstr "´íÎó£º%s ʹÓà VFP Ö¸Á¶ø %s ʹÓà FPA Ö¸Áî" + +#: elf32-arm.h:2318 +#, c-format +msgid "ERROR: %s uses FPA instructions, whereas %s uses VFP instructions" +msgstr "´íÎó£º%s ʹÓà FPA Ö¸Á¶ø %s ʹÓà VFP Ö¸Áî" + +#: elf32-arm.h:2338 +#, c-format +msgid "ERROR: %s uses software FP, whereas %s uses hardware FP" +msgstr "´íÎó£º%s ʹÓÃÈí¼þ FP£¬¶ø %s ʹÓÃÓ²¼þ FP" + +#: elf32-arm.h:2343 +#, c-format +msgid "ERROR: %s uses hardware FP, whereas %s uses software FP" +msgstr "´íÎó£º%s ʹÓÃÓ²¼þ FP£¬¶ø %s ʹÓÃÈí¼þ FP" + +#. Ignore init flag - it may not be set, despite the flags field +#. containing valid data. +#: elf32-arm.h:2396 elf32-cris.c:2988 elf32-m68k.c:410 elf32-vax.c:543 +#: elfxx-mips.c:7756 +#, c-format +msgid "private flags = %lx:" +msgstr "˽ÓбêÖ¾ = %lx£º" + +#: elf32-arm.h:2405 +msgid " [interworking enabled]" +msgstr " [ÆôÓû¥²Ù×÷]" + +#: elf32-arm.h:2413 +msgid " [VFP float format]" +msgstr " [VFP ¸¡µã¸ñʽ]" + +#: elf32-arm.h:2415 +msgid " [FPA float format]" +msgstr " [FPA ¸¡µã¸ñʽ]" + +#: elf32-arm.h:2424 +msgid " [new ABI]" +msgstr " [РABI]" + +#: elf32-arm.h:2427 +msgid " [old ABI]" +msgstr " [¾É ABI]" + +#: elf32-arm.h:2430 +msgid " [software FP]" +msgstr " [Èí¼þ FP]" + +#: elf32-arm.h:2438 +msgid " [Version1 EABI]" +msgstr " [°æ±¾1 EABI]" + +#: elf32-arm.h:2441 elf32-arm.h:2452 +msgid " [sorted symbol table]" +msgstr " [ÅÅÐò¹ýµÄ·ûºÅ±í]" + +#: elf32-arm.h:2443 elf32-arm.h:2454 +msgid " [unsorted symbol table]" +msgstr " [δÅÅÐòµÄ·ûºÅ±í]" + +#: elf32-arm.h:2449 +msgid " [Version2 EABI]" +msgstr " [°æ±¾2 EABI]" + +#: elf32-arm.h:2457 +msgid " [dynamic symbols use segment index]" +msgstr " [¶¯Ì¬·ûºÅʹÓöÎË÷Òý]" + +#: elf32-arm.h:2460 +msgid " [mapping symbols precede others]" +msgstr "" + +#: elf32-arm.h:2467 +msgid " " +msgstr " <²»¿Éʶ±ðµÄ EABI °æ±¾>" + +#: elf32-arm.h:2474 +msgid " [relocatable executable]" +msgstr " [¿ÉÖØж¨Î»µÄ¿ÉÖ´ÐгÌÐò]" + +#: elf32-arm.h:2477 +msgid " [has entry point]" +msgstr " [º¬ÓÐÈë¿Úµã]" + +#: elf32-arm.h:2482 +msgid "" +msgstr "<ÎÞ·¨Ê¶±ðµÄ±ê־λ¼¯ºÏ>" + +#: elf32-avr.c:841 elf32-cris.c:1411 elf32-fr30.c:643 elf32-frv.c:817 +#: elf32-i860.c:1039 elf32-openrisc.c:447 elf32-v850.c:1699 +#: elf32-xstormy16.c:941 elf64-mmix.c:1310 +msgid "internal error: dangerous relocation" +msgstr "ÄÚ²¿´íÎó£ºÎ£ÏÕµÄÖض¨Î»" + +#: elf32-cris.c:949 +#, c-format +msgid "%s: unresolvable relocation %s against symbol `%s' from %s section" +msgstr "%1$s£ºÀ´×Ô %4$s ½ÚµÄ¹ØÓÚ·ûºÅ¡°%3$s¡±µÄÎÞ·¨½âÎöµÄÖض¨Î» %2$s" + +#: elf32-cris.c:1012 +#, c-format +msgid "%s: No PLT nor GOT for relocation %s against symbol `%s' from %s section" +msgstr "" + +#: elf32-cris.c:1015 elf32-cris.c:1141 +msgid "[whose name is lost]" +msgstr "" + +#: elf32-cris.c:1130 +#, c-format +msgid "%s: relocation %s with non-zero addend %d against local symbol from %s section" +msgstr "" + +#: elf32-cris.c:1137 +#, c-format +msgid "%s: relocation %s with non-zero addend %d against symbol `%s' from %s section" +msgstr "" + +#: elf32-cris.c:1155 +#, c-format +msgid "%s: relocation %s is not allowed for global symbol: `%s' from %s section" +msgstr "" + +#: elf32-cris.c:1170 +#, c-format +msgid "%s: relocation %s in section %s with no GOT created" +msgstr "" + +#: elf32-cris.c:1288 +#, c-format +msgid "%s: Internal inconsistency; no relocation section %s" +msgstr "%s£ºÄÚ²¿²»Ò»Ö£»Ã»ÓÐÖض¨Î»½Ú %s" + +#: elf32-cris.c:2514 +#, c-format +msgid "" +"%s, section %s:\n" +" relocation %s should not be used in a shared object; recompile with -fPIC" +msgstr "" + +#: elf32-cris.c:2991 +msgid " [symbols have a _ prefix]" +msgstr " [·ûºÅÓиö _ ǰ׺]" + +#: elf32-cris.c:3030 +#, c-format +msgid "%s: uses _-prefixed symbols, but writing file with non-prefixed symbols" +msgstr "%s£ºÊ¹Óôø _ ǰ׺µÄ·ûºÅ£¬µ«ÒÔÎÞǰ׺·ûºÅдÈëÎļþ" + +#: elf32-cris.c:3031 +#, c-format +msgid "%s: uses non-prefixed symbols, but writing file with _-prefixed symbols" +msgstr "%s£ºÊ¹ÓÃÎÞǰ׺·ûºÅ£¬µ«ÒÔ´ø _ ǰ׺µÄ·ûºÅдÈëÎļþ" + +#: elf32-frv.c:1217 +#, c-format +msgid "%s: compiled with %s and linked with modules that use non-pic relocations" +msgstr "" + +#: elf32-frv.c:1267 +#, c-format +msgid "%s: compiled with %s and linked with modules compiled with %s" +msgstr "%s£ºÒÔ %s ±àÒ벢ͬÒÔ %s ±àÒëµÄÄ£¿éÁ¬½Ó" + +#: elf32-frv.c:1279 +#, c-format +msgid "%s: uses different unknown e_flags (0x%lx) fields than previous modules (0x%lx)" +msgstr "" + +#: elf32-frv.c:1315 +#, c-format +msgid "private flags = 0x%lx:" +msgstr "˽ÓбêÖ¾ = 0x%lx£º" + +#: elf32-gen.c:82 elf64-gen.c:82 +#, c-format +msgid "%s: Relocations in generic ELF (EM: %d)" +msgstr "" + +#: elf32-hppa.c:671 elf64-ppc.c:2323 +#, c-format +msgid "%s: cannot create stub entry %s" +msgstr "" + +#: elf32-hppa.c:956 elf32-hppa.c:3555 +#, c-format +msgid "%s(%s+0x%lx): cannot reach %s, recompile with -ffunction-sections" +msgstr "" + +#: elf32-hppa.c:1338 elf64-x86-64.c:673 +#, c-format +msgid "%s: relocation %s can not be used when making a shared object; recompile with -fPIC" +msgstr "" + +#: elf32-hppa.c:1358 +#, c-format +msgid "%s: relocation %s should not be used when making a shared object; recompile with -fPIC" +msgstr "" + +#: elf32-hppa.c:1551 +#, c-format +msgid "Could not find relocation section for %s" +msgstr "ÎÞ·¨Îª %s ÕÒµ½Öض¨Î»½Ú" + +#: elf32-hppa.c:2855 +#, c-format +msgid "%s: duplicate export stub %s" +msgstr "" + +#: elf32-hppa.c:3433 +#, c-format +msgid "%s(%s+0x%lx): fixing %s" +msgstr "%s(%s+0x%lx)£ºÕýÔÚÐÞ¸´ %s" + +#: elf32-hppa.c:4080 +#, c-format +msgid "%s(%s+0x%lx): cannot handle %s for %s" +msgstr "" + +#: elf32-hppa.c:4393 +msgid ".got section not immediately after .plt section" +msgstr ".got ½Ú²»Äܽô½ÓÔÚ .plt ½ÚÖ®ºó" + +#: elf32-i386.c:379 +#, c-format +msgid "%s: invalid relocation type %d" +msgstr "%s£ºÎÞЧµÄÖض¨Î»ÀàÐÍ %d" + +#: elf32-i386.c:876 elf32-s390.c:649 elf64-s390.c:595 elf64-x86-64.c:591 +#, c-format +msgid "%s: bad symbol index: %d" +msgstr "%s£º´íÎóµÄ·ûºÅË÷Òý£º%d" + +#: elf32-i386.c:948 +#, c-format +msgid "%s: `%s' accessed both as normal and thread local symbol" +msgstr "" + +#: elf32-i386.c:1072 elf32-s390.c:808 elf64-ppc.c:2827 elf64-s390.c:759 +#: elf64-x86-64.c:761 +#, c-format +msgid "%s: bad relocation section name `%s'" +msgstr "%s£º´íÎóµÄÖض¨Î»½ÚÃû³Æ¡°%s¡±" + +#: elf32-i386.c:1159 elf64-alpha.c:4768 +#, c-format +msgid "%s: TLS local exec code cannot be linked into shared objects" +msgstr "" + +#: elf32-i386.c:2747 elf32-s390.c:1981 elf32-sparc.c:1571 elf64-ppc.c:5918 +#: elf64-s390.c:1945 elf64-sparc.c:2578 elf64-x86-64.c:1948 +#, c-format +msgid "%s(%s+0x%lx): unresolvable relocation against symbol `%s'" +msgstr "" + +#: elf32-i386.c:2784 elf32-s390.c:2019 elf64-ppc.c:5977 elf64-s390.c:1983 +#: elf64-x86-64.c:1986 +#, c-format +msgid "%s(%s+0x%lx): reloc against `%s': error %d" +msgstr "" + +#: elf32-m32r.c:924 +msgid "SDA relocation when _SDA_BASE_ not defined" +msgstr "ÔÚ _SDA_BASE_ 䶨Òåʱ³öÏÖ SDA Öض¨Î»" + +#: elf32-ia64.c:3687 elf32-m32r.c:1013 elf32-ppc.c:2987 elf64-alpha.c:4185 +#: elf64-alpha.c:4313 elf64-ia64.c:3687 +#, c-format +msgid "%s: unknown relocation type %d" +msgstr "%s£ºÎ´ÖªµÄÖض¨Î»ÀàÐÍ %d" + +#: elf32-m32r.c:1221 +#, c-format +msgid "%s: The target (%s) of an %s relocation is in the wrong section (%s)" +msgstr "" + +#: elf32-m32r.c:1947 +#, c-format +msgid "%s: Instruction set mismatch with previous modules" +msgstr "" + +#: elf32-m32r.c:1970 +#, c-format +msgid "private flags = %lx" +msgstr "˽ÓбêÖ¾ = %lx" + +#: elf32-m32r.c:1975 +msgid ": m32r instructions" +msgstr "£ºm32r Ö¸Áî" + +#: elf32-m32r.c:1976 +msgid ": m32rx instructions" +msgstr "£ºm32rx Ö¸Áî" + +#: elf32-m68k.c:413 +msgid " [cpu32]" +msgstr " [cpu32]" + +#: elf32-m68k.c:416 +msgid " [m68000]" +msgstr " [m68000]" + +#: elf32-mcore.c:354 elf32-mcore.c:457 +#, c-format +msgid "%s: Relocation %s (%d) is not currently supported.\n" +msgstr "" + +#: elf32-mcore.c:442 +#, c-format +msgid "%s: Unknown relocation type %d\n" +msgstr "%s£ºÎ´ÖªµÄÖض¨Î»ÀàÐÍ %d\n" + +#: elf32-mips.c:1152 elf64-mips.c:1783 +msgid "32bits gp relative relocation occurs for an external symbol" +msgstr "" + +#: elf32-mips.c:1301 +#, c-format +msgid "Linking mips16 objects into %s format is not supported" +msgstr "½« mips16 Ä¿±êÎļþÁ¬½Óµ½ %s ¸ñʽÊDz»Ö§³ÖµÄ" + +#: elf32-ppc.c:1460 +#, c-format +msgid "%s: compiled with -mrelocatable and linked with modules compiled normally" +msgstr "" + +#: elf32-ppc.c:1468 +#, c-format +msgid "%s: compiled normally and linked with modules compiled with -mrelocatable" +msgstr "" + +#: elf32-ppc.c:1494 elf64-sparc.c:2989 elfxx-mips.c:7713 +#, c-format +msgid "%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)" +msgstr "" + +#: elf32-ppc.c:1592 +#, c-format +msgid "%s: Unknown special linker type %d" +msgstr "%s£ºÎ´ÖªµÄÌض¨Á¬½ÓÆ÷ÀàÐÍ %d" + +#: elf32-ppc.c:2273 elf32-ppc.c:2307 elf32-ppc.c:2342 +#, c-format +msgid "%s: relocation %s cannot be used when making a shared object" +msgstr "%s£º´´½¨¹²ÏíÄ¿±êÎļþʱ²»ÄÜʹÓÃÖض¨Î» %s" + +#: elf32-ppc.c:3126 elf64-ppc.c:5473 +#, c-format +msgid "%s: unknown relocation type %d for symbol %s" +msgstr "%1$s£º¹ØÓÚ·ûºÅ %3$s µÄδ֪Öض¨Î»ÀàÐÍ %2$d" + +#: elf32-ppc.c:3482 elf32-ppc.c:3503 elf32-ppc.c:3553 +#, c-format +msgid "%s: The target (%s) of a %s relocation is in the wrong output section (%s)" +msgstr "" + +#: elf32-ppc.c:3619 +#, c-format +msgid "%s: Relocation %s is not yet supported for symbol %s." +msgstr "%s£ºÉв»Ö§³Ö¹ØÓÚ·ûºÅ %s µÄÖض¨Î» %s¡£" + +#: elf32-sh.c:1964 +#, c-format +msgid "%s: 0x%lx: warning: bad R_SH_USES offset" +msgstr "%s£º0x%lx£º¾¯¸æ£º´íÎóµÄ R_SH_USES Æ«ÒÆÁ¿" + +#: elf32-sh.c:1976 +#, c-format +msgid "%s: 0x%lx: warning: R_SH_USES points to unrecognized insn 0x%x" +msgstr "%s£º0x%lx£º¾¯¸æ£ºR_SH_USES Ö¸ÏòÎÞ·¨Ê¶±ðµÄÖ¸Áî 0x%x" + +#: elf32-sh.c:1993 +#, c-format +msgid "%s: 0x%lx: warning: bad R_SH_USES load offset" +msgstr "%s£º0x%lx£º¾¯¸æ£º´íÎóµÄ R_SH_USES ×°ÈëÆ«ÒÆÁ¿" + +#: elf32-sh.c:2008 +#, c-format +msgid "%s: 0x%lx: warning: could not find expected reloc" +msgstr "%s£º0x%lx£º¾¯¸æ£ºÎÞ·¨ÕÒµ½Ô¤ÆÚµÄÖض¨Î»" + +#: elf32-sh.c:2036 +#, c-format +msgid "%s: 0x%lx: warning: symbol in unexpected section" +msgstr "%s£º0x%lx£º¾¯¸æ£ºÒâÍâ½ÚÖгöÏÖ·ûºÅ" + +#: elf32-sh.c:2153 +#, c-format +msgid "%s: 0x%lx: warning: could not find expected COUNT reloc" +msgstr "%s£º0x%lx£º¾¯¸æ£ºÎÞ·¨ÕÒµ½Ô¤ÆÚµÄ COUNT Öض¨Î»" + +#: elf32-sh.c:2162 +#, c-format +msgid "%s: 0x%lx: warning: bad count" +msgstr "%s£º0x%lx£º¾¯¸æ£º´íÎó¼ÆÊý" + +#: elf32-sh.c:2550 elf32-sh.c:2926 +#, c-format +msgid "%s: 0x%lx: fatal: reloc overflow while relaxing" +msgstr "" + +#: elf32-sh.c:4073 elf64-sh64.c:1576 +msgid "Unexpected STO_SH5_ISA32 on local symbol is not handled" +msgstr "" + +#: elf32-sh.c:4284 +#, c-format +msgid "%s: 0x%lx: fatal: unaligned branch target for relax-support relocation" +msgstr "" + +#: elf32-sh64.c:203 elf64-sh64.c:2364 +#, c-format +msgid "%s: compiled as 32-bit object and %s is 64-bit" +msgstr "%s£º±àÒëΪ 32-λĿ±êÎļþµ« %s ÊÇ 64-λµÄ" + +#: elf32-sh64.c:206 elf64-sh64.c:2367 +#, c-format +msgid "%s: compiled as 64-bit object and %s is 32-bit" +msgstr "%s£º±àÒëΪ 64-λĿ±êÎļþµ« %s ÊÇ 32-λµÄ" + +#: elf32-sh64.c:208 elf64-sh64.c:2369 +#, c-format +msgid "%s: object size does not match that of target %s" +msgstr "%s£ºÄ¿±êÎļþ´óСºÍÄ¿±ê %s ²»Æ¥Åä" + +#: elf32-sh64.c:440 elf64-sh64.c:2941 +#, c-format +msgid "%s: encountered datalabel symbol in input" +msgstr "%s£ºÔÚÊäÈëÖÐÓöµ½Êý¾Ý±êÇ©·ûºÅ" + +#: elf32-sh64.c:523 +msgid "PTB mismatch: a SHmedia address (bit 0 == 1)" +msgstr "PTB ²»Æ¥Å䣺SHmedia µØÖ· (λ 0 == 1)" + +#: elf32-sh64.c:526 +msgid "PTA mismatch: a SHcompact address (bit 0 == 0)" +msgstr "PTA ²»Æ¥Å䣺SHcompact µØÖ· (λ 0 == 0)" + +#: elf32-sh64.c:544 +#, c-format +msgid "%s: GAS error: unexpected PTB insn with R_SH_PT_16" +msgstr "%s£ºGAS ´íÎó£ºÒâÍâµÄ´øÓÐ R_SH_PT_16 µÄ PTB Ö¸Áî" + +#: elf32-sh64.c:593 elf64-sh64.c:1703 +#, c-format +msgid "%s: error: unaligned relocation type %d at %08x reloc %08x\n" +msgstr "" + +#: elf32-sh64.c:677 +#, c-format +msgid "%s: could not write out added .cranges entries" +msgstr "%s£ºÎÞ·¨Ð´³ö .cranges ÌõÄ¿" + +#: elf32-sh64.c:739 +#, c-format +msgid "%s: could not write out sorted .cranges entries" +msgstr "%s£ºÎÞ·¨Ð´³ö¾­ÅÅÐòµÄ .cranges ÌõÄ¿" + +#: elf32-sparc.c:1535 elf64-sparc.c:2224 +#, c-format +msgid "%s: probably compiled without -fPIC?" +msgstr "" + +#: elf32-sparc.c:2002 +#, c-format +msgid "%s: compiled for a 64 bit system and target is 32 bit" +msgstr "%s£ºÎª 64 λϵͳ±àÒ뵫Ŀ±êƽ̨ÊÇ 32 λµÄ" + +#: elf32-sparc.c:2016 +#, c-format +msgid "%s: linking little endian files with big endian files" +msgstr "%s£ºÁ¬½ÓС¶ËÎļþºÍ´ó¶ËÎļþ" + +#: elf32-v850.c:682 +#, c-format +msgid "Variable `%s' cannot occupy in multiple small data regions" +msgstr "±äÁ¿¡°%s¡±²»ÄÜÕ¼¾Ý¶à¸öСÊý¾ÝÇø" + +#: elf32-v850.c:685 +#, c-format +msgid "Variable `%s' can only be in one of the small, zero, and tiny data regions" +msgstr "±äÁ¿¡°%s¡±Ö»ÄܳöÏÖÔÚСÊý¾ÝÇø¡¢ÁãÊý¾ÝÇø¡¢Î¢Êý¾ÝÇøÖ®Ò»" + +#: elf32-v850.c:688 +#, c-format +msgid "Variable `%s' cannot be in both small and zero data regions simultaneously" +msgstr "±äÁ¿¡°%s¡±²»ÄÜͬʱ³öÏÖÔÚСÊý¾ÝÇøºÍÁãÊý¾ÝÇø" + +#: elf32-v850.c:691 +#, c-format +msgid "Variable `%s' cannot be in both small and tiny data regions simultaneously" +msgstr "±äÁ¿¡°%s¡±²»ÄÜͬʱ³öÏÖÔÚСÊý¾ÝÇøºÍ΢Êý¾ÝÇø" + +#: elf32-v850.c:694 +#, c-format +msgid "Variable `%s' cannot be in both zero and tiny data regions simultaneously" +msgstr "±äÁ¿¡°%s¡±²»ÄÜͬʱ³öÏÖÔÚÁãÊý¾ÝÇøºÍ΢Êý¾ÝÇø" + +#: elf32-v850.c:1072 +msgid "FAILED to find previous HI16 reloc\n" +msgstr "Ñ°ÕÒÉÏÒ»¸ö HI16 Öض¨Î»Ê§°Ü\n" + +#: elf32-v850.c:1703 +msgid "could not locate special linker symbol __gp" +msgstr "ÎÞ·¨¶¨Î»ÌØÊâÁ¬½ÓÆ÷·ûºÅ __gp" + +#: elf32-v850.c:1707 +msgid "could not locate special linker symbol __ep" +msgstr "ÎÞ·¨¶¨Î»ÌØÊâÁ¬½ÓÆ÷·ûºÅ __ep" + +#: elf32-v850.c:1711 +msgid "could not locate special linker symbol __ctbp" +msgstr "ÎÞ·¨¶¨Î»ÌØÊâÁª»úÆ÷·ûºÅ __ctbp" + +#: elf32-v850.c:1875 +#, c-format +msgid "%s: Architecture mismatch with previous modules" +msgstr "%s£ºÌåϵ½á¹¹Í¬Ç°Ò»¸öÄ£¿é²»Æ¥Åä" + +#: elf32-v850.c:1895 +#, c-format +msgid "private flags = %lx: " +msgstr "˽ÓбêÖ¾ = %lx£º" + +#: elf32-v850.c:1900 +msgid "v850 architecture" +msgstr "v850 Ìåϵ½á¹¹" + +#: elf32-v850.c:1901 +msgid "v850e architecture" +msgstr "v850e Ìåϵ½á¹¹" + +#: elf32-v850.c:1902 +msgid "v850ea architecture" +msgstr "v850ea Ìåϵ½á¹¹" + +#: elf32-vax.c:546 +msgid " [nonpic]" +msgstr "" + +#: elf32-vax.c:549 +msgid " [d-float]" +msgstr "" + +#: elf32-vax.c:552 +msgid " [g-float]" +msgstr "" + +#: elf32-vax.c:674 +#, c-format +msgid "%s: warning: GOT addend of %ld to `%s' does not match previous GOT addend of %ld" +msgstr "" + +#: elf32-vax.c:1679 +#, c-format +msgid "%s: warning: PLT addend of %d to `%s' from %s section ignored" +msgstr "" + +#: elf32-vax.c:1814 +#, c-format +msgid "%s: warning: %s relocation against symbol `%s' from %s section" +msgstr "" + +#: elf32-vax.c:1820 +#, c-format +msgid "%s: warning: %s relocation to 0x%x from %s section" +msgstr "" + +#: elf32-ia64.c:2280 elf32-xstormy16.c:414 elf64-ia64.c:2280 +msgid "non-zero addend in @fptr reloc" +msgstr "" + +#: elf64-alpha.c:1097 +msgid "GPDISP relocation did not find ldah and lda instructions" +msgstr "GPDISP Öض¨Î»ÎÞ·¨ÕÒµ½ ldah ºÍ lda Ö¸Áî" + +#: elf64-alpha.c:3675 +#, c-format +msgid "%s: .got subsegment exceeds 64K (size %d)" +msgstr "%s£º.got ×Ó½Ú³¬¹ýÁË 64K (´óС %d)" + +#: elf64-alpha.c:4498 elf64-alpha.c:4510 +#, c-format +msgid "%s: gp-relative relocation against dynamic symbol %s" +msgstr "" + +#: elf64-alpha.c:4536 elf64-alpha.c:4676 +#, c-format +msgid "%s: pc-relative relocation against dynamic symbol %s" +msgstr "" + +#: elf64-alpha.c:4564 +#, c-format +msgid "%s: change in gp: BRSGP %s" +msgstr "" + +#: elf64-alpha.c:4589 +msgid "" +msgstr "<δ֪>" + +#: elf64-alpha.c:4594 +#, c-format +msgid "%s: !samegp reloc against symbol without .prologue: %s" +msgstr "" + +#: elf64-alpha.c:4639 +#, c-format +msgid "%s: unhandled dynamic relocation against %s" +msgstr "%s£ºÎ´´¦ÀíµÄ¹ØÓÚ %s µÄ¶¯Ì¬Öض¨Î»" + +#: elf64-alpha.c:4752 +#, c-format +msgid "%s: dtp-relative relocation against dynamic symbol %s" +msgstr "" + +#: elf64-alpha.c:4775 +#, c-format +msgid "%s: tp-relative relocation against dynamic symbol %s" +msgstr "" + +#: elf64-hppa.c:2080 +#, c-format +msgid "stub entry for %s cannot load .plt, dp offset = %ld" +msgstr "" + +#: elf64-mmix.c:1002 +#, c-format +msgid "" +"%s: Internal inconsistency error for value for\n" +" linker-allocated global register: linked: 0x%lx%08lx != relaxed: 0x%lx%08lx\n" +msgstr "" + +#: elf64-mmix.c:1386 +#, c-format +msgid "%s: base-plus-offset relocation against register symbol: (unknown) in %s" +msgstr "" + +#: elf64-mmix.c:1391 +#, c-format +msgid "%s: base-plus-offset relocation against register symbol: %s in %s" +msgstr "" + +#: elf64-mmix.c:1435 +#, c-format +msgid "%s: register relocation against non-register symbol: (unknown) in %s" +msgstr "" + +#: elf64-mmix.c:1440 +#, c-format +msgid "%s: register relocation against non-register symbol: %s in %s" +msgstr "" + +#: elf64-mmix.c:1477 +#, c-format +msgid "%s: directive LOCAL valid only with a register or absolute value" +msgstr "%s£ºÖ¸Áî LOCAL Ö»¶Ô¼Ä´æÆ÷»ò¾ø¶ÔÖµÓÐЧ" + +#: elf64-mmix.c:1505 +#, c-format +msgid "%s: LOCAL directive: Register $%ld is not a local register. First global register is $%ld." +msgstr "%s£ºLOCAL Ö¸Á¼Ä´æÆ÷ $%ld ²»ÊDZ¾µØ¼Ä´æÆ÷¡£ µÚÒ»¸öÈ«¾Ö¼Ä´æÆ÷ÊÇ $%ld¡£" + +#: elf64-mmix.c:1965 +#, c-format +msgid "%s: Error: multiple definition of `%s'; start of %s is set in a earlier linked file\n" +msgstr "%s£º´íÎó£ºÖظ´¶¨Òå¡°%s¡±£»%s µÄÆðµãÔÚ´ËÇ°Á¬½ÓµÄÎļþÖÐÒÑÉ趨\n" + +#: elf64-mmix.c:2024 +msgid "Register section has contents\n" +msgstr "¼Ä´æÆ÷½ÚÓÐÄÚÈÝ\n" + +#: elf64-mmix.c:2186 +#, c-format +msgid "" +"Internal inconsistency: remaining %u != max %u.\n" +" Please report this bug." +msgstr "" +"ÄÚ²¿²»Ò»Ö£ºÊ£Óà %u != ×î´ó %u¡£\n" +" Ç뱨¸æ¸Ã bug¡£" + +#: elf64-ppc.c:1669 libbfd.c:1435 +#, c-format +msgid "%s: compiled for a big endian system and target is little endian" +msgstr "%s£ºÎª´ó¶Ëϵͳ±àÒ뵫Ŀ±êƽ̨ÊÇС¶ËµÄ" + +#: elf64-ppc.c:1671 libbfd.c:1437 +#, c-format +msgid "%s: compiled for a little endian system and target is big endian" +msgstr "%s£ºÎªÐ¡¶Ëϵͳ±àÒ뵫Ŀ±êƽ̨ÊÇ´ó¶ËµÄ" + +#: elf64-ppc.c:3610 +#, c-format +msgid "%s: unexpected reloc type %u in .opd section" +msgstr "%s£º.opd ½ÚÖÐÒâÍâµÄÖض¨Î»ÀàÐÍ %u" + +#: elf64-ppc.c:3630 +#, c-format +msgid "%s: .opd is not a regular array of opd entries" +msgstr "%s£º.opd ²»ÊÇ opd ÌõÄ¿µÄÆÕͨÊý×é" + +#: elf64-ppc.c:3672 +#, c-format +msgid "%s: undefined sym `%s' in .opd section" +msgstr "%s£º.opd ½ÚÖÐ䶨ÒåµÄ¡°%s¡±" + +#: elf64-ppc.c:4397 +#, c-format +msgid "can't find branch stub `%s'" +msgstr "" + +#: elf64-ppc.c:4436 elf64-ppc.c:4501 +#, c-format +msgid "linkage table error against `%s'" +msgstr "" + +#: elf64-ppc.c:4573 +#, c-format +msgid "can't build branch stub `%s'" +msgstr "" + +#: elf64-ppc.c:5179 +msgid "stubs don't match calculated size" +msgstr "" + +#: elf64-ppc.c:5828 +#, c-format +msgid "%s: Relocation %s is not supported for symbol %s." +msgstr "%s£ºÖض¨Î» %s ²»Ö§³Ö·ûºÅ %s¡£" + +#: elf64-ppc.c:5872 +#, c-format +msgid "%s: error: relocation %s not a multiple of 4" +msgstr "%s£º´íÎó£ºÖض¨Î» %s ²»ÊÇ 4 µÄ±¶Êý" + +#: elf64-sparc.c:1280 +#, c-format +msgid "%s: check_relocs: unhandled reloc type %d" +msgstr "%s£ºcheck_relocs£ºÎ´´¦ÀíµÄÖض¨Î»ÀàÐÍ %d" + +#: elf64-sparc.c:1317 +#, c-format +msgid "%s: Only registers %%g[2367] can be declared using STT_REGISTER" +msgstr "%s£ºÖ»ÓмĴæÆ÷ %%g[2367] ¿ÉÒÔÓà STT_REGISTER À´ÉùÃ÷" + +#: elf64-sparc.c:1337 +#, c-format +msgid "Register %%g%d used incompatibly: %s in %s, previously %s in %s" +msgstr "²»¼æÈݵØʹÓüĴæÆ÷ %%g%1$d£ºÔÚ %3$s ÖÐΪ %2$s£¬ÔÚÇ°ÃæµÄ %5$s ÖÐΪ %4$s" + +#: elf64-sparc.c:1360 +#, c-format +msgid "Symbol `%s' has differing types: REGISTER in %s, previously %s in %s" +msgstr "·ûºÅ¡°%1$s¡±µÄÀàÐͲ»Í¬£º%2$s ÖÐΪ¼Ä´æÆ÷£¬ÔÚÇ°ÃæµÄ %4$s ÖÐΪ %3$s" + +#: elf64-sparc.c:1406 +#, c-format +msgid "Symbol `%s' has differing types: %s in %s, previously REGISTER in %s" +msgstr "" + +#: elf64-sparc.c:2970 +#, c-format +msgid "%s: linking UltraSPARC specific with HAL specific code" +msgstr "" + +#: elfcode.h:1198 +#, c-format +msgid "%s: version count (%ld) does not match symbol count (%ld)" +msgstr "%s£º°æ±¾¼ÆÊý (%ld) ÎÞ·¨Æ¥Åä·ûºÅ¼ÆÊý (%ld)" + +#: elflink.c:440 +#, c-format +msgid "%s: Section %s is too large to add hole of %ld bytes" +msgstr "" + +#: elflink.h:1090 +#, c-format +msgid "%s: warning: unexpected redefinition of `%s'" +msgstr "%s£º¾¯¸æ£ºÒâÍâµÄÖØж¨Òå¡°%s¡±" + +#: elflink.h:1727 +#, c-format +msgid "%s: %s: invalid version %u (max %d)" +msgstr "%s£º%s£ºÎÞЧµÄ°æ±¾ %u (×î´ó %d)" + +#: elflink.h:1768 +#, c-format +msgid "%s: %s: invalid needed version %d" +msgstr "%s£º%s£ºÎÞЧµÄ±Ø±¸°æ±¾ %d" + +#: elflink.h:1890 +#, c-format +msgid "Warning: size of symbol `%s' changed from %lu to %lu in %s" +msgstr "¾¯¸æ£º%4$s ÖеķûºÅ¡°%1$s¡±µÄ´óСÓÉ %2$lu ±äΪ %3$lu" + +#: elflink.h:3174 +#, c-format +msgid "%s: .preinit_array section is not allowed in DSO" +msgstr "%s£ºDSO Öв»ÔÊÐí³öÏÖ .preinit_array ½Ú" + +#: elflink.h:4030 +#, c-format +msgid "warning: type and size of dynamic symbol `%s' are not defined" +msgstr "¾¯¸æ£º¶¯Ì¬·ûºÅ¡°%s¡±µÄÀàÐͺʹóС䶨Òå" + +#: elflink.h:4345 +#, c-format +msgid "%s: undefined versioned symbol name %s" +msgstr "%s£ºÎ´¶¨ÒåµÄÓа汾·ûºÅÃû %s" + +#: elflink.h:4611 elflink.h:4619 elflink.h:6508 elflink.h:7600 +msgid "Error: out of memory" +msgstr "´íÎó£ºÃ»ÓÐÄÚ´æ" + +#: elflink.h:4781 +msgid "Not enough memory to sort relocations" +msgstr "ûÓÐ×ã¹»µÄÄÚ´æ½øÐÐÖض¨Î»ÅÅÐò" + +#: elflink.h:5682 elflink.h:5725 +#, c-format +msgid "%s: could not find output section %s" +msgstr "%s£ºÎÞ·¨ÕÒµ½Êä³ö½Ú %s" + +#: elflink.h:5688 +#, c-format +msgid "warning: %s section has zero size" +msgstr "¾¯¸æ£º%s ½ÚµÄ´óСΪÁã" + +#: elflink.h:6275 +#, c-format +msgid "%s: could not find output section %s for input section %s" +msgstr "%1$s£ºÎÞ·¨ÎªÊäÈë½Ú %3$s ÕÒµ½Êä³ö½Ú %2$s" + +#: elflink.h:6486 +#, c-format +msgid "%s: relocation size mismatch in %s section %s" +msgstr "" + +#: elflink.h:6849 +msgid "warning: relocation against removed section; zeroing" +msgstr "¾¯¸æ£º¹ØÓÚÒÑɾ³ýµÄ½ÚµÄÖض¨Î»£»ÕýÔÚÇåÁã" + +#: elflink.h:6879 +msgid "warning: relocation against removed section" +msgstr "¾¯¸æ£º¹ØÓÚÒÑɾ³ýµÄ½ÚµÄÖض¨Î»" + +#: elflink.h:6892 +#, c-format +msgid "local symbols in discarded section %s" +msgstr "ÒѽûÓÃµÄ½Ú %s Öеı¾µØ·ûºÅ" + +#: elfxx-mips.c:734 +msgid "static procedure (no name)" +msgstr "¾²Ì¬¹ý³Ì (ÎÞÃû³Æ)" + +#: elfxx-mips.c:1601 +msgid "not enough GOT space for local GOT entries" +msgstr "ûÓÐ×ã¹»µÄ GOT ¿Õ¼äÓÃÓÚ GOT ÌõÄ¿" + +#: elfxx-mips.c:2750 +#, c-format +msgid "%s: %s+0x%lx: jump to stub routine which is not jal" +msgstr "" + +#: elfxx-mips.c:4270 +#, c-format +msgid "%s: Malformed reloc detected for section %s" +msgstr "" + +#: elfxx-mips.c:4348 +#, c-format +msgid "%s: CALL16 reloc at 0x%lx not against global symbol" +msgstr "" + +#: elfxx-mips.c:7301 +#, c-format +msgid "%s: illegal section name `%s'" +msgstr "%s£º·Ç·¨µÄ½ÚÃû¡°%s¡±" + +#: elfxx-mips.c:7615 +#, c-format +msgid "%s: linking PIC files with non-PIC files" +msgstr "%s£º½« PIC Îļþͬ·Ç-PIC ÎļþÁ¬½Ó" + +#: elfxx-mips.c:7625 +#, c-format +msgid "%s: linking abicalls files with non-abicalls files" +msgstr "" + +#: elfxx-mips.c:7654 +#, c-format +msgid "%s: ISA mismatch (-mips%d) with previous modules (-mips%d)" +msgstr "%s£ºISA (-mips%d) ͬǰÃæµÄÄ£¿é(-mips%d)²»Æ¥Åä" + +#: elfxx-mips.c:7676 +#, c-format +msgid "%s: ISA mismatch (%d) with previous modules (%d)" +msgstr "%s£ºISA (%d) ͬǰÃæµÄÄ£¿é (%d) ²»Æ¥Åä" + +#: elfxx-mips.c:7699 +#, c-format +msgid "%s: ABI mismatch: linking %s module with previous %s modules" +msgstr "%s£ºABI ²»Æ¥Å䣺ÕýÔÚ½«Ä£¿é %s ͬǰһ¸öÄ£¿é %s ½øÐÐÁ¬½Ó" + +#: elfxx-mips.c:7759 +msgid " [abi=O32]" +msgstr " [abi=O32]" + +#: elfxx-mips.c:7761 +msgid " [abi=O64]" +msgstr " [abi=O64]" + +#: elfxx-mips.c:7763 +msgid " [abi=EABI32]" +msgstr " [abi=EABI32]" + +#: elfxx-mips.c:7765 +msgid " [abi=EABI64]" +msgstr " [abi=EABI64]" + +#: elfxx-mips.c:7767 +msgid " [abi unknown]" +msgstr " [abi δ֪]" + +#: elfxx-mips.c:7769 +msgid " [abi=N32]" +msgstr " [abi=N32]" + +#: elfxx-mips.c:7771 +msgid " [abi=64]" +msgstr " [abi=64]" + +#: elfxx-mips.c:7773 +msgid " [no abi set]" +msgstr "" + +#: elfxx-mips.c:7776 +msgid " [mips1]" +msgstr " [mips1]" + +#: elfxx-mips.c:7778 +msgid " [mips2]" +msgstr " [mips2]" + +#: elfxx-mips.c:7780 +msgid " [mips3]" +msgstr " [mips3]" + +#: elfxx-mips.c:7782 +msgid " [mips4]" +msgstr " [mips4]" + +#: elfxx-mips.c:7784 +msgid " [mips5]" +msgstr " [mips5]" + +#: elfxx-mips.c:7786 +msgid " [mips32]" +msgstr " [mips32]" + +#: elfxx-mips.c:7788 +msgid " [mips64]" +msgstr " [mips64]" + +#: elfxx-mips.c:7790 +msgid " [unknown ISA]" +msgstr " [δ֪µÄ ISA]" + +#: elfxx-mips.c:7793 +msgid " [mdmx]" +msgstr " [mdmx]" + +#: elfxx-mips.c:7796 +msgid " [mips16]" +msgstr " [mips16]" + +#: elfxx-mips.c:7799 +msgid " [32bitmode]" +msgstr " [32λģʽ]" + +#: elfxx-mips.c:7801 +msgid " [not 32bitmode]" +msgstr " [·Ç 32λģʽ]" + +#: i386linux.c:458 m68klinux.c:462 sparclinux.c:459 +#, c-format +msgid "Output file requires shared library `%s'\n" +msgstr "Êä³öÎļþÐèÒª¹²Ïí¿â¡°%s¡±\n" + +#: i386linux.c:466 m68klinux.c:470 sparclinux.c:467 +#, c-format +msgid "Output file requires shared library `%s.so.%s'\n" +msgstr "Êä³öÎļþÐèÒª¹²Ïí¿â¡°%s.so.%s¡±\n" + +#: i386linux.c:655 i386linux.c:705 m68klinux.c:662 m68klinux.c:710 +#: sparclinux.c:657 sparclinux.c:707 +#, c-format +msgid "Symbol %s not defined for fixups\n" +msgstr "" + +#: i386linux.c:729 m68klinux.c:734 sparclinux.c:731 +msgid "Warning: fixup count mismatch\n" +msgstr "" + +#: ieee.c:235 +#, c-format +msgid "%s: string too long (%d chars, max 65535)" +msgstr "%s£º×Ö·û´®¹ý³¤ (%d ×Ö·û£¬×î´ó 65535)" + +#: ieee.c:365 +#, c-format +msgid "%s: unrecognized symbol `%s' flags 0x%x" +msgstr "%s£ºÎÞ·¨Ê¶±ðµÄ¡°%s¡±±êÖ¾ 0x%x" + +#: ieee.c:877 +#, c-format +msgid "%s: unimplemented ATI record %u for symbol %u" +msgstr "" + +#: ieee.c:902 +#, c-format +msgid "%s: unexpected ATN type %d in external part" +msgstr "" + +#: ieee.c:924 +#, c-format +msgid "%s: unexpected type after ATN" +msgstr "%s£ºATN Ö®ºó³öÏÖÒâÍâµÄÀàÐÍ" + +#: ihex.c:258 +#, c-format +msgid "%s:%d: unexpected character `%s' in Intel Hex file\n" +msgstr "%s£º%d£ºIntel Ê®Áù½øÖÆÎļþÖеÄÒâÍâ×Ö·û¡°%s\n" + +#: ihex.c:366 +#, c-format +msgid "%s:%u: bad checksum in Intel Hex file (expected %u, found %u)" +msgstr "%s£º%u£ºIntel Ê®Áù½øÖÆÎļþÖеÄУÑéºÍ´íÎó (ӦΪ %u¡¢ÊµÎª %u)" + +#: ihex.c:420 +#, c-format +msgid "%s:%u: bad extended address record length in Intel Hex file" +msgstr "" + +#: ihex.c:437 +#, c-format +msgid "%s:%u: bad extended start address length in Intel Hex file" +msgstr "" + +#: ihex.c:454 +#, c-format +msgid "%s:%u: bad extended linear address record length in Intel Hex file" +msgstr "" + +#: ihex.c:471 +#, c-format +msgid "%s:%u: bad extended linear start address length in Intel Hex file" +msgstr "" + +#: ihex.c:488 +#, c-format +msgid "%s:%u: unrecognized ihex type %u in Intel Hex file\n" +msgstr "" + +#: ihex.c:607 +#, c-format +msgid "%s: internal error in ihex_read_section" +msgstr "" + +#: ihex.c:642 +#, c-format +msgid "%s: bad section length in ihex_read_section" +msgstr "" + +#: ihex.c:860 +#, c-format +msgid "%s: address 0x%s out of range for Intel Hex file" +msgstr "" + +#: libbfd.c:492 +#, c-format +msgid "not mapping: data=%lx mapped=%d\n" +msgstr "" + +#: libbfd.c:495 +msgid "not mapping: env var not set\n" +msgstr "" + +#: libbfd.c:1466 +#, c-format +msgid "Deprecated %s called at %s line %d in %s\n" +msgstr "" + +#: libbfd.c:1469 +#, c-format +msgid "Deprecated %s called\n" +msgstr "" + +#: linker.c:1873 +#, c-format +msgid "%s: indirect symbol `%s' to `%s' is a loop" +msgstr "" + +#: linker.c:2776 +#, c-format +msgid "Attempt to do relocateable link with %s input and %s output" +msgstr "" + +#: merge.c:892 +#, c-format +msgid "%s: access beyond end of merged section (%ld + %ld)" +msgstr "" + +#: mmo.c:460 +#, c-format +msgid "%s: No core to allocate section name %s\n" +msgstr "" + +#: mmo.c:536 +#, c-format +msgid "%s: No core to allocate a symbol %d bytes long\n" +msgstr "" + +#: mmo.c:1245 +#, c-format +msgid "%s: invalid mmo file: initialization value for $255 is not `Main'\n" +msgstr "" + +#: mmo.c:1391 +#, c-format +msgid "%s: unsupported wide character sequence 0x%02X 0x%02X after symbol name starting with `%s'\n" +msgstr "" + +#: mmo.c:1633 +#, c-format +msgid "%s: invalid mmo file: unsupported lopcode `%d'\n" +msgstr "" + +#: mmo.c:1643 +#, c-format +msgid "%s: invalid mmo file: expected YZ = 1 got YZ = %d for lop_quote\n" +msgstr "" + +#: mmo.c:1679 +#, c-format +msgid "%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_loc\n" +msgstr "" + +#: mmo.c:1725 +#, c-format +msgid "%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_fixo\n" +msgstr "" + +#: mmo.c:1764 +#, c-format +msgid "%s: invalid mmo file: expected y = 0, got y = %d for lop_fixrx\n" +msgstr "" + +#: mmo.c:1773 +#, c-format +msgid "%s: invalid mmo file: expected z = 16 or z = 24, got z = %d for lop_fixrx\n" +msgstr "" + +#: mmo.c:1796 +#, c-format +msgid "%s: invalid mmo file: leading byte of operand word must be 0 or 1, got %d for lop_fixrx\n" +msgstr "" + +#: mmo.c:1819 +#, c-format +msgid "%s: cannot allocate file name for file number %d, %d bytes\n" +msgstr "" + +#: mmo.c:1839 +#, c-format +msgid "%s: invalid mmo file: file number %d `%s', was already entered as `%s'\n" +msgstr "" + +#: mmo.c:1852 +#, c-format +msgid "%s: invalid mmo file: file name for number %d was not specified before use\n" +msgstr "" + +#: mmo.c:1958 +#, c-format +msgid "%s: invalid mmo file: fields y and z of lop_stab non-zero, y: %d, z: %d\n" +msgstr "" + +#: mmo.c:1994 +#, c-format +msgid "%s: invalid mmo file: lop_end not last item in file\n" +msgstr "" + +#: mmo.c:2007 +#, c-format +msgid "%s: invalid mmo file: YZ of lop_end (%ld) not equal to the number of tetras to the preceding lop_stab (%ld)\n" +msgstr "" + +#: mmo.c:2670 +#, c-format +msgid "%s: invalid symbol table: duplicate symbol `%s'\n" +msgstr "" + +#: mmo.c:2921 +#, c-format +msgid "%s: Bad symbol definition: `Main' set to %s rather than the start address %s\n" +msgstr "" + +#: mmo.c:3011 +#, c-format +msgid "%s: warning: symbol table too large for mmo, larger than 65535 32-bit words: %d. Only `Main' will be emitted.\n" +msgstr "" + +#: mmo.c:3056 +#, c-format +msgid "%s: internal error, symbol table changed size from %d to %d words\n" +msgstr "" + +#: mmo.c:3111 +#, c-format +msgid "%s: internal error, internal register section %s had contents\n" +msgstr "" + +#: mmo.c:3163 +#, c-format +msgid "%s: no initialized registers; section length 0\n" +msgstr "" + +#: mmo.c:3169 +#, c-format +msgid "%s: too many initialized registers; section length %ld\n" +msgstr "" + +#: mmo.c:3174 +#, c-format +msgid "%s: invalid start address for initialized registers of length %ld: 0x%lx%08lx\n" +msgstr "" + +#: oasys.c:1029 +#, c-format +msgid "%s: can not represent section `%s' in oasys" +msgstr "" + +#: osf-core.c:132 +#, c-format +msgid "Unhandled OSF/1 core file section type %d\n" +msgstr "" + +#: pe-mips.c:658 +#, c-format +msgid "%s: `ld -r' not supported with PE MIPS objects\n" +msgstr "" + +#. OK, at this point the following variables are set up: +#. src = VMA of the memory we're fixing up +#. mem = pointer to memory we're fixing up +#. val = VMA of what we need to refer to +#. +#: pe-mips.c:794 +#, c-format +msgid "%s: unimplemented %s\n" +msgstr "%s£ºÎ´ÊµÏÖµÄ %s\n" + +#: pe-mips.c:820 +#, c-format +msgid "%s: jump too far away\n" +msgstr "%s£ºÌøת¹ýÔ¶\n" + +#: pe-mips.c:847 +#, c-format +msgid "%s: bad pair/reflo after refhi\n" +msgstr "" + +#. XXX code yet to be written. +#: peicode.h:785 +#, c-format +msgid "%s: Unhandled import type; %x" +msgstr "%s£ºÎ´´¦ÀíµÄµ¼ÈëÀàÐÍ£»%x" + +#: peicode.h:790 +#, c-format +msgid "%s: Unrecognised import type; %x" +msgstr "%s£ºÎ´Ê¶±ðµÄµ¼ÈëÀàÐÍ£»%x" + +#: peicode.h:804 +#, c-format +msgid "%s: Unrecognised import name type; %x" +msgstr "%s£ºÎ´Ê¶±ðµÄµ¼ÈëÃû×ÖÀàÐÍ£»%x" + +#: peicode.h:1162 +#, c-format +msgid "%s: Unrecognised machine type (0x%x) in Import Library Format archive" +msgstr "" + +#: peicode.h:1174 +#, c-format +msgid "%s: Recognised but unhandled machine type (0x%x) in Import Library Format archive" +msgstr "" + +#: peicode.h:1191 +#, c-format +msgid "%s: size field is zero in Import Library Format header" +msgstr "" + +#: peicode.h:1219 +#, c-format +msgid "%s: string not null terminated in ILF object file." +msgstr "" + +#: ppcboot.c:416 +msgid "" +"\n" +"ppcboot header:\n" +msgstr "" + +#: ppcboot.c:417 +#, c-format +msgid "Entry offset = 0x%.8lx (%ld)\n" +msgstr "ÌõÄ¿Æ«ÒÆÁ¿ = 0x%.8lx (%ld)\n" + +#: ppcboot.c:418 +#, c-format +msgid "Length = 0x%.8lx (%ld)\n" +msgstr "³¤¶È = 0x%.8lx (%ld)\n" + +#: ppcboot.c:421 +#, c-format +msgid "Flag field = 0x%.2x\n" +msgstr "±êÖ¾Óò = 0x%.2x\n" + +#: ppcboot.c:427 +#, c-format +msgid "Partition name = \"%s\"\n" +msgstr "·ÖÇøÃû = \"%s\"\n" + +#: ppcboot.c:446 +#, c-format +msgid "" +"\n" +"Partition[%d] start = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n" +msgstr "" +"\n" +"·ÖÇø[%d] Æðµã = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n" + +#: ppcboot.c:452 +#, c-format +msgid "Partition[%d] end = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n" +msgstr "·ÖÇø[%d] ÖÕµã = { 0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x }\n" + +#: ppcboot.c:458 +#, c-format +msgid "Partition[%d] sector = 0x%.8lx (%ld)\n" +msgstr "·ÖÇø[%d] ÉÈÇø = 0x%.8lx (%ld)\n" + +#: ppcboot.c:459 +#, c-format +msgid "Partition[%d] length = 0x%.8lx (%ld)\n" +msgstr "·ÖÇø[%d] ³¤¶È = 0x%.8lx (%ld)\n" + +#: som.c:5398 +msgid "som_sizeof_headers unimplemented" +msgstr "" + +#: srec.c:301 +#, c-format +msgid "%s:%d: Unexpected character `%s' in S-record file\n" +msgstr "" + +#: stabs.c:319 +#, c-format +msgid "%s(%s+0x%lx): Stabs entry has invalid string index." +msgstr "" + +#: syms.c:1044 +msgid "Unsupported .stab relocation" +msgstr "²»Ö§³ÖµÄ .stab Öض¨Î»" + +#: vms-gsd.c:356 +#, c-format +msgid "bfd_make_section (%s) failed" +msgstr "" + +#: vms-gsd.c:371 +#, c-format +msgid "bfd_set_section_flags (%s, %x) failed" +msgstr "" + +#: vms-gsd.c:407 +#, c-format +msgid "Size mismatch section %s=%lx, %s=%lx" +msgstr "" + +#: vms-gsd.c:702 +#, c-format +msgid "unknown gsd/egsd subtype %d" +msgstr "" + +#: vms-hdr.c:406 +msgid "Object module NOT error-free !\n" +msgstr "" + +#: vms-misc.c:543 +#, c-format +msgid "Stack overflow (%d) in _bfd_vms_push" +msgstr "" + +#: vms-misc.c:561 +msgid "Stack underflow in _bfd_vms_pop" +msgstr "" + +#: vms-misc.c:919 +msgid "_bfd_vms_output_counted called with zero bytes" +msgstr "" + +#: vms-misc.c:924 +msgid "_bfd_vms_output_counted called with too many bytes" +msgstr "" + +#: vms-misc.c:1055 +#, c-format +msgid "Symbol %s replaced by %s\n" +msgstr "" + +#: vms-misc.c:1117 +#, c-format +msgid "failed to enter %s" +msgstr "" + +#: vms-tir.c:81 +msgid "No Mem !" +msgstr "" + +#: vms-tir.c:362 +#, c-format +msgid "bad section index in %s" +msgstr "%s ÖеĴíÎó½ÚË÷Òý" + +#: vms-tir.c:375 +#, c-format +msgid "unsupported STA cmd %s" +msgstr "²»Ö§³ÖµÄ STA ÃüÁî %s" + +#: vms-tir.c:380 vms-tir.c:1240 +#, c-format +msgid "reserved STA cmd %d" +msgstr "" + +#: vms-tir.c:491 vms-tir.c:514 +#, c-format +msgid "%s: no symbol \"%s\"" +msgstr "" + +#. unsigned shift +#. rotate +#. Redefine symbol to current location. +#. Define a literal. +#: vms-tir.c:581 vms-tir.c:693 vms-tir.c:803 vms-tir.c:821 vms-tir.c:829 +#: vms-tir.c:838 vms-tir.c:1563 +#, c-format +msgid "%s: not supported" +msgstr "%s£º²»Ö§³Ö" + +#: vms-tir.c:586 vms-tir.c:1418 +#, c-format +msgid "%s: not implemented" +msgstr "%s£ºÎ´ÊµÏÖ" + +#: vms-tir.c:590 vms-tir.c:1422 +#, c-format +msgid "reserved STO cmd %d" +msgstr "±£ÁôµÄ STO ÃüÁî %d" + +#: vms-tir.c:708 vms-tir.c:1568 +#, c-format +msgid "reserved OPR cmd %d" +msgstr "±£ÁôµÄ OPR ÃüÁî %d" + +#: vms-tir.c:776 vms-tir.c:1632 +#, c-format +msgid "reserved CTL cmd %d" +msgstr "±£ÁôµÄ CTL ÃüÁî %d" + +#. stack byte from image +#. arg: none. +#: vms-tir.c:1148 +msgid "stack-from-image not implemented" +msgstr "δʵÏÖ stack-from-image" + +#: vms-tir.c:1166 +msgid "stack-entry-mask not fully implemented" +msgstr "ÉÐδÍêȫʵÏÖ stack-entry-mask" + +#. compare procedure argument +#. arg: cs symbol name +#. by argument index +#. da argument descriptor +#. +#. compare argument descriptor with symbol argument (ARG$V_PASSMECH) +#. and stack TRUE (args match) or FALSE (args dont match) value. +#: vms-tir.c:1180 +msgid "PASSMECH not fully implemented" +msgstr "ÉÐδÍêȫʵÏÖ PASSMECH" + +#: vms-tir.c:1199 +msgid "stack-local-symbol not fully implemented" +msgstr "ÉÐδÍêȫʵÏÖ stack-local-symbol" + +#: vms-tir.c:1212 +msgid "stack-literal not fully implemented" +msgstr "ÉÐδÍêȫʵÏÖ stack-literal" + +#: vms-tir.c:1233 +msgid "stack-local-symbol-entry-point-mask not fully implemented" +msgstr "ÉÐδÍêȫʵÏÖ stack-local-symbol-entry-point-mask" + +#: vms-tir.c:1510 vms-tir.c:1522 vms-tir.c:1534 vms-tir.c:1546 vms-tir.c:1611 +#: vms-tir.c:1619 vms-tir.c:1627 +#, c-format +msgid "%s: not fully implemented" +msgstr "%s£ºÉÐδÍêȫʵÏÖ" + +#: vms-tir.c:1684 +#, c-format +msgid "obj code %d not found" +msgstr "" + +#: vms-tir.c:2019 +#, c-format +msgid "SEC_RELOC with no relocs in section %s" +msgstr "" + +#: vms-tir.c:2307 +#, c-format +msgid "Unhandled relocation %s" +msgstr "δ´¦ÀíµÄÖض¨Î» %s" + +#: xcofflink.c:1243 +#, c-format +msgid "%s: `%s' has line numbers but no enclosing section" +msgstr "" + +#: xcofflink.c:1296 +#, c-format +msgid "%s: class %d symbol `%s' has no aux entries" +msgstr "" + +#: xcofflink.c:1319 +#, c-format +msgid "%s: symbol `%s' has unrecognized csect type %d" +msgstr "" + +#: xcofflink.c:1331 +#, c-format +msgid "%s: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d" +msgstr "" + +#: xcofflink.c:1367 +#, c-format +msgid "%s: XMC_TC0 symbol `%s' is class %d scnlen %d" +msgstr "" + +#: xcofflink.c:1519 +#, c-format +msgid "%s: csect `%s' not in enclosing section" +msgstr "" + +#: xcofflink.c:1626 +#, c-format +msgid "%s: misplaced XTY_LD `%s'" +msgstr "" + +#: xcofflink.c:1957 +#, c-format +msgid "%s: reloc %s:%d not in csect" +msgstr "" + +#: xcofflink.c:2092 +#, c-format +msgid "%s: XCOFF shared object when not producing XCOFF output" +msgstr "" + +#: xcofflink.c:2113 +#, c-format +msgid "%s: dynamic object with no .loader section" +msgstr "" + +#: xcofflink.c:2758 +#, c-format +msgid "%s: no such symbol" +msgstr "" + +#: xcofflink.c:2891 +msgid "error: undefined symbol __rtinit" +msgstr "´íÎó£ºÎ´¶¨ÒåµÄ·ûºÅ __rtinit" + +#: xcofflink.c:3453 +#, c-format +msgid "warning: attempt to export undefined symbol `%s'" +msgstr "¾¯¸æ£ºÊÔͼµ¼³ö䶨ÒåµÄ·ûºÅ¡°%s¡±" + +#: xcofflink.c:4447 +#, c-format +msgid "TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling" +msgstr "" + +#: xcofflink.c:5287 xcofflink.c:5756 xcofflink.c:5818 xcofflink.c:6119 +#, c-format +msgid "%s: loader reloc in unrecognized section `%s'" +msgstr "" + +#: xcofflink.c:5309 xcofflink.c:6130 +#, c-format +msgid "%s: `%s' in loader reloc but not loader sym" +msgstr "" + +#: xcofflink.c:5324 +#, c-format +msgid "%s: loader reloc in read-only section %s" +msgstr "" + +#: elf32-ia64.c:2222 elf64-ia64.c:2222 +msgid "@pltoff reloc against local symbol" +msgstr "" + +#: elf32-ia64.c:3562 elf64-ia64.c:3562 +#, c-format +msgid "%s: short data segment overflowed (0x%lx >= 0x400000)" +msgstr "" + +#: elf32-ia64.c:3573 elf64-ia64.c:3573 +#, c-format +msgid "%s: __gp does not cover short data segment" +msgstr "" + +#: elf32-ia64.c:3858 elf64-ia64.c:3858 +#, c-format +msgid "%s: linking non-pic code in a shared library" +msgstr "" + +#: elf32-ia64.c:3891 elf64-ia64.c:3891 +#, c-format +msgid "%s: @gprel relocation against dynamic symbol %s" +msgstr "" + +#: elf32-ia64.c:4030 elf64-ia64.c:4030 +#, c-format +msgid "%s: dynamic relocation against speculation fixup" +msgstr "" + +#: elf32-ia64.c:4038 elf64-ia64.c:4038 +#, c-format +msgid "%s: speculation fixup against undefined weak symbol" +msgstr "" + +#: elf32-ia64.c:4271 elf64-ia64.c:4271 +msgid "unsupported reloc" +msgstr "²»Ö§³ÖµÄÖض¨Î»" + +#: elf32-ia64.c:4551 elf64-ia64.c:4551 +#, c-format +msgid "%s: linking trap-on-NULL-dereference with non-trapping files" +msgstr "" + +#: elf32-ia64.c:4560 elf64-ia64.c:4560 +#, c-format +msgid "%s: linking big-endian files with little-endian files" +msgstr "%s£º½«´ó¶ËÎļþͬС¶ËÎļþ" + +#: elf32-ia64.c:4569 elf64-ia64.c:4569 +#, c-format +msgid "%s: linking 64-bit files with 32-bit files" +msgstr "%s£º½« 64-λÎļþͬ 32-λÎļþÁ¬½Ó" + +#: elf32-ia64.c:4578 elf64-ia64.c:4578 +#, c-format +msgid "%s: linking constant-gp files with non-constant-gp files" +msgstr "" + +#: elf32-ia64.c:4588 elf64-ia64.c:4588 +#, c-format +msgid "%s: linking auto-pic files with non-auto-pic files" +msgstr "" + +#: peigen.c:962 pepigen.c:962 +#, c-format +msgid "%s: line number overflow: 0x%lx > 0xffff" +msgstr "%s£ºÐкÅÒç³ö£º0x%lx > 0xffff" + +#: peigen.c:979 pepigen.c:979 +#, c-format +msgid "%s: reloc overflow 1: 0x%lx > 0xffff" +msgstr "" + +#: peigen.c:993 pepigen.c:993 +msgid "Export Directory [.edata (or where ever we found it)]" +msgstr "µ¼³öĿ¼ [.edata (»òÕßÆäËüÈκÎÄÜÕÒµ½ËüµÄµØ·½)]" + +#: peigen.c:994 pepigen.c:994 +msgid "Import Directory [parts of .idata]" +msgstr "µ¼ÈëĿ¼ [.idata µÄÒ»²¿·Ö]" + +#: peigen.c:995 pepigen.c:995 +msgid "Resource Directory [.rsrc]" +msgstr "×ÊԴĿ¼ [.rsrc]" + +#: peigen.c:996 pepigen.c:996 +msgid "Exception Directory [.pdata]" +msgstr "" + +#: peigen.c:997 pepigen.c:997 +msgid "Security Directory" +msgstr "°²È«Ä¿Â¼" + +#: peigen.c:998 pepigen.c:998 +msgid "Base Relocation Directory [.reloc]" +msgstr "" + +#: peigen.c:999 pepigen.c:999 +msgid "Debug Directory" +msgstr "µ÷ÊÔĿ¼" + +#: peigen.c:1000 pepigen.c:1000 +msgid "Description Directory" +msgstr "ÃèÊöĿ¼" + +#: peigen.c:1001 pepigen.c:1001 +msgid "Special Directory" +msgstr "ÌØÊâĿ¼" + +#: peigen.c:1002 pepigen.c:1002 +msgid "Thread Storage Directory [.tls]" +msgstr "Ï̴߳洢Ŀ¼ [.tls]" + +#: peigen.c:1003 pepigen.c:1003 +msgid "Load Configuration Directory" +msgstr "×°ÈëÅäÖÃĿ¼" + +#: peigen.c:1004 pepigen.c:1004 +msgid "Bound Import Directory" +msgstr "" + +#: peigen.c:1005 pepigen.c:1005 +msgid "Import Address Table Directory" +msgstr "µ¼ÈëµØÖ·±íĿ¼" + +#: peigen.c:1006 pepigen.c:1006 +msgid "Delay Import Directory" +msgstr "ÑÓ³Ùµ¼ÈëĿ¼" + +#: peigen.c:1007 peigen.c:1008 pepigen.c:1007 pepigen.c:1008 +msgid "Reserved" +msgstr "±£Áô" + +#: peigen.c:1071 pepigen.c:1071 +msgid "" +"\n" +"There is an import table, but the section containing it could not be found\n" +msgstr "" + +#: peigen.c:1076 pepigen.c:1076 +#, c-format +msgid "" +"\n" +"There is an import table in %s at 0x%lx\n" +msgstr "" + +#: peigen.c:1113 pepigen.c:1113 +#, c-format +msgid "" +"\n" +"Function descriptor located at the start address: %04lx\n" +msgstr "" + +#: peigen.c:1116 pepigen.c:1116 +#, c-format +msgid "\tcode-base %08lx toc (loadable/actual) %08lx/%08lx\n" +msgstr "" + +#: peigen.c:1122 pepigen.c:1122 +msgid "" +"\n" +"No reldata section! Function descriptor not decoded.\n" +msgstr "" + +#: peigen.c:1127 pepigen.c:1127 +#, c-format +msgid "" +"\n" +"The Import Tables (interpreted %s section contents)\n" +msgstr "" + +#: peigen.c:1130 pepigen.c:1130 +msgid "" +" vma: Hint Time Forward DLL First\n" +" Table Stamp Chain Name Thunk\n" +msgstr "" + +#: peigen.c:1181 pepigen.c:1181 +#, c-format +msgid "" +"\n" +"\tDLL Name: %s\n" +msgstr "" +"\n" +"\tDLL Ãû³Æ£º%s\n" + +#: peigen.c:1192 pepigen.c:1192 +msgid "\tvma: Hint/Ord Member-Name Bound-To\n" +msgstr "" + +#: peigen.c:1217 pepigen.c:1217 +msgid "" +"\n" +"There is a first thunk, but the section containing it could not be found\n" +msgstr "" + +#: peigen.c:1357 pepigen.c:1357 +msgid "" +"\n" +"There is an export table, but the section containing it could not be found\n" +msgstr "" + +#: peigen.c:1362 pepigen.c:1362 +#, c-format +msgid "" +"\n" +"There is an export table in %s at 0x%lx\n" +msgstr "" +"\n" +"%s Öеĵ¼³ö±íλÓÚ 0x%lx\n" + +#: peigen.c:1393 pepigen.c:1393 +#, c-format +msgid "" +"\n" +"The Export Tables (interpreted %s section contents)\n" +"\n" +msgstr "" + +#: peigen.c:1397 pepigen.c:1397 +#, c-format +msgid "Export Flags \t\t\t%lx\n" +msgstr "µ¼³ö±êÖ¾ \t\t\t%lx\n" + +#: peigen.c:1400 pepigen.c:1400 +#, c-format +msgid "Time/Date stamp \t\t%lx\n" +msgstr "ÈÕÆÚ/ʱ¼ä´Á \t\t%lx\n" + +#: peigen.c:1403 pepigen.c:1403 +#, c-format +msgid "Major/Minor \t\t\t%d/%d\n" +msgstr "" + +#: peigen.c:1406 pepigen.c:1406 +msgid "Name \t\t\t\t" +msgstr "Ãû³Æ \t\t\t\t" + +#: peigen.c:1412 pepigen.c:1412 +#, c-format +msgid "Ordinal Base \t\t\t%ld\n" +msgstr "" + +#: peigen.c:1415 pepigen.c:1415 +msgid "Number in:\n" +msgstr "" + +#: peigen.c:1418 pepigen.c:1418 +#, c-format +msgid "\tExport Address Table \t\t%08lx\n" +msgstr "" + +#: peigen.c:1422 pepigen.c:1422 +#, c-format +msgid "\t[Name Pointer/Ordinal] Table\t%08lx\n" +msgstr "" + +#: peigen.c:1425 pepigen.c:1425 +msgid "Table Addresses\n" +msgstr "±íµØÖ·\n" + +#: peigen.c:1428 pepigen.c:1428 +msgid "\tExport Address Table \t\t" +msgstr "\tµ¼³öµØÖ·±í \t\t" + +#: peigen.c:1433 pepigen.c:1433 +msgid "\tName Pointer Table \t\t" +msgstr "\tÃû³ÆÖ¸Õë±í \t\t" + +#: peigen.c:1438 pepigen.c:1438 +msgid "\tOrdinal Table \t\t\t" +msgstr "" + +#: peigen.c:1453 pepigen.c:1453 +#, c-format +msgid "" +"\n" +"Export Address Table -- Ordinal Base %ld\n" +msgstr "" + +#: peigen.c:1472 pepigen.c:1472 +msgid "Forwarder RVA" +msgstr "" + +#: peigen.c:1483 pepigen.c:1483 +msgid "Export RVA" +msgstr "µ¼³ö RVA" + +#: peigen.c:1490 pepigen.c:1490 +msgid "" +"\n" +"[Ordinal/Name Pointer] Table\n" +msgstr "" + +#: peigen.c:1545 pepigen.c:1545 +#, c-format +msgid "Warning, .pdata section size (%ld) is not a multiple of %d\n" +msgstr "" + +#: peigen.c:1549 pepigen.c:1549 +msgid "" +"\n" +"The Function Table (interpreted .pdata section contents)\n" +msgstr "" + +#: peigen.c:1552 pepigen.c:1552 +msgid " vma:\t\t\tBegin Address End Address Unwind Info\n" +msgstr "" + +#: peigen.c:1554 pepigen.c:1554 +msgid "" +" vma:\t\tBegin End EH EH PrologEnd Exception\n" +" \t\tAddress Address Handler Data Address Mask\n" +msgstr "" + +#: peigen.c:1624 pepigen.c:1624 +msgid " Register save millicode" +msgstr "" + +#: peigen.c:1627 pepigen.c:1627 +msgid " Register restore millicode" +msgstr "" + +#: peigen.c:1630 pepigen.c:1630 +msgid " Glue code sequence" +msgstr "" + +#: peigen.c:1682 pepigen.c:1682 +msgid "" +"\n" +"\n" +"PE File Base Relocations (interpreted .reloc section contents)\n" +msgstr "" + +#: peigen.c:1712 pepigen.c:1712 +#, c-format +msgid "" +"\n" +"Virtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n" +msgstr "" + +#: peigen.c:1725 pepigen.c:1725 +#, c-format +msgid "\treloc %4d offset %4x [%4lx] %s" +msgstr "" + +#. The MS dumpbin program reportedly ands with 0xff0f before +#. printing the characteristics field. Not sure why. No reason to +#. emulate it here. +#: peigen.c:1765 pepigen.c:1765 +#, c-format +msgid "" +"\n" +"Characteristics 0x%x\n" +msgstr "" diff --git a/bfd/xtensa-isa.c b/bfd/xtensa-isa.c new file mode 100644 index 0000000..ffbef53 --- /dev/null +++ b/bfd/xtensa-isa.c @@ -0,0 +1,593 @@ +/* Configurable Xtensa ISA support. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +#include "xtensa-isa.h" +#include "xtensa-isa-internal.h" + +xtensa_isa xtensa_default_isa = NULL; + +static int +opname_lookup_compare (const void *v1, const void *v2) +{ + opname_lookup_entry *e1 = (opname_lookup_entry *)v1; + opname_lookup_entry *e2 = (opname_lookup_entry *)v2; + + return strcmp (e1->key, e2->key); +} + + +xtensa_isa +xtensa_isa_init (void) +{ + xtensa_isa isa; + int mod; + + isa = xtensa_load_isa (0); + if (isa == 0) + { + fprintf (stderr, "Failed to initialize Xtensa base ISA module\n"); + return NULL; + } + + for (mod = 1; xtensa_isa_modules[mod].get_num_opcodes_fn; mod++) + { + if (!xtensa_extend_isa (isa, mod)) + { + fprintf (stderr, "Failed to initialize Xtensa TIE ISA module\n"); + return NULL; + } + } + + return isa; +} + +/* ISA information. */ + +static int +xtensa_check_isa_config (xtensa_isa_internal *isa, + struct config_struct *config_table) +{ + int i, j; + + if (!config_table) + { + fprintf (stderr, "Error: Empty configuration table in ISA DLL\n"); + return 0; + } + + /* For the first module, save a pointer to the table and record the + specified endianness and availability of the density option. */ + + if (isa->num_modules == 0) + { + int found_memory_order = 0; + + isa->config = config_table; + isa->has_density = 1; /* Default to have density option. */ + + for (i = 0; config_table[i].param_name; i++) + { + if (!strcmp (config_table[i].param_name, "IsaMemoryOrder")) + { + isa->is_big_endian = + (strcmp (config_table[i].param_value, "BigEndian") == 0); + found_memory_order = 1; + } + if (!strcmp (config_table[i].param_name, "IsaUseDensityInstruction")) + { + isa->has_density = atoi (config_table[i].param_value); + } + } + if (!found_memory_order) + { + fprintf (stderr, "Error: \"IsaMemoryOrder\" missing from " + "configuration table in ISA DLL\n"); + return 0; + } + + return 1; + } + + /* For subsequent modules, check that the parameters match. Note: This + code is sufficient to handle the current model where there are never + more than 2 modules; we might at some point want to handle cases where + module N > 0 specifies some parameters not included in the base table, + and we would then add those to isa->config so that subsequent modules + would check against them. */ + + for (i = 0; config_table[i].param_name; i++) + { + for (j = 0; isa->config[j].param_name; j++) + { + if (!strcmp (config_table[i].param_name, isa->config[j].param_name)) + { + int mismatch; + if (!strcmp (config_table[i].param_name, "IsaCoprocessorCount")) + { + /* Only require the coprocessor count to be <= the base. */ + int tiecnt = atoi (config_table[i].param_value); + int basecnt = atoi (isa->config[j].param_value); + mismatch = (tiecnt > basecnt); + } + else + mismatch = strcmp (config_table[i].param_value, + isa->config[j].param_value); + if (mismatch) + { +#define MISMATCH_MESSAGE \ +"Error: Configuration mismatch in the \"%s\" parameter:\n\ +the configuration used when the TIE file was compiled had a value of\n\ +\"%s\", while the current configuration has a value of\n\ +\"%s\". Please rerun the TIE compiler with a matching\n\ +configuration.\n" + fprintf (stderr, MISMATCH_MESSAGE, + config_table[i].param_name, + config_table[i].param_value, + isa->config[j].param_value); + return 0; + } + break; + } + } + } + + return 1; +} + + +static int +xtensa_add_isa (xtensa_isa_internal *isa, libisa_module_specifier libisa) +{ + const int (*get_num_opcodes_fn) (void); + struct config_struct *(*get_config_table_fn) (void); + xtensa_opcode_internal **(*get_opcodes_fn) (void); + int (*decode_insn_fn) (const xtensa_insnbuf); + xtensa_opcode_internal **opcodes; + int opc, insn_size, prev_num_opcodes, new_num_opcodes, this_module; + + get_num_opcodes_fn = xtensa_isa_modules[libisa].get_num_opcodes_fn; + get_opcodes_fn = xtensa_isa_modules[libisa].get_opcodes_fn; + decode_insn_fn = xtensa_isa_modules[libisa].decode_insn_fn; + get_config_table_fn = xtensa_isa_modules[libisa].get_config_table_fn; + + if (!get_num_opcodes_fn || !get_opcodes_fn || !decode_insn_fn + || (!get_config_table_fn && isa->num_modules == 0)) + return 0; + + if (get_config_table_fn + && !xtensa_check_isa_config (isa, get_config_table_fn ())) + return 0; + + prev_num_opcodes = isa->num_opcodes; + new_num_opcodes = (*get_num_opcodes_fn) (); + + isa->num_opcodes += new_num_opcodes; + isa->opcode_table = (xtensa_opcode_internal **) + realloc (isa->opcode_table, isa->num_opcodes * + sizeof (xtensa_opcode_internal *)); + isa->opname_lookup_table = (opname_lookup_entry *) + realloc (isa->opname_lookup_table, isa->num_opcodes * + sizeof (opname_lookup_entry)); + + opcodes = (*get_opcodes_fn) (); + + insn_size = isa->insn_size; + for (opc = 0; opc < new_num_opcodes; opc++) + { + xtensa_opcode_internal *intopc = opcodes[opc]; + int newopc = prev_num_opcodes + opc; + isa->opcode_table[newopc] = intopc; + isa->opname_lookup_table[newopc].key = intopc->name; + isa->opname_lookup_table[newopc].opcode = newopc; + if (intopc->length > insn_size) + insn_size = intopc->length; + } + + isa->insn_size = insn_size; + isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) / + sizeof (xtensa_insnbuf_word)); + + qsort (isa->opname_lookup_table, isa->num_opcodes, + sizeof (opname_lookup_entry), opname_lookup_compare); + + /* Check for duplicate opcode names. */ + for (opc = 1; opc < isa->num_opcodes; opc++) + { + if (!opname_lookup_compare (&isa->opname_lookup_table[opc-1], + &isa->opname_lookup_table[opc])) + { + fprintf (stderr, "Error: Duplicate TIE opcode \"%s\"\n", + isa->opname_lookup_table[opc].key); + return 0; + } + } + + this_module = isa->num_modules; + isa->num_modules += 1; + + isa->module_opcode_base = (int *) realloc (isa->module_opcode_base, + isa->num_modules * sizeof (int)); + isa->module_decode_fn = (xtensa_insn_decode_fn *) + realloc (isa->module_decode_fn, isa->num_modules * + sizeof (xtensa_insn_decode_fn)); + + isa->module_opcode_base[this_module] = prev_num_opcodes; + isa->module_decode_fn[this_module] = decode_insn_fn; + + xtensa_default_isa = isa; + + return 1; /* Library was successfully added. */ +} + + +xtensa_isa +xtensa_load_isa (libisa_module_specifier libisa) +{ + xtensa_isa_internal *isa; + + isa = (xtensa_isa_internal *) malloc (sizeof (xtensa_isa_internal)); + memset (isa, 0, sizeof (xtensa_isa_internal)); + if (!xtensa_add_isa (isa, libisa)) + { + xtensa_isa_free (isa); + return NULL; + } + return (xtensa_isa) isa; +} + + +int +xtensa_extend_isa (xtensa_isa isa, libisa_module_specifier libisa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return xtensa_add_isa (intisa, libisa); +} + + +void +xtensa_isa_free (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + if (intisa->opcode_table) + free (intisa->opcode_table); + if (intisa->opname_lookup_table) + free (intisa->opname_lookup_table); + if (intisa->module_opcode_base) + free (intisa->module_opcode_base); + if (intisa->module_decode_fn) + free (intisa->module_decode_fn); + free (intisa); +} + + +int +xtensa_insn_maxlength (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->insn_size; +} + + +int +xtensa_insnbuf_size (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->insnbuf_size; +} + + +int +xtensa_num_opcodes (xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->num_opcodes; +} + + +xtensa_opcode +xtensa_opcode_lookup (xtensa_isa isa, const char *opname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + opname_lookup_entry entry, *result; + + entry.key = opname; + result = bsearch (&entry, intisa->opname_lookup_table, intisa->num_opcodes, + sizeof (opname_lookup_entry), opname_lookup_compare); + if (!result) return XTENSA_UNDEFINED; + return result->opcode; +} + + +xtensa_opcode +xtensa_decode_insn (xtensa_isa isa, const xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int n, opc; + for (n = 0; n < intisa->num_modules; n++) { + opc = (intisa->module_decode_fn[n]) (insn); + if (opc != XTENSA_UNDEFINED) + return intisa->module_opcode_base[n] + opc; + } + return XTENSA_UNDEFINED; +} + + +/* Opcode information. */ + +void +xtensa_encode_insn (xtensa_isa isa, xtensa_opcode opc, xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_insnbuf template = intisa->opcode_table[opc]->template(); + int len = intisa->opcode_table[opc]->length; + int n; + + /* Convert length to 32-bit words. */ + len = (len + 3) / 4; + + /* Copy the template. */ + for (n = 0; n < len; n++) + insn[n] = template[n]; + + /* Fill any unused buffer space with zeros. */ + for ( ; n < intisa->insnbuf_size; n++) + insn[n] = 0; +} + + +const char * +xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->opcode_table[opc]->name; +} + + +int +xtensa_insn_length (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->opcode_table[opc]->length; +} + + +int +xtensa_insn_length_from_first_byte (xtensa_isa isa, char first_byte) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int is_density = (first_byte & (intisa->is_big_endian ? 0x80 : 0x08)) != 0; + return (intisa->has_density && is_density ? 2 : 3); +} + + +int +xtensa_num_operands (xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + return intisa->opcode_table[opc]->iclass->num_operands; +} + + +xtensa_operand +xtensa_get_operand (xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + xtensa_iclass_internal *iclass = intisa->opcode_table[opc]->iclass; + if (opnd >= iclass->num_operands) + return NULL; + return (xtensa_operand) iclass->operands[opnd]; +} + + +/* Operand information. */ + +char * +xtensa_operand_kind (xtensa_operand opnd) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return intop->operand_kind; +} + + +char +xtensa_operand_inout (xtensa_operand opnd) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return intop->inout; +} + + +uint32 +xtensa_operand_get_field (xtensa_operand opnd, const xtensa_insnbuf insn) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return (*intop->get_field) (insn); +} + + +void +xtensa_operand_set_field (xtensa_operand opnd, xtensa_insnbuf insn, uint32 val) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return (*intop->set_field) (insn, val); +} + + +xtensa_encode_result +xtensa_operand_encode (xtensa_operand opnd, uint32 *valp) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return (*intop->encode) (valp); +} + + +uint32 +xtensa_operand_decode (xtensa_operand opnd, uint32 val) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return (*intop->decode) (val); +} + + +int +xtensa_operand_isPCRelative (xtensa_operand opnd) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + return intop->isPCRelative; +} + + +uint32 +xtensa_operand_do_reloc (xtensa_operand opnd, uint32 addr, uint32 pc) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + if (!intop->isPCRelative) + return addr; + return (*intop->do_reloc) (addr, pc); +} + + +uint32 +xtensa_operand_undo_reloc (xtensa_operand opnd, uint32 offset, uint32 pc) +{ + xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd; + if (!intop->isPCRelative) + return offset; + return (*intop->undo_reloc) (offset, pc); +} + + +/* Instruction buffers. */ + +xtensa_insnbuf +xtensa_insnbuf_alloc (xtensa_isa isa) +{ + return (xtensa_insnbuf) malloc (xtensa_insnbuf_size (isa) * + sizeof (xtensa_insnbuf_word)); +} + + +void +xtensa_insnbuf_free (xtensa_insnbuf buf) +{ + free( buf ); +} + + +/* Given , the index of a byte in a xtensa_insnbuf, our + internal representation of a xtensa instruction word, return the index of + its word and the bit index of its low order byte in the xtensa_insnbuf. */ + +static inline int +byte_to_word_index (int byte_index) +{ + return byte_index / sizeof (xtensa_insnbuf_word); +} + + +static inline int +byte_to_bit_index (int byte_index) +{ + return (byte_index & 0x3) * 8; +} + + +/* Copy an instruction in the 32 bit words pointed at by to characters + pointed at by . This is more complicated than you might think because + we want 16 bit instructions in bytes 2,3 for big endian. This function + allows us to specify which byte in to start with and which way to + increment, allowing trivial implementation for both big and little endian. + And it seems to make pretty good code for both. */ + +void +xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, char *cp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int insn_size = xtensa_insn_maxlength (intisa); + int fence_post, start, increment, i, byte_count; + xtensa_opcode opc; + + if (intisa->is_big_endian) + { + start = insn_size - 1; + increment = -1; + } + else + { + start = 0; + increment = 1; + } + + /* Find the opcode; do nothing if the buffer does not contain a valid + instruction since we need to know how many bytes to copy. */ + opc = xtensa_decode_insn (isa, insn); + if (opc == XTENSA_UNDEFINED) + return; + + byte_count = xtensa_insn_length (isa, opc); + fence_post = start + (byte_count * increment); + + for (i = start; i != fence_post; i += increment, ++cp) + { + int word_inx = byte_to_word_index (i); + int bit_inx = byte_to_bit_index (i); + + *cp = (insn[word_inx] >> bit_inx) & 0xff; + } +} + +/* Inward conversion from byte stream to xtensa_insnbuf. See + xtensa_insnbuf_to_chars for a discussion of why this is + complicated by endianness. */ + +void +xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, const char* cp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa; + int insn_size = xtensa_insn_maxlength (intisa); + int fence_post, start, increment, i; + + if (intisa->is_big_endian) + { + start = insn_size - 1; + increment = -1; + } + else + { + start = 0; + increment = 1; + } + + fence_post = start + (insn_size * increment); + memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word)); + + for ( i = start; i != fence_post; i += increment, ++cp ) + { + int word_inx = byte_to_word_index (i); + int bit_inx = byte_to_bit_index (i); + + insn[word_inx] |= (*cp & 0xff) << bit_inx; + } +} + diff --git a/bfd/xtensa-modules.c b/bfd/xtensa-modules.c new file mode 100644 index 0000000..d023b52 --- /dev/null +++ b/bfd/xtensa-modules.c @@ -0,0 +1,6088 @@ +/* Xtensa configuration-specific ISA information. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "xtensa-isa-internal.h" +#include "ansidecl.h" + +#define BPW 32 +#define WINDEX(_n) ((_n) / BPW) +#define BINDEX(_n) ((_n) %% BPW) + +static uint32 tie_do_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED; +static uint32 tie_undo_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED; + +static uint32 +tie_do_reloc_l (uint32 addr, uint32 pc) +{ + return (addr - pc); +} + +static uint32 +tie_undo_reloc_l (uint32 offset, uint32 pc) +{ + return (pc + offset); +} + +xtensa_opcode_internal** get_opcodes (void); +const int get_num_opcodes (void); +int decode_insn (const xtensa_insnbuf); +int interface_version (void); + +uint32 get_bbi_field (const xtensa_insnbuf); +void set_bbi_field (xtensa_insnbuf, uint32); +uint32 get_bbi4_field (const xtensa_insnbuf); +void set_bbi4_field (xtensa_insnbuf, uint32); +uint32 get_i_field (const xtensa_insnbuf); +void set_i_field (xtensa_insnbuf, uint32); +uint32 get_imm12_field (const xtensa_insnbuf); +void set_imm12_field (xtensa_insnbuf, uint32); +uint32 get_imm12b_field (const xtensa_insnbuf); +void set_imm12b_field (xtensa_insnbuf, uint32); +uint32 get_imm16_field (const xtensa_insnbuf); +void set_imm16_field (xtensa_insnbuf, uint32); +uint32 get_imm4_field (const xtensa_insnbuf); +void set_imm4_field (xtensa_insnbuf, uint32); +uint32 get_imm6_field (const xtensa_insnbuf); +void set_imm6_field (xtensa_insnbuf, uint32); +uint32 get_imm6hi_field (const xtensa_insnbuf); +void set_imm6hi_field (xtensa_insnbuf, uint32); +uint32 get_imm6lo_field (const xtensa_insnbuf); +void set_imm6lo_field (xtensa_insnbuf, uint32); +uint32 get_imm7_field (const xtensa_insnbuf); +void set_imm7_field (xtensa_insnbuf, uint32); +uint32 get_imm7hi_field (const xtensa_insnbuf); +void set_imm7hi_field (xtensa_insnbuf, uint32); +uint32 get_imm7lo_field (const xtensa_insnbuf); +void set_imm7lo_field (xtensa_insnbuf, uint32); +uint32 get_imm8_field (const xtensa_insnbuf); +void set_imm8_field (xtensa_insnbuf, uint32); +uint32 get_m_field (const xtensa_insnbuf); +void set_m_field (xtensa_insnbuf, uint32); +uint32 get_mn_field (const xtensa_insnbuf); +void set_mn_field (xtensa_insnbuf, uint32); +uint32 get_n_field (const xtensa_insnbuf); +void set_n_field (xtensa_insnbuf, uint32); +uint32 get_none_field (const xtensa_insnbuf); +void set_none_field (xtensa_insnbuf, uint32); +uint32 get_offset_field (const xtensa_insnbuf); +void set_offset_field (xtensa_insnbuf, uint32); +uint32 get_op0_field (const xtensa_insnbuf); +void set_op0_field (xtensa_insnbuf, uint32); +uint32 get_op1_field (const xtensa_insnbuf); +void set_op1_field (xtensa_insnbuf, uint32); +uint32 get_op2_field (const xtensa_insnbuf); +void set_op2_field (xtensa_insnbuf, uint32); +uint32 get_r_field (const xtensa_insnbuf); +void set_r_field (xtensa_insnbuf, uint32); +uint32 get_s_field (const xtensa_insnbuf); +void set_s_field (xtensa_insnbuf, uint32); +uint32 get_sa4_field (const xtensa_insnbuf); +void set_sa4_field (xtensa_insnbuf, uint32); +uint32 get_sae_field (const xtensa_insnbuf); +void set_sae_field (xtensa_insnbuf, uint32); +uint32 get_sae4_field (const xtensa_insnbuf); +void set_sae4_field (xtensa_insnbuf, uint32); +uint32 get_sal_field (const xtensa_insnbuf); +void set_sal_field (xtensa_insnbuf, uint32); +uint32 get_sar_field (const xtensa_insnbuf); +void set_sar_field (xtensa_insnbuf, uint32); +uint32 get_sas_field (const xtensa_insnbuf); +void set_sas_field (xtensa_insnbuf, uint32); +uint32 get_sas4_field (const xtensa_insnbuf); +void set_sas4_field (xtensa_insnbuf, uint32); +uint32 get_sr_field (const xtensa_insnbuf); +void set_sr_field (xtensa_insnbuf, uint32); +uint32 get_t_field (const xtensa_insnbuf); +void set_t_field (xtensa_insnbuf, uint32); +uint32 get_thi3_field (const xtensa_insnbuf); +void set_thi3_field (xtensa_insnbuf, uint32); +uint32 get_z_field (const xtensa_insnbuf); +void set_z_field (xtensa_insnbuf, uint32); + + +uint32 +get_bbi_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf0000) >> 16) | + ((insn[0] & 0x100) >> 4); +} + +void +set_bbi_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); + insn[0] = (insn[0] & 0xfffffeff) | ((val << 4) & 0x100); +} + +uint32 +get_bbi4_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x100) >> 8); +} + +void +set_bbi4_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffffeff) | ((val << 8) & 0x100); +} + +uint32 +get_i_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x80000) >> 19); +} + +void +set_i_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff7ffff) | ((val << 19) & 0x80000); +} + +uint32 +get_imm12_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xfff)); +} + +void +set_imm12_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff000) | (val & 0xfff); +} + +uint32 +get_imm12b_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xff)) | + ((insn[0] & 0xf000) >> 4); +} + +void +set_imm12b_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffffff00) | (val & 0xff); + insn[0] = (insn[0] & 0xffff0fff) | ((val << 4) & 0xf000); +} + +uint32 +get_imm16_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xffff)); +} + +void +set_imm16_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffff0000) | (val & 0xffff); +} + +uint32 +get_imm4_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8); +} + +void +set_imm4_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); +} + +uint32 +get_imm6_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8) | + ((insn[0] & 0x30000) >> 12); +} + +void +set_imm6_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + insn[0] = (insn[0] & 0xfffcffff) | ((val << 12) & 0x30000); +} + +uint32 +get_imm6hi_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x30000) >> 16); +} + +void +set_imm6hi_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); +} + +uint32 +get_imm6lo_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8); +} + +void +set_imm6lo_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); +} + +uint32 +get_imm7_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8) | + ((insn[0] & 0x70000) >> 12); +} + +void +set_imm7_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + insn[0] = (insn[0] & 0xfff8ffff) | ((val << 12) & 0x70000); +} + +uint32 +get_imm7hi_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x70000) >> 16); +} + +void +set_imm7hi_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff8ffff) | ((val << 16) & 0x70000); +} + +uint32 +get_imm7lo_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8); +} + +void +set_imm7lo_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); +} + +uint32 +get_imm8_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xff)); +} + +void +set_imm8_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffffff00) | (val & 0xff); +} + +uint32 +get_m_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x30000) >> 16); +} + +void +set_m_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); +} + +uint32 +get_mn_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x30000) >> 16) | + ((insn[0] & 0xc0000) >> 16); +} + +void +set_mn_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000); + insn[0] = (insn[0] & 0xfff3ffff) | ((val << 16) & 0xc0000); +} + +uint32 +get_n_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xc0000) >> 18); +} + +void +set_n_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff3ffff) | ((val << 18) & 0xc0000); +} + +uint32 +get_none_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x0)); +} + +void +set_none_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffffffff) | (val & 0x0); +} + +uint32 +get_offset_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x3ffff)); +} + +void +set_offset_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffc0000) | (val & 0x3ffff); +} + +uint32 +get_op0_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00000) >> 20); +} + +void +set_op0_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xff0fffff) | ((val << 20) & 0xf00000); +} + +uint32 +get_op1_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf0) >> 4); +} + +void +set_op1_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffffff0f) | ((val << 4) & 0xf0); +} + +uint32 +get_op2_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf)); +} + +void +set_op2_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffffff0) | (val & 0xf); +} + +uint32 +get_r_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8); +} + +void +set_r_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); +} + +uint32 +get_s_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf000) >> 12); +} + +void +set_s_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); +} + +uint32 +get_sa4_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x1)); +} + +void +set_sa4_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffffffe) | (val & 0x1); +} + +uint32 +get_sae_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf000) >> 12) | + ((insn[0] & 0x10)); +} + +void +set_sae_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); + insn[0] = (insn[0] & 0xffffffef) | (val & 0x10); +} + +uint32 +get_sae4_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x10) >> 4); +} + +void +set_sae4_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffffffef) | ((val << 4) & 0x10); +} + +uint32 +get_sal_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf0000) >> 16) | + ((insn[0] & 0x1) << 4); +} + +void +set_sal_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); + insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1); +} + +uint32 +get_sar_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf000) >> 12) | + ((insn[0] & 0x1) << 4); +} + +void +set_sar_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); + insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1); +} + +uint32 +get_sas_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf000) >> 12) | + ((insn[0] & 0x10000) >> 12); +} + +void +set_sas_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000); + insn[0] = (insn[0] & 0xfffeffff) | ((val << 12) & 0x10000); +} + +uint32 +get_sas4_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x10000) >> 16); +} + +void +set_sas4_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffeffff) | ((val << 16) & 0x10000); +} + +uint32 +get_sr_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf00) >> 8) | + ((insn[0] & 0xf000) >> 8); +} + +void +set_sr_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00); + insn[0] = (insn[0] & 0xffff0fff) | ((val << 8) & 0xf000); +} + +uint32 +get_t_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xf0000) >> 16); +} + +void +set_t_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000); +} + +uint32 +get_thi3_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0xe0000) >> 17); +} + +void +set_thi3_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfff1ffff) | ((val << 17) & 0xe0000); +} + +uint32 +get_z_field (const xtensa_insnbuf insn) +{ + return ((insn[0] & 0x40000) >> 18); +} + +void +set_z_field (xtensa_insnbuf insn, uint32 val) +{ + insn[0] = (insn[0] & 0xfffbffff) | ((val << 18) & 0x40000); +} + +uint32 decode_b4constu (uint32); +xtensa_encode_result encode_b4constu (uint32 *); +uint32 decode_simm8x256 (uint32); +xtensa_encode_result encode_simm8x256 (uint32 *); +uint32 decode_soffset (uint32); +xtensa_encode_result encode_soffset (uint32 *); +uint32 decode_imm4 (uint32); +xtensa_encode_result encode_imm4 (uint32 *); +uint32 decode_op0 (uint32); +xtensa_encode_result encode_op0 (uint32 *); +uint32 decode_op1 (uint32); +xtensa_encode_result encode_op1 (uint32 *); +uint32 decode_imm6 (uint32); +xtensa_encode_result encode_imm6 (uint32 *); +uint32 decode_op2 (uint32); +xtensa_encode_result encode_op2 (uint32 *); +uint32 decode_imm7 (uint32); +xtensa_encode_result encode_imm7 (uint32 *); +uint32 decode_simm4 (uint32); +xtensa_encode_result encode_simm4 (uint32 *); +uint32 decode_ai4const (uint32); +xtensa_encode_result encode_ai4const (uint32 *); +uint32 decode_imm8 (uint32); +xtensa_encode_result encode_imm8 (uint32 *); +uint32 decode_sae (uint32); +xtensa_encode_result encode_sae (uint32 *); +uint32 decode_imm7lo (uint32); +xtensa_encode_result encode_imm7lo (uint32 *); +uint32 decode_simm7 (uint32); +xtensa_encode_result encode_simm7 (uint32 *); +uint32 decode_simm8 (uint32); +xtensa_encode_result encode_simm8 (uint32 *); +uint32 decode_uimm12x8 (uint32); +xtensa_encode_result encode_uimm12x8 (uint32 *); +uint32 decode_sal (uint32); +xtensa_encode_result encode_sal (uint32 *); +uint32 decode_uimm6 (uint32); +xtensa_encode_result encode_uimm6 (uint32 *); +uint32 decode_sas4 (uint32); +xtensa_encode_result encode_sas4 (uint32 *); +uint32 decode_uimm8 (uint32); +xtensa_encode_result encode_uimm8 (uint32 *); +uint32 decode_uimm16x4 (uint32); +xtensa_encode_result encode_uimm16x4 (uint32 *); +uint32 decode_sar (uint32); +xtensa_encode_result encode_sar (uint32 *); +uint32 decode_sa4 (uint32); +xtensa_encode_result encode_sa4 (uint32 *); +uint32 decode_sas (uint32); +xtensa_encode_result encode_sas (uint32 *); +uint32 decode_imm6hi (uint32); +xtensa_encode_result encode_imm6hi (uint32 *); +uint32 decode_bbi (uint32); +xtensa_encode_result encode_bbi (uint32 *); +uint32 decode_uimm8x2 (uint32); +xtensa_encode_result encode_uimm8x2 (uint32 *); +uint32 decode_uimm8x4 (uint32); +xtensa_encode_result encode_uimm8x4 (uint32 *); +uint32 decode_msalp32 (uint32); +xtensa_encode_result encode_msalp32 (uint32 *); +uint32 decode_bbi4 (uint32); +xtensa_encode_result encode_bbi4 (uint32 *); +uint32 decode_op2p1 (uint32); +xtensa_encode_result encode_op2p1 (uint32 *); +uint32 decode_soffsetx4 (uint32); +xtensa_encode_result encode_soffsetx4 (uint32 *); +uint32 decode_imm6lo (uint32); +xtensa_encode_result encode_imm6lo (uint32 *); +uint32 decode_imm12 (uint32); +xtensa_encode_result encode_imm12 (uint32 *); +uint32 decode_b4const (uint32); +xtensa_encode_result encode_b4const (uint32 *); +uint32 decode_i (uint32); +xtensa_encode_result encode_i (uint32 *); +uint32 decode_imm16 (uint32); +xtensa_encode_result encode_imm16 (uint32 *); +uint32 decode_mn (uint32); +xtensa_encode_result encode_mn (uint32 *); +uint32 decode_m (uint32); +xtensa_encode_result encode_m (uint32 *); +uint32 decode_n (uint32); +xtensa_encode_result encode_n (uint32 *); +uint32 decode_none (uint32); +xtensa_encode_result encode_none (uint32 *); +uint32 decode_imm12b (uint32); +xtensa_encode_result encode_imm12b (uint32 *); +uint32 decode_r (uint32); +xtensa_encode_result encode_r (uint32 *); +uint32 decode_s (uint32); +xtensa_encode_result encode_s (uint32 *); +uint32 decode_t (uint32); +xtensa_encode_result encode_t (uint32 *); +uint32 decode_thi3 (uint32); +xtensa_encode_result encode_thi3 (uint32 *); +uint32 decode_sae4 (uint32); +xtensa_encode_result encode_sae4 (uint32 *); +uint32 decode_offset (uint32); +xtensa_encode_result encode_offset (uint32 *); +uint32 decode_imm7hi (uint32); +xtensa_encode_result encode_imm7hi (uint32 *); +uint32 decode_uimm4x16 (uint32); +xtensa_encode_result encode_uimm4x16 (uint32 *); +uint32 decode_simm12b (uint32); +xtensa_encode_result encode_simm12b (uint32 *); +uint32 decode_lsi4x4 (uint32); +xtensa_encode_result encode_lsi4x4 (uint32 *); +uint32 decode_z (uint32); +xtensa_encode_result encode_z (uint32 *); +uint32 decode_simm12 (uint32); +xtensa_encode_result encode_simm12 (uint32 *); +uint32 decode_sr (uint32); +xtensa_encode_result encode_sr (uint32 *); +uint32 decode_nimm4x2 (uint32); +xtensa_encode_result encode_nimm4x2 (uint32 *); + + +static const uint32 b4constu_table[] = { + 32768, + 65536, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 16, + 32, + 64, + 128, + 256 +}; + +uint32 +decode_b4constu (uint32 val) +{ + val = b4constu_table[val]; + return val; +} + +xtensa_encode_result +encode_b4constu (uint32 *valp) +{ + uint32 val = *valp; + unsigned i; + for (i = 0; i < (1 << 4); i += 1) + if (b4constu_table[i] == val) goto found; + return xtensa_encode_result_not_in_table; + found: + val = i; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm8x256 (uint32 val) +{ + val = (val ^ 0x80) - 0x80; + val <<= 8; + return val; +} + +xtensa_encode_result +encode_simm8x256 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 8) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 8; + if (((val + (1 << 7)) >> 8) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_soffset (uint32 val) +{ + val = (val ^ 0x20000) - 0x20000; + return val; +} + +xtensa_encode_result +encode_soffset (uint32 *valp) +{ + uint32 val = *valp; + if (((val + (1 << 17)) >> 18) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm4 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_op0 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_op0 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_op1 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_op1 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm6 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm6 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 6) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_op2 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_op2 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm7 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm7 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 7) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm4 (uint32 val) +{ + val = (val ^ 0x8) - 0x8; + return val; +} + +xtensa_encode_result +encode_simm4 (uint32 *valp) +{ + uint32 val = *valp; + if (((val + (1 << 3)) >> 4) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +static const uint32 ai4const_table[] = { + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 +}; + +uint32 +decode_ai4const (uint32 val) +{ + val = ai4const_table[val]; + return val; +} + +xtensa_encode_result +encode_ai4const (uint32 *valp) +{ + uint32 val = *valp; + unsigned i; + for (i = 0; i < (1 << 4); i += 1) + if (ai4const_table[i] == val) goto found; + return xtensa_encode_result_not_in_table; + found: + val = i; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm8 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm8 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 8) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sae (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sae (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 5) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm7lo (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm7lo (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm7 (uint32 val) +{ + if (val > 95) + val |= -32; + return val; +} + +xtensa_encode_result +encode_simm7 (uint32 *valp) +{ + uint32 val = *valp; + if ((signed int) val < -32) + return xtensa_encode_result_too_low; + if ((signed int) val > 95) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm8 (uint32 val) +{ + val = (val ^ 0x80) - 0x80; + return val; +} + +xtensa_encode_result +encode_simm8 (uint32 *valp) +{ + uint32 val = *valp; + if (((val + (1 << 7)) >> 8) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm12x8 (uint32 val) +{ + val <<= 3; + return val; +} + +xtensa_encode_result +encode_uimm12x8 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 3) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 3; + if ((val >> 12) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sal (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sal (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 5) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm6 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_uimm6 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 6) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sas4 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sas4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm8 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_uimm8 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 8) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm16x4 (uint32 val) +{ + val |= -1 << 16; + val <<= 2; + return val; +} + +xtensa_encode_result +encode_uimm16x4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 2) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 2; + if ((signed int) val >> 16 != -1) + { + if ((signed int) val >= 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sar (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sar (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 5) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sa4 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sa4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sas (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sas (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 5) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm6hi (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm6hi (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 2) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_bbi (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_bbi (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 5) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm8x2 (uint32 val) +{ + val <<= 1; + return val; +} + +xtensa_encode_result +encode_uimm8x2 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 1) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 1; + if ((val >> 8) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm8x4 (uint32 val) +{ + val <<= 2; + return val; +} + +xtensa_encode_result +encode_uimm8x4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 2) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 2; + if ((val >> 8) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +static const uint32 mip32const_table[] = { + 32, + 31, + 30, + 29, + 28, + 27, + 26, + 25, + 24, + 23, + 22, + 21, + 20, + 19, + 18, + 17, + 16, + 15, + 14, + 13, + 12, + 11, + 10, + 9, + 8, + 7, + 6, + 5, + 4, + 3, + 2, + 1 +}; + +uint32 +decode_msalp32 (uint32 val) +{ + val = mip32const_table[val]; + return val; +} + +xtensa_encode_result +encode_msalp32 (uint32 *valp) +{ + uint32 val = *valp; + unsigned i; + for (i = 0; i < (1 << 5); i += 1) + if (mip32const_table[i] == val) goto found; + return xtensa_encode_result_not_in_table; + found: + val = i; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_bbi4 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_bbi4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +static const uint32 i4p1const_table[] = { + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16 +}; + +uint32 +decode_op2p1 (uint32 val) +{ + val = i4p1const_table[val]; + return val; +} + +xtensa_encode_result +encode_op2p1 (uint32 *valp) +{ + uint32 val = *valp; + unsigned i; + for (i = 0; i < (1 << 4); i += 1) + if (i4p1const_table[i] == val) goto found; + return xtensa_encode_result_not_in_table; + found: + val = i; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_soffsetx4 (uint32 val) +{ + val = (val ^ 0x20000) - 0x20000; + val <<= 2; + return val; +} + +xtensa_encode_result +encode_soffsetx4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 2) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 2; + if (((val + (1 << 17)) >> 18) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm6lo (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm6lo (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm12 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm12 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 12) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +static const uint32 b4const_table[] = { + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 12, + 16, + 32, + 64, + 128, + 256 +}; + +uint32 +decode_b4const (uint32 val) +{ + val = b4const_table[val]; + return val; +} + +xtensa_encode_result +encode_b4const (uint32 *valp) +{ + uint32 val = *valp; + unsigned i; + for (i = 0; i < (1 << 4); i += 1) + if (b4const_table[i] == val) goto found; + return xtensa_encode_result_not_in_table; + found: + val = i; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_i (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_i (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm16 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm16 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 16) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_mn (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_mn (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_m (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_m (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 2) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_n (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_n (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 2) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_none (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_none (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 0) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm12b (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm12b (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 12) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_r (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_r (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_s (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_s (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_t (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_t (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_thi3 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_thi3 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 3) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sae4 (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sae4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_offset (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_offset (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 18) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_imm7hi (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_imm7hi (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 3) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_uimm4x16 (uint32 val) +{ + val <<= 4; + return val; +} + +xtensa_encode_result +encode_uimm4x16 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 4) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 4; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm12b (uint32 val) +{ + val = (val ^ 0x800) - 0x800; + return val; +} + +xtensa_encode_result +encode_simm12b (uint32 *valp) +{ + uint32 val = *valp; + if (((val + (1 << 11)) >> 12) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_lsi4x4 (uint32 val) +{ + val <<= 2; + return val; +} + +xtensa_encode_result +encode_lsi4x4 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 2) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 2; + if ((val >> 4) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_z (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_z (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 1) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_simm12 (uint32 val) +{ + val = (val ^ 0x800) - 0x800; + return val; +} + +xtensa_encode_result +encode_simm12 (uint32 *valp) +{ + uint32 val = *valp; + if (((val + (1 << 11)) >> 12) != 0) + { + if ((signed int) val > 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_sr (uint32 val) +{ + return val; +} + +xtensa_encode_result +encode_sr (uint32 *valp) +{ + uint32 val = *valp; + if ((val >> 8) != 0) + return xtensa_encode_result_too_high; + *valp = val; + return xtensa_encode_result_ok; +} + +uint32 +decode_nimm4x2 (uint32 val) +{ + val |= -1 << 4; + val <<= 2; + return val; +} + +xtensa_encode_result +encode_nimm4x2 (uint32 *valp) +{ + uint32 val = *valp; + if ((val & ((1 << 2) - 1)) != 0) + return xtensa_encode_result_align; + val = (signed int) val >> 2; + if ((signed int) val >> 4 != -1) + { + if ((signed int) val >= 0) + return xtensa_encode_result_too_high; + else + return xtensa_encode_result_too_low; + } + *valp = val; + return xtensa_encode_result_ok; +} + + + +uint32 do_reloc_l (uint32, uint32); +uint32 undo_reloc_l (uint32, uint32); +uint32 do_reloc_L (uint32, uint32); +uint32 undo_reloc_L (uint32, uint32); +uint32 do_reloc_r (uint32, uint32); +uint32 undo_reloc_r (uint32, uint32); + + +uint32 +do_reloc_l (uint32 addr, uint32 pc) +{ + return addr - pc - 4; +} + +uint32 +undo_reloc_l (uint32 offset, uint32 pc) +{ + return pc + offset + 4; +} + +uint32 +do_reloc_L (uint32 addr, uint32 pc) +{ + return addr - (pc & -4) - 4; +} + +uint32 +undo_reloc_L (uint32 offset, uint32 pc) +{ + return (pc & -4) + offset + 4; +} + +uint32 +do_reloc_r (uint32 addr, uint32 pc) +{ + return addr - ((pc+3) & -4); +} + +uint32 +undo_reloc_r (uint32 offset, uint32 pc) +{ + return ((pc+3) & -4) + offset; +} + +static xtensa_operand_internal iib4const_operand = { + "i", + '<', + 0, + get_r_field, + set_r_field, + encode_b4const, + decode_b4const, + 0, + 0 +}; + +static xtensa_operand_internal iiuimm8_operand = { + "i", + '<', + 0, + get_imm8_field, + set_imm8_field, + encode_uimm8, + decode_uimm8, + 0, + 0 +}; + +static xtensa_operand_internal lisoffsetx4_operand = { + "L", + '<', + 1, + get_offset_field, + set_offset_field, + encode_soffsetx4, + decode_soffsetx4, + do_reloc_L, + undo_reloc_L, +}; + +static xtensa_operand_internal iisimm8x256_operand = { + "i", + '<', + 0, + get_imm8_field, + set_imm8_field, + encode_simm8x256, + decode_simm8x256, + 0, + 0 +}; + +static xtensa_operand_internal lisimm12_operand = { + "l", + '<', + 1, + get_imm12_field, + set_imm12_field, + encode_simm12, + decode_simm12, + do_reloc_l, + undo_reloc_l, +}; + +static xtensa_operand_internal iiop2p1_operand = { + "i", + '<', + 0, + get_op2_field, + set_op2_field, + encode_op2p1, + decode_op2p1, + 0, + 0 +}; + +static xtensa_operand_internal iisae_operand = { + "i", + '<', + 0, + get_sae_field, + set_sae_field, + encode_sae, + decode_sae, + 0, + 0 +}; + +static xtensa_operand_internal iis_operand = { + "i", + '<', + 0, + get_s_field, + set_s_field, + encode_s, + decode_s, + 0, + 0 +}; + +static xtensa_operand_internal iit_operand = { + "i", + '<', + 0, + get_t_field, + set_t_field, + encode_t, + decode_t, + 0, + 0 +}; + +static xtensa_operand_internal iisimm12b_operand = { + "i", + '<', + 0, + get_imm12b_field, + set_imm12b_field, + encode_simm12b, + decode_simm12b, + 0, + 0 +}; + +static xtensa_operand_internal iinimm4x2_operand = { + "i", + '<', + 0, + get_imm4_field, + set_imm4_field, + encode_nimm4x2, + decode_nimm4x2, + 0, + 0 +}; + +static xtensa_operand_internal iiuimm4x16_operand = { + "i", + '<', + 0, + get_op2_field, + set_op2_field, + encode_uimm4x16, + decode_uimm4x16, + 0, + 0 +}; + +static xtensa_operand_internal abs_operand = { + "a", + '=', + 0, + get_s_field, + set_s_field, + encode_s, + decode_s, + 0, + 0 +}; + +static xtensa_operand_internal iisar_operand = { + "i", + '<', + 0, + get_sar_field, + set_sar_field, + encode_sar, + decode_sar, + 0, + 0 +}; + +static xtensa_operand_internal abt_operand = { + "a", + '=', + 0, + get_t_field, + set_t_field, + encode_t, + decode_t, + 0, + 0 +}; + +static xtensa_operand_internal iisas_operand = { + "i", + '<', + 0, + get_sas_field, + set_sas_field, + encode_sas, + decode_sas, + 0, + 0 +}; + +static xtensa_operand_internal amr_operand = { + "a", + '=', + 0, + get_r_field, + set_r_field, + encode_r, + decode_r, + 0, + 0 +}; + +static xtensa_operand_internal iib4constu_operand = { + "i", + '<', + 0, + get_r_field, + set_r_field, + encode_b4constu, + decode_b4constu, + 0, + 0 +}; + +static xtensa_operand_internal iisr_operand = { + "i", + '<', + 0, + get_sr_field, + set_sr_field, + encode_sr, + decode_sr, + 0, + 0 +}; + +static xtensa_operand_internal iibbi_operand = { + "i", + '<', + 0, + get_bbi_field, + set_bbi_field, + encode_bbi, + decode_bbi, + 0, + 0 +}; + +static xtensa_operand_internal iiai4const_operand = { + "i", + '<', + 0, + get_t_field, + set_t_field, + encode_ai4const, + decode_ai4const, + 0, + 0 +}; + +static xtensa_operand_internal iiuimm12x8_operand = { + "i", + '<', + 0, + get_imm12_field, + set_imm12_field, + encode_uimm12x8, + decode_uimm12x8, + 0, + 0 +}; + +static xtensa_operand_internal riuimm16x4_operand = { + "r", + '<', + 1, + get_imm16_field, + set_imm16_field, + encode_uimm16x4, + decode_uimm16x4, + do_reloc_r, + undo_reloc_r, +}; + +static xtensa_operand_internal lisimm8_operand = { + "l", + '<', + 1, + get_imm8_field, + set_imm8_field, + encode_simm8, + decode_simm8, + do_reloc_l, + undo_reloc_l, +}; + +static xtensa_operand_internal iilsi4x4_operand = { + "i", + '<', + 0, + get_r_field, + set_r_field, + encode_lsi4x4, + decode_lsi4x4, + 0, + 0 +}; + +static xtensa_operand_internal iiuimm8x2_operand = { + "i", + '<', + 0, + get_imm8_field, + set_imm8_field, + encode_uimm8x2, + decode_uimm8x2, + 0, + 0 +}; + +static xtensa_operand_internal iisimm4_operand = { + "i", + '<', + 0, + get_mn_field, + set_mn_field, + encode_simm4, + decode_simm4, + 0, + 0 +}; + +static xtensa_operand_internal iimsalp32_operand = { + "i", + '<', + 0, + get_sal_field, + set_sal_field, + encode_msalp32, + decode_msalp32, + 0, + 0 +}; + +static xtensa_operand_internal liuimm6_operand = { + "l", + '<', + 1, + get_imm6_field, + set_imm6_field, + encode_uimm6, + decode_uimm6, + do_reloc_l, + undo_reloc_l, +}; + +static xtensa_operand_internal iiuimm8x4_operand = { + "i", + '<', + 0, + get_imm8_field, + set_imm8_field, + encode_uimm8x4, + decode_uimm8x4, + 0, + 0 +}; + +static xtensa_operand_internal lisoffset_operand = { + "l", + '<', + 1, + get_offset_field, + set_offset_field, + encode_soffset, + decode_soffset, + do_reloc_l, + undo_reloc_l, +}; + +static xtensa_operand_internal iisimm7_operand = { + "i", + '<', + 0, + get_imm7_field, + set_imm7_field, + encode_simm7, + decode_simm7, + 0, + 0 +}; + +static xtensa_operand_internal ais_operand = { + "a", + '<', + 0, + get_s_field, + set_s_field, + encode_s, + decode_s, + 0, + 0 +}; + +static xtensa_operand_internal liuimm8_operand = { + "l", + '<', + 1, + get_imm8_field, + set_imm8_field, + encode_uimm8, + decode_uimm8, + do_reloc_l, + undo_reloc_l, +}; + +static xtensa_operand_internal ait_operand = { + "a", + '<', + 0, + get_t_field, + set_t_field, + encode_t, + decode_t, + 0, + 0 +}; + +static xtensa_operand_internal iisimm8_operand = { + "i", + '<', + 0, + get_imm8_field, + set_imm8_field, + encode_simm8, + decode_simm8, + 0, + 0 +}; + +static xtensa_operand_internal aor_operand = { + "a", + '>', + 0, + get_r_field, + set_r_field, + encode_r, + decode_r, + 0, + 0 +}; + +static xtensa_operand_internal aos_operand = { + "a", + '>', + 0, + get_s_field, + set_s_field, + encode_s, + decode_s, + 0, + 0 +}; + +static xtensa_operand_internal aot_operand = { + "a", + '>', + 0, + get_t_field, + set_t_field, + encode_t, + decode_t, + 0, + 0 +}; + +static xtensa_iclass_internal nopn_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *movi_operand_list[] = { + &aot_operand, + &iisimm12b_operand +}; + +static xtensa_iclass_internal movi_iclass = { + 2, + &movi_operand_list[0] +}; + +static xtensa_operand_internal *bsi8u_operand_list[] = { + &ais_operand, + &iib4constu_operand, + &lisimm8_operand +}; + +static xtensa_iclass_internal bsi8u_iclass = { + 3, + &bsi8u_operand_list[0] +}; + +static xtensa_operand_internal *itlb_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal itlb_iclass = { + 1, + &itlb_operand_list[0] +}; + +static xtensa_operand_internal *shiftst_operand_list[] = { + &aor_operand, + &ais_operand, + &ait_operand +}; + +static xtensa_iclass_internal shiftst_iclass = { + 3, + &shiftst_operand_list[0] +}; + +static xtensa_operand_internal *l32r_operand_list[] = { + &aot_operand, + &riuimm16x4_operand +}; + +static xtensa_iclass_internal l32r_iclass = { + 2, + &l32r_operand_list[0] +}; + +static xtensa_iclass_internal rfe_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *wait_operand_list[] = { + &iis_operand +}; + +static xtensa_iclass_internal wait_iclass = { + 1, + &wait_operand_list[0] +}; + +static xtensa_operand_internal *rfi_operand_list[] = { + &iis_operand +}; + +static xtensa_iclass_internal rfi_iclass = { + 1, + &rfi_operand_list[0] +}; + +static xtensa_operand_internal *movz_operand_list[] = { + &amr_operand, + &ais_operand, + &ait_operand +}; + +static xtensa_iclass_internal movz_iclass = { + 3, + &movz_operand_list[0] +}; + +static xtensa_operand_internal *callx_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal callx_iclass = { + 1, + &callx_operand_list[0] +}; + +static xtensa_operand_internal *mov_n_operand_list[] = { + &aot_operand, + &ais_operand +}; + +static xtensa_iclass_internal mov_n_iclass = { + 2, + &mov_n_operand_list[0] +}; + +static xtensa_operand_internal *loadi4_operand_list[] = { + &aot_operand, + &ais_operand, + &iilsi4x4_operand +}; + +static xtensa_iclass_internal loadi4_iclass = { + 3, + &loadi4_operand_list[0] +}; + +static xtensa_operand_internal *exti_operand_list[] = { + &aor_operand, + &ait_operand, + &iisae_operand, + &iiop2p1_operand +}; + +static xtensa_iclass_internal exti_iclass = { + 4, + &exti_operand_list[0] +}; + +static xtensa_operand_internal *break_operand_list[] = { + &iis_operand, + &iit_operand +}; + +static xtensa_iclass_internal break_iclass = { + 2, + &break_operand_list[0] +}; + +static xtensa_operand_internal *slli_operand_list[] = { + &aor_operand, + &ais_operand, + &iimsalp32_operand +}; + +static xtensa_iclass_internal slli_iclass = { + 3, + &slli_operand_list[0] +}; + +static xtensa_operand_internal *s16i_operand_list[] = { + &ait_operand, + &ais_operand, + &iiuimm8x2_operand +}; + +static xtensa_iclass_internal s16i_iclass = { + 3, + &s16i_operand_list[0] +}; + +static xtensa_operand_internal *call_operand_list[] = { + &lisoffsetx4_operand +}; + +static xtensa_iclass_internal call_iclass = { + 1, + &call_operand_list[0] +}; + +static xtensa_operand_internal *shifts_operand_list[] = { + &aor_operand, + &ais_operand +}; + +static xtensa_iclass_internal shifts_iclass = { + 2, + &shifts_operand_list[0] +}; + +static xtensa_operand_internal *shiftt_operand_list[] = { + &aor_operand, + &ait_operand +}; + +static xtensa_iclass_internal shiftt_iclass = { + 2, + &shiftt_operand_list[0] +}; + +static xtensa_operand_internal *rotw_operand_list[] = { + &iisimm4_operand +}; + +static xtensa_iclass_internal rotw_iclass = { + 1, + &rotw_operand_list[0] +}; + +static xtensa_operand_internal *addsub_operand_list[] = { + &aor_operand, + &ais_operand, + &ait_operand +}; + +static xtensa_iclass_internal addsub_iclass = { + 3, + &addsub_operand_list[0] +}; + +static xtensa_operand_internal *l8i_operand_list[] = { + &aot_operand, + &ais_operand, + &iiuimm8_operand +}; + +static xtensa_iclass_internal l8i_iclass = { + 3, + &l8i_operand_list[0] +}; + +static xtensa_operand_internal *sari_operand_list[] = { + &iisas_operand +}; + +static xtensa_iclass_internal sari_iclass = { + 1, + &sari_operand_list[0] +}; + +static xtensa_operand_internal *xsr_operand_list[] = { + &abt_operand, + &iisr_operand +}; + +static xtensa_iclass_internal xsr_iclass = { + 2, + &xsr_operand_list[0] +}; + +static xtensa_operand_internal *rsil_operand_list[] = { + &aot_operand, + &iis_operand +}; + +static xtensa_iclass_internal rsil_iclass = { + 2, + &rsil_operand_list[0] +}; + +static xtensa_operand_internal *bst8_operand_list[] = { + &ais_operand, + &ait_operand, + &lisimm8_operand +}; + +static xtensa_iclass_internal bst8_iclass = { + 3, + &bst8_operand_list[0] +}; + +static xtensa_operand_internal *addi_operand_list[] = { + &aot_operand, + &ais_operand, + &iisimm8_operand +}; + +static xtensa_iclass_internal addi_iclass = { + 3, + &addi_operand_list[0] +}; + +static xtensa_operand_internal *callx12_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal callx12_iclass = { + 1, + &callx12_operand_list[0] +}; + +static xtensa_operand_internal *bsi8_operand_list[] = { + &ais_operand, + &iib4const_operand, + &lisimm8_operand +}; + +static xtensa_iclass_internal bsi8_iclass = { + 3, + &bsi8_operand_list[0] +}; + +static xtensa_operand_internal *jumpx_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal jumpx_iclass = { + 1, + &jumpx_operand_list[0] +}; + +static xtensa_iclass_internal retn_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *nsa_operand_list[] = { + &aot_operand, + &ais_operand +}; + +static xtensa_iclass_internal nsa_iclass = { + 2, + &nsa_operand_list[0] +}; + +static xtensa_operand_internal *storei4_operand_list[] = { + &ait_operand, + &ais_operand, + &iilsi4x4_operand +}; + +static xtensa_iclass_internal storei4_iclass = { + 3, + &storei4_operand_list[0] +}; + +static xtensa_operand_internal *wtlb_operand_list[] = { + &ait_operand, + &ais_operand +}; + +static xtensa_iclass_internal wtlb_iclass = { + 2, + &wtlb_operand_list[0] +}; + +static xtensa_operand_internal *dce_operand_list[] = { + &ais_operand, + &iiuimm4x16_operand +}; + +static xtensa_iclass_internal dce_iclass = { + 2, + &dce_operand_list[0] +}; + +static xtensa_operand_internal *l16i_operand_list[] = { + &aot_operand, + &ais_operand, + &iiuimm8x2_operand +}; + +static xtensa_iclass_internal l16i_iclass = { + 3, + &l16i_operand_list[0] +}; + +static xtensa_operand_internal *callx4_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal callx4_iclass = { + 1, + &callx4_operand_list[0] +}; + +static xtensa_operand_internal *callx8_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal callx8_iclass = { + 1, + &callx8_operand_list[0] +}; + +static xtensa_operand_internal *movsp_operand_list[] = { + &aot_operand, + &ais_operand +}; + +static xtensa_iclass_internal movsp_iclass = { + 2, + &movsp_operand_list[0] +}; + +static xtensa_operand_internal *wsr_operand_list[] = { + &ait_operand, + &iisr_operand +}; + +static xtensa_iclass_internal wsr_iclass = { + 2, + &wsr_operand_list[0] +}; + +static xtensa_operand_internal *call12_operand_list[] = { + &lisoffsetx4_operand +}; + +static xtensa_iclass_internal call12_iclass = { + 1, + &call12_operand_list[0] +}; + +static xtensa_operand_internal *call4_operand_list[] = { + &lisoffsetx4_operand +}; + +static xtensa_iclass_internal call4_iclass = { + 1, + &call4_operand_list[0] +}; + +static xtensa_operand_internal *addmi_operand_list[] = { + &aot_operand, + &ais_operand, + &iisimm8x256_operand +}; + +static xtensa_iclass_internal addmi_iclass = { + 3, + &addmi_operand_list[0] +}; + +static xtensa_operand_internal *bit_operand_list[] = { + &aor_operand, + &ais_operand, + &ait_operand +}; + +static xtensa_iclass_internal bit_iclass = { + 3, + &bit_operand_list[0] +}; + +static xtensa_operand_internal *call8_operand_list[] = { + &lisoffsetx4_operand +}; + +static xtensa_iclass_internal call8_iclass = { + 1, + &call8_operand_list[0] +}; + +static xtensa_iclass_internal itlba_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *break_n_operand_list[] = { + &iis_operand +}; + +static xtensa_iclass_internal break_n_iclass = { + 1, + &break_n_operand_list[0] +}; + +static xtensa_operand_internal *sar_operand_list[] = { + &ais_operand +}; + +static xtensa_iclass_internal sar_iclass = { + 1, + &sar_operand_list[0] +}; + +static xtensa_operand_internal *s32e_operand_list[] = { + &ait_operand, + &ais_operand, + &iinimm4x2_operand +}; + +static xtensa_iclass_internal s32e_iclass = { + 3, + &s32e_operand_list[0] +}; + +static xtensa_operand_internal *bz6_operand_list[] = { + &ais_operand, + &liuimm6_operand +}; + +static xtensa_iclass_internal bz6_iclass = { + 2, + &bz6_operand_list[0] +}; + +static xtensa_operand_internal *loop_operand_list[] = { + &ais_operand, + &liuimm8_operand +}; + +static xtensa_iclass_internal loop_iclass = { + 2, + &loop_operand_list[0] +}; + +static xtensa_operand_internal *rsr_operand_list[] = { + &aot_operand, + &iisr_operand +}; + +static xtensa_iclass_internal rsr_iclass = { + 2, + &rsr_operand_list[0] +}; + +static xtensa_operand_internal *icache_operand_list[] = { + &ais_operand, + &iiuimm8x4_operand +}; + +static xtensa_iclass_internal icache_iclass = { + 2, + &icache_operand_list[0] +}; + +static xtensa_operand_internal *s8i_operand_list[] = { + &ait_operand, + &ais_operand, + &iiuimm8_operand +}; + +static xtensa_iclass_internal s8i_iclass = { + 3, + &s8i_operand_list[0] +}; + +static xtensa_iclass_internal return_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *dcache_operand_list[] = { + &ais_operand, + &iiuimm8x4_operand +}; + +static xtensa_iclass_internal dcache_iclass = { + 2, + &dcache_operand_list[0] +}; + +static xtensa_operand_internal *s32i_operand_list[] = { + &ait_operand, + &ais_operand, + &iiuimm8x4_operand +}; + +static xtensa_iclass_internal s32i_iclass = { + 3, + &s32i_operand_list[0] +}; + +static xtensa_operand_internal *jump_operand_list[] = { + &lisoffset_operand +}; + +static xtensa_iclass_internal jump_iclass = { + 1, + &jump_operand_list[0] +}; + +static xtensa_operand_internal *addi_n_operand_list[] = { + &aor_operand, + &ais_operand, + &iiai4const_operand +}; + +static xtensa_iclass_internal addi_n_iclass = { + 3, + &addi_n_operand_list[0] +}; + +static xtensa_iclass_internal sync_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *neg_operand_list[] = { + &aor_operand, + &ait_operand +}; + +static xtensa_iclass_internal neg_iclass = { + 2, + &neg_operand_list[0] +}; + +static xtensa_iclass_internal syscall_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *bsz12_operand_list[] = { + &ais_operand, + &lisimm12_operand +}; + +static xtensa_iclass_internal bsz12_iclass = { + 2, + &bsz12_operand_list[0] +}; + +static xtensa_iclass_internal excw_iclass = { + 0, + 0 +}; + +static xtensa_operand_internal *movi_n_operand_list[] = { + &aos_operand, + &iisimm7_operand +}; + +static xtensa_iclass_internal movi_n_iclass = { + 2, + &movi_n_operand_list[0] +}; + +static xtensa_operand_internal *rtlb_operand_list[] = { + &aot_operand, + &ais_operand +}; + +static xtensa_iclass_internal rtlb_iclass = { + 2, + &rtlb_operand_list[0] +}; + +static xtensa_operand_internal *actl_operand_list[] = { + &aot_operand, + &ais_operand +}; + +static xtensa_iclass_internal actl_iclass = { + 2, + &actl_operand_list[0] +}; + +static xtensa_operand_internal *srli_operand_list[] = { + &aor_operand, + &ait_operand, + &iis_operand +}; + +static xtensa_iclass_internal srli_iclass = { + 3, + &srli_operand_list[0] +}; + +static xtensa_operand_internal *bsi8b_operand_list[] = { + &ais_operand, + &iibbi_operand, + &lisimm8_operand +}; + +static xtensa_iclass_internal bsi8b_iclass = { + 3, + &bsi8b_operand_list[0] +}; + +static xtensa_operand_internal *acts_operand_list[] = { + &ait_operand, + &ais_operand +}; + +static xtensa_iclass_internal acts_iclass = { + 2, + &acts_operand_list[0] +}; + +static xtensa_operand_internal *add_n_operand_list[] = { + &aor_operand, + &ais_operand, + &ait_operand +}; + +static xtensa_iclass_internal add_n_iclass = { + 3, + &add_n_operand_list[0] +}; + +static xtensa_operand_internal *srai_operand_list[] = { + &aor_operand, + &ait_operand, + &iisar_operand +}; + +static xtensa_iclass_internal srai_iclass = { + 3, + &srai_operand_list[0] +}; + +static xtensa_operand_internal *entry_operand_list[] = { + &abs_operand, + &iiuimm12x8_operand +}; + +static xtensa_iclass_internal entry_iclass = { + 2, + &entry_operand_list[0] +}; + +static xtensa_operand_internal *l32e_operand_list[] = { + &aot_operand, + &ais_operand, + &iinimm4x2_operand +}; + +static xtensa_iclass_internal l32e_iclass = { + 3, + &l32e_operand_list[0] +}; + +static xtensa_operand_internal *dpf_operand_list[] = { + &ais_operand, + &iiuimm8x4_operand +}; + +static xtensa_iclass_internal dpf_iclass = { + 2, + &dpf_operand_list[0] +}; + +static xtensa_operand_internal *l32i_operand_list[] = { + &aot_operand, + &ais_operand, + &iiuimm8x4_operand +}; + +static xtensa_iclass_internal l32i_iclass = { + 3, + &l32i_operand_list[0] +}; + +static xtensa_insnbuf abs_template (void); +static xtensa_insnbuf add_template (void); +static xtensa_insnbuf add_n_template (void); +static xtensa_insnbuf addi_template (void); +static xtensa_insnbuf addi_n_template (void); +static xtensa_insnbuf addmi_template (void); +static xtensa_insnbuf addx2_template (void); +static xtensa_insnbuf addx4_template (void); +static xtensa_insnbuf addx8_template (void); +static xtensa_insnbuf and_template (void); +static xtensa_insnbuf ball_template (void); +static xtensa_insnbuf bany_template (void); +static xtensa_insnbuf bbc_template (void); +static xtensa_insnbuf bbci_template (void); +static xtensa_insnbuf bbs_template (void); +static xtensa_insnbuf bbsi_template (void); +static xtensa_insnbuf beq_template (void); +static xtensa_insnbuf beqi_template (void); +static xtensa_insnbuf beqz_template (void); +static xtensa_insnbuf beqz_n_template (void); +static xtensa_insnbuf bge_template (void); +static xtensa_insnbuf bgei_template (void); +static xtensa_insnbuf bgeu_template (void); +static xtensa_insnbuf bgeui_template (void); +static xtensa_insnbuf bgez_template (void); +static xtensa_insnbuf blt_template (void); +static xtensa_insnbuf blti_template (void); +static xtensa_insnbuf bltu_template (void); +static xtensa_insnbuf bltui_template (void); +static xtensa_insnbuf bltz_template (void); +static xtensa_insnbuf bnall_template (void); +static xtensa_insnbuf bne_template (void); +static xtensa_insnbuf bnei_template (void); +static xtensa_insnbuf bnez_template (void); +static xtensa_insnbuf bnez_n_template (void); +static xtensa_insnbuf bnone_template (void); +static xtensa_insnbuf break_template (void); +static xtensa_insnbuf break_n_template (void); +static xtensa_insnbuf call0_template (void); +static xtensa_insnbuf call12_template (void); +static xtensa_insnbuf call4_template (void); +static xtensa_insnbuf call8_template (void); +static xtensa_insnbuf callx0_template (void); +static xtensa_insnbuf callx12_template (void); +static xtensa_insnbuf callx4_template (void); +static xtensa_insnbuf callx8_template (void); +static xtensa_insnbuf dhi_template (void); +static xtensa_insnbuf dhwb_template (void); +static xtensa_insnbuf dhwbi_template (void); +static xtensa_insnbuf dii_template (void); +static xtensa_insnbuf diwb_template (void); +static xtensa_insnbuf diwbi_template (void); +static xtensa_insnbuf dpfr_template (void); +static xtensa_insnbuf dpfro_template (void); +static xtensa_insnbuf dpfw_template (void); +static xtensa_insnbuf dpfwo_template (void); +static xtensa_insnbuf dsync_template (void); +static xtensa_insnbuf entry_template (void); +static xtensa_insnbuf esync_template (void); +static xtensa_insnbuf excw_template (void); +static xtensa_insnbuf extui_template (void); +static xtensa_insnbuf idtlb_template (void); +static xtensa_insnbuf idtlba_template (void); +static xtensa_insnbuf ihi_template (void); +static xtensa_insnbuf iii_template (void); +static xtensa_insnbuf iitlb_template (void); +static xtensa_insnbuf iitlba_template (void); +static xtensa_insnbuf ipf_template (void); +static xtensa_insnbuf isync_template (void); +static xtensa_insnbuf j_template (void); +static xtensa_insnbuf jx_template (void); +static xtensa_insnbuf l16si_template (void); +static xtensa_insnbuf l16ui_template (void); +static xtensa_insnbuf l32e_template (void); +static xtensa_insnbuf l32i_template (void); +static xtensa_insnbuf l32i_n_template (void); +static xtensa_insnbuf l32r_template (void); +static xtensa_insnbuf l8ui_template (void); +static xtensa_insnbuf ldct_template (void); +static xtensa_insnbuf lict_template (void); +static xtensa_insnbuf licw_template (void); +static xtensa_insnbuf loop_template (void); +static xtensa_insnbuf loopgtz_template (void); +static xtensa_insnbuf loopnez_template (void); +static xtensa_insnbuf memw_template (void); +static xtensa_insnbuf mov_n_template (void); +static xtensa_insnbuf moveqz_template (void); +static xtensa_insnbuf movgez_template (void); +static xtensa_insnbuf movi_template (void); +static xtensa_insnbuf movi_n_template (void); +static xtensa_insnbuf movltz_template (void); +static xtensa_insnbuf movnez_template (void); +static xtensa_insnbuf movsp_template (void); +static xtensa_insnbuf neg_template (void); +static xtensa_insnbuf nop_n_template (void); +static xtensa_insnbuf nsa_template (void); +static xtensa_insnbuf nsau_template (void); +static xtensa_insnbuf or_template (void); +static xtensa_insnbuf pdtlb_template (void); +static xtensa_insnbuf pitlb_template (void); +static xtensa_insnbuf rdtlb0_template (void); +static xtensa_insnbuf rdtlb1_template (void); +static xtensa_insnbuf ret_template (void); +static xtensa_insnbuf ret_n_template (void); +static xtensa_insnbuf retw_template (void); +static xtensa_insnbuf retw_n_template (void); +static xtensa_insnbuf rfde_template (void); +static xtensa_insnbuf rfe_template (void); +static xtensa_insnbuf rfi_template (void); +static xtensa_insnbuf rfwo_template (void); +static xtensa_insnbuf rfwu_template (void); +static xtensa_insnbuf ritlb0_template (void); +static xtensa_insnbuf ritlb1_template (void); +static xtensa_insnbuf rotw_template (void); +static xtensa_insnbuf rsil_template (void); +static xtensa_insnbuf rsr_template (void); +static xtensa_insnbuf rsync_template (void); +static xtensa_insnbuf s16i_template (void); +static xtensa_insnbuf s32e_template (void); +static xtensa_insnbuf s32i_template (void); +static xtensa_insnbuf s32i_n_template (void); +static xtensa_insnbuf s8i_template (void); +static xtensa_insnbuf sdct_template (void); +static xtensa_insnbuf sict_template (void); +static xtensa_insnbuf sicw_template (void); +static xtensa_insnbuf simcall_template (void); +static xtensa_insnbuf sll_template (void); +static xtensa_insnbuf slli_template (void); +static xtensa_insnbuf sra_template (void); +static xtensa_insnbuf srai_template (void); +static xtensa_insnbuf src_template (void); +static xtensa_insnbuf srl_template (void); +static xtensa_insnbuf srli_template (void); +static xtensa_insnbuf ssa8b_template (void); +static xtensa_insnbuf ssa8l_template (void); +static xtensa_insnbuf ssai_template (void); +static xtensa_insnbuf ssl_template (void); +static xtensa_insnbuf ssr_template (void); +static xtensa_insnbuf sub_template (void); +static xtensa_insnbuf subx2_template (void); +static xtensa_insnbuf subx4_template (void); +static xtensa_insnbuf subx8_template (void); +static xtensa_insnbuf syscall_template (void); +static xtensa_insnbuf waiti_template (void); +static xtensa_insnbuf wdtlb_template (void); +static xtensa_insnbuf witlb_template (void); +static xtensa_insnbuf wsr_template (void); +static xtensa_insnbuf xor_template (void); +static xtensa_insnbuf xsr_template (void); + +static xtensa_insnbuf +abs_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00001006 }; + return &template[0]; +} + +static xtensa_insnbuf +add_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000008 }; + return &template[0]; +} + +static xtensa_insnbuf +add_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00a00000 }; + return &template[0]; +} + +static xtensa_insnbuf +addi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200c00 }; + return &template[0]; +} + +static xtensa_insnbuf +addi_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00b00000 }; + return &template[0]; +} + +static xtensa_insnbuf +addmi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200d00 }; + return &template[0]; +} + +static xtensa_insnbuf +addx2_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000009 }; + return &template[0]; +} + +static xtensa_insnbuf +addx4_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000a }; + return &template[0]; +} + +static xtensa_insnbuf +addx8_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000b }; + return &template[0]; +} + +static xtensa_insnbuf +and_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000001 }; + return &template[0]; +} + +static xtensa_insnbuf +ball_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700400 }; + return &template[0]; +} + +static xtensa_insnbuf +bany_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700800 }; + return &template[0]; +} + +static xtensa_insnbuf +bbc_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700500 }; + return &template[0]; +} + +static xtensa_insnbuf +bbci_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700600 }; + return &template[0]; +} + +static xtensa_insnbuf +bbs_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700d00 }; + return &template[0]; +} + +static xtensa_insnbuf +bbsi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700e00 }; + return &template[0]; +} + +static xtensa_insnbuf +beq_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700100 }; + return &template[0]; +} + +static xtensa_insnbuf +beqi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00680000 }; + return &template[0]; +} + +static xtensa_insnbuf +beqz_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00640000 }; + return &template[0]; +} + +static xtensa_insnbuf +beqz_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00c80000 }; + return &template[0]; +} + +static xtensa_insnbuf +bge_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700a00 }; + return &template[0]; +} + +static xtensa_insnbuf +bgei_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006b0000 }; + return &template[0]; +} + +static xtensa_insnbuf +bgeu_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700b00 }; + return &template[0]; +} + +static xtensa_insnbuf +bgeui_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006f0000 }; + return &template[0]; +} + +static xtensa_insnbuf +bgez_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00670000 }; + return &template[0]; +} + +static xtensa_insnbuf +blt_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700200 }; + return &template[0]; +} + +static xtensa_insnbuf +blti_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006a0000 }; + return &template[0]; +} + +static xtensa_insnbuf +bltu_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700300 }; + return &template[0]; +} + +static xtensa_insnbuf +bltui_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006e0000 }; + return &template[0]; +} + +static xtensa_insnbuf +bltz_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00660000 }; + return &template[0]; +} + +static xtensa_insnbuf +bnall_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700c00 }; + return &template[0]; +} + +static xtensa_insnbuf +bne_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700900 }; + return &template[0]; +} + +static xtensa_insnbuf +bnei_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00690000 }; + return &template[0]; +} + +static xtensa_insnbuf +bnez_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00650000 }; + return &template[0]; +} + +static xtensa_insnbuf +bnez_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00cc0000 }; + return &template[0]; +} + +static xtensa_insnbuf +bnone_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00700000 }; + return &template[0]; +} + +static xtensa_insnbuf +break_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000400 }; + return &template[0]; +} + +static xtensa_insnbuf +break_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00d20f00 }; + return &template[0]; +} + +static xtensa_insnbuf +call0_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00500000 }; + return &template[0]; +} + +static xtensa_insnbuf +call12_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x005c0000 }; + return &template[0]; +} + +static xtensa_insnbuf +call4_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00540000 }; + return &template[0]; +} + +static xtensa_insnbuf +call8_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00580000 }; + return &template[0]; +} + +static xtensa_insnbuf +callx0_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00030000 }; + return &template[0]; +} + +static xtensa_insnbuf +callx12_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x000f0000 }; + return &template[0]; +} + +static xtensa_insnbuf +callx4_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00070000 }; + return &template[0]; +} + +static xtensa_insnbuf +callx8_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x000b0000 }; + return &template[0]; +} + +static xtensa_insnbuf +dhi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00260700 }; + return &template[0]; +} + +static xtensa_insnbuf +dhwb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00240700 }; + return &template[0]; +} + +static xtensa_insnbuf +dhwbi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00250700 }; + return &template[0]; +} + +static xtensa_insnbuf +dii_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00270700 }; + return &template[0]; +} + +static xtensa_insnbuf +diwb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00280740 }; + return &template[0]; +} + +static xtensa_insnbuf +diwbi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00280750 }; + return &template[0]; +} + +static xtensa_insnbuf +dpfr_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200700 }; + return &template[0]; +} + +static xtensa_insnbuf +dpfro_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00220700 }; + return &template[0]; +} + +static xtensa_insnbuf +dpfw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00210700 }; + return &template[0]; +} + +static xtensa_insnbuf +dpfwo_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00230700 }; + return &template[0]; +} + +static xtensa_insnbuf +dsync_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00030200 }; + return &template[0]; +} + +static xtensa_insnbuf +entry_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006c0000 }; + return &template[0]; +} + +static xtensa_insnbuf +esync_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00020200 }; + return &template[0]; +} + +static xtensa_insnbuf +excw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00080200 }; + return &template[0]; +} + +static xtensa_insnbuf +extui_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000040 }; + return &template[0]; +} + +static xtensa_insnbuf +idtlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000c05 }; + return &template[0]; +} + +static xtensa_insnbuf +idtlba_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000805 }; + return &template[0]; +} + +static xtensa_insnbuf +ihi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x002e0700 }; + return &template[0]; +} + +static xtensa_insnbuf +iii_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x002f0700 }; + return &template[0]; +} + +static xtensa_insnbuf +iitlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000405 }; + return &template[0]; +} + +static xtensa_insnbuf +iitlba_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000005 }; + return &template[0]; +} + +static xtensa_insnbuf +ipf_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x002c0700 }; + return &template[0]; +} + +static xtensa_insnbuf +isync_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000200 }; + return &template[0]; +} + +static xtensa_insnbuf +j_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00600000 }; + return &template[0]; +} + +static xtensa_insnbuf +jx_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x000a0000 }; + return &template[0]; +} + +static xtensa_insnbuf +l16si_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200900 }; + return &template[0]; +} + +static xtensa_insnbuf +l16ui_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200100 }; + return &template[0]; +} + +static xtensa_insnbuf +l32e_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000090 }; + return &template[0]; +} + +static xtensa_insnbuf +l32i_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200200 }; + return &template[0]; +} + +static xtensa_insnbuf +l32i_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00800000 }; + return &template[0]; +} + +static xtensa_insnbuf +l32r_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00100000 }; + return &template[0]; +} + +static xtensa_insnbuf +l8ui_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200000 }; + return &template[0]; +} + +static xtensa_insnbuf +ldct_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000081f }; + return &template[0]; +} + +static xtensa_insnbuf +lict_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000001f }; + return &template[0]; +} + +static xtensa_insnbuf +licw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000021f }; + return &template[0]; +} + +static xtensa_insnbuf +loop_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006d0800 }; + return &template[0]; +} + +static xtensa_insnbuf +loopgtz_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006d0a00 }; + return &template[0]; +} + +static xtensa_insnbuf +loopnez_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x006d0900 }; + return &template[0]; +} + +static xtensa_insnbuf +memw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x000c0200 }; + return &template[0]; +} + +static xtensa_insnbuf +mov_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00d00000 }; + return &template[0]; +} + +static xtensa_insnbuf +moveqz_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000038 }; + return &template[0]; +} + +static xtensa_insnbuf +movgez_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000003b }; + return &template[0]; +} + +static xtensa_insnbuf +movi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200a00 }; + return &template[0]; +} + +static xtensa_insnbuf +movi_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00c00000 }; + return &template[0]; +} + +static xtensa_insnbuf +movltz_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000003a }; + return &template[0]; +} + +static xtensa_insnbuf +movnez_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000039 }; + return &template[0]; +} + +static xtensa_insnbuf +movsp_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000100 }; + return &template[0]; +} + +static xtensa_insnbuf +neg_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000006 }; + return &template[0]; +} + +static xtensa_insnbuf +nop_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00d30f00 }; + return &template[0]; +} + +static xtensa_insnbuf +nsa_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000e04 }; + return &template[0]; +} + +static xtensa_insnbuf +nsau_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000f04 }; + return &template[0]; +} + +static xtensa_insnbuf +or_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000002 }; + return &template[0]; +} + +static xtensa_insnbuf +pdtlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000d05 }; + return &template[0]; +} + +static xtensa_insnbuf +pitlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000505 }; + return &template[0]; +} + +static xtensa_insnbuf +rdtlb0_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000b05 }; + return &template[0]; +} + +static xtensa_insnbuf +rdtlb1_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000f05 }; + return &template[0]; +} + +static xtensa_insnbuf +ret_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00020000 }; + return &template[0]; +} + +static xtensa_insnbuf +ret_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00d00f00 }; + return &template[0]; +} + +static xtensa_insnbuf +retw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00060000 }; + return &template[0]; +} + +static xtensa_insnbuf +retw_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00d10f00 }; + return &template[0]; +} + +static xtensa_insnbuf +rfde_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00002300 }; + return &template[0]; +} + +static xtensa_insnbuf +rfe_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000300 }; + return &template[0]; +} + +static xtensa_insnbuf +rfi_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00010300 }; + return &template[0]; +} + +static xtensa_insnbuf +rfwo_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00004300 }; + return &template[0]; +} + +static xtensa_insnbuf +rfwu_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00005300 }; + return &template[0]; +} + +static xtensa_insnbuf +ritlb0_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000305 }; + return &template[0]; +} + +static xtensa_insnbuf +ritlb1_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000705 }; + return &template[0]; +} + +static xtensa_insnbuf +rotw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000804 }; + return &template[0]; +} + +static xtensa_insnbuf +rsil_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000600 }; + return &template[0]; +} + +static xtensa_insnbuf +rsr_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000030 }; + return &template[0]; +} + +static xtensa_insnbuf +rsync_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00010200 }; + return &template[0]; +} + +static xtensa_insnbuf +s16i_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200500 }; + return &template[0]; +} + +static xtensa_insnbuf +s32e_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000094 }; + return &template[0]; +} + +static xtensa_insnbuf +s32i_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200600 }; + return &template[0]; +} + +static xtensa_insnbuf +s32i_n_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00900000 }; + return &template[0]; +} + +static xtensa_insnbuf +s8i_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00200400 }; + return &template[0]; +} + +static xtensa_insnbuf +sdct_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000091f }; + return &template[0]; +} + +static xtensa_insnbuf +sict_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000011f }; + return &template[0]; +} + +static xtensa_insnbuf +sicw_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000031f }; + return &template[0]; +} + +static xtensa_insnbuf +simcall_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00001500 }; + return &template[0]; +} + +static xtensa_insnbuf +sll_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000001a }; + return &template[0]; +} + +static xtensa_insnbuf +slli_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000010 }; + return &template[0]; +} + +static xtensa_insnbuf +sra_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000001b }; + return &template[0]; +} + +static xtensa_insnbuf +srai_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000012 }; + return &template[0]; +} + +static xtensa_insnbuf +src_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000018 }; + return &template[0]; +} + +static xtensa_insnbuf +srl_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000019 }; + return &template[0]; +} + +static xtensa_insnbuf +srli_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000014 }; + return &template[0]; +} + +static xtensa_insnbuf +ssa8b_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000304 }; + return &template[0]; +} + +static xtensa_insnbuf +ssa8l_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000204 }; + return &template[0]; +} + +static xtensa_insnbuf +ssai_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000404 }; + return &template[0]; +} + +static xtensa_insnbuf +ssl_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000104 }; + return &template[0]; +} + +static xtensa_insnbuf +ssr_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000004 }; + return &template[0]; +} + +static xtensa_insnbuf +sub_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000c }; + return &template[0]; +} + +static xtensa_insnbuf +subx2_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000d }; + return &template[0]; +} + +static xtensa_insnbuf +subx4_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000e }; + return &template[0]; +} + +static xtensa_insnbuf +subx8_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x0000000f }; + return &template[0]; +} + +static xtensa_insnbuf +syscall_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000500 }; + return &template[0]; +} + +static xtensa_insnbuf +waiti_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000700 }; + return &template[0]; +} + +static xtensa_insnbuf +wdtlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000e05 }; + return &template[0]; +} + +static xtensa_insnbuf +witlb_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000605 }; + return &template[0]; +} + +static xtensa_insnbuf +wsr_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000031 }; + return &template[0]; +} + +static xtensa_insnbuf +xor_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000003 }; + return &template[0]; +} + +static xtensa_insnbuf +xsr_template (void) +{ + static xtensa_insnbuf_word template[] = { 0x00000016 }; + return &template[0]; +} + +static xtensa_opcode_internal abs_opcode = { + "abs", + 3, + abs_template, + &neg_iclass +}; + +static xtensa_opcode_internal add_opcode = { + "add", + 3, + add_template, + &addsub_iclass +}; + +static xtensa_opcode_internal add_n_opcode = { + "add.n", + 2, + add_n_template, + &add_n_iclass +}; + +static xtensa_opcode_internal addi_opcode = { + "addi", + 3, + addi_template, + &addi_iclass +}; + +static xtensa_opcode_internal addi_n_opcode = { + "addi.n", + 2, + addi_n_template, + &addi_n_iclass +}; + +static xtensa_opcode_internal addmi_opcode = { + "addmi", + 3, + addmi_template, + &addmi_iclass +}; + +static xtensa_opcode_internal addx2_opcode = { + "addx2", + 3, + addx2_template, + &addsub_iclass +}; + +static xtensa_opcode_internal addx4_opcode = { + "addx4", + 3, + addx4_template, + &addsub_iclass +}; + +static xtensa_opcode_internal addx8_opcode = { + "addx8", + 3, + addx8_template, + &addsub_iclass +}; + +static xtensa_opcode_internal and_opcode = { + "and", + 3, + and_template, + &bit_iclass +}; + +static xtensa_opcode_internal ball_opcode = { + "ball", + 3, + ball_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bany_opcode = { + "bany", + 3, + bany_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bbc_opcode = { + "bbc", + 3, + bbc_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bbci_opcode = { + "bbci", + 3, + bbci_template, + &bsi8b_iclass +}; + +static xtensa_opcode_internal bbs_opcode = { + "bbs", + 3, + bbs_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bbsi_opcode = { + "bbsi", + 3, + bbsi_template, + &bsi8b_iclass +}; + +static xtensa_opcode_internal beq_opcode = { + "beq", + 3, + beq_template, + &bst8_iclass +}; + +static xtensa_opcode_internal beqi_opcode = { + "beqi", + 3, + beqi_template, + &bsi8_iclass +}; + +static xtensa_opcode_internal beqz_opcode = { + "beqz", + 3, + beqz_template, + &bsz12_iclass +}; + +static xtensa_opcode_internal beqz_n_opcode = { + "beqz.n", + 2, + beqz_n_template, + &bz6_iclass +}; + +static xtensa_opcode_internal bge_opcode = { + "bge", + 3, + bge_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bgei_opcode = { + "bgei", + 3, + bgei_template, + &bsi8_iclass +}; + +static xtensa_opcode_internal bgeu_opcode = { + "bgeu", + 3, + bgeu_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bgeui_opcode = { + "bgeui", + 3, + bgeui_template, + &bsi8u_iclass +}; + +static xtensa_opcode_internal bgez_opcode = { + "bgez", + 3, + bgez_template, + &bsz12_iclass +}; + +static xtensa_opcode_internal blt_opcode = { + "blt", + 3, + blt_template, + &bst8_iclass +}; + +static xtensa_opcode_internal blti_opcode = { + "blti", + 3, + blti_template, + &bsi8_iclass +}; + +static xtensa_opcode_internal bltu_opcode = { + "bltu", + 3, + bltu_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bltui_opcode = { + "bltui", + 3, + bltui_template, + &bsi8u_iclass +}; + +static xtensa_opcode_internal bltz_opcode = { + "bltz", + 3, + bltz_template, + &bsz12_iclass +}; + +static xtensa_opcode_internal bnall_opcode = { + "bnall", + 3, + bnall_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bne_opcode = { + "bne", + 3, + bne_template, + &bst8_iclass +}; + +static xtensa_opcode_internal bnei_opcode = { + "bnei", + 3, + bnei_template, + &bsi8_iclass +}; + +static xtensa_opcode_internal bnez_opcode = { + "bnez", + 3, + bnez_template, + &bsz12_iclass +}; + +static xtensa_opcode_internal bnez_n_opcode = { + "bnez.n", + 2, + bnez_n_template, + &bz6_iclass +}; + +static xtensa_opcode_internal bnone_opcode = { + "bnone", + 3, + bnone_template, + &bst8_iclass +}; + +static xtensa_opcode_internal break_opcode = { + "break", + 3, + break_template, + &break_iclass +}; + +static xtensa_opcode_internal break_n_opcode = { + "break.n", + 2, + break_n_template, + &break_n_iclass +}; + +static xtensa_opcode_internal call0_opcode = { + "call0", + 3, + call0_template, + &call_iclass +}; + +static xtensa_opcode_internal call12_opcode = { + "call12", + 3, + call12_template, + &call12_iclass +}; + +static xtensa_opcode_internal call4_opcode = { + "call4", + 3, + call4_template, + &call4_iclass +}; + +static xtensa_opcode_internal call8_opcode = { + "call8", + 3, + call8_template, + &call8_iclass +}; + +static xtensa_opcode_internal callx0_opcode = { + "callx0", + 3, + callx0_template, + &callx_iclass +}; + +static xtensa_opcode_internal callx12_opcode = { + "callx12", + 3, + callx12_template, + &callx12_iclass +}; + +static xtensa_opcode_internal callx4_opcode = { + "callx4", + 3, + callx4_template, + &callx4_iclass +}; + +static xtensa_opcode_internal callx8_opcode = { + "callx8", + 3, + callx8_template, + &callx8_iclass +}; + +static xtensa_opcode_internal dhi_opcode = { + "dhi", + 3, + dhi_template, + &dcache_iclass +}; + +static xtensa_opcode_internal dhwb_opcode = { + "dhwb", + 3, + dhwb_template, + &dcache_iclass +}; + +static xtensa_opcode_internal dhwbi_opcode = { + "dhwbi", + 3, + dhwbi_template, + &dcache_iclass +}; + +static xtensa_opcode_internal dii_opcode = { + "dii", + 3, + dii_template, + &dcache_iclass +}; + +static xtensa_opcode_internal diwb_opcode = { + "diwb", + 3, + diwb_template, + &dce_iclass +}; + +static xtensa_opcode_internal diwbi_opcode = { + "diwbi", + 3, + diwbi_template, + &dce_iclass +}; + +static xtensa_opcode_internal dpfr_opcode = { + "dpfr", + 3, + dpfr_template, + &dpf_iclass +}; + +static xtensa_opcode_internal dpfro_opcode = { + "dpfro", + 3, + dpfro_template, + &dpf_iclass +}; + +static xtensa_opcode_internal dpfw_opcode = { + "dpfw", + 3, + dpfw_template, + &dpf_iclass +}; + +static xtensa_opcode_internal dpfwo_opcode = { + "dpfwo", + 3, + dpfwo_template, + &dpf_iclass +}; + +static xtensa_opcode_internal dsync_opcode = { + "dsync", + 3, + dsync_template, + &sync_iclass +}; + +static xtensa_opcode_internal entry_opcode = { + "entry", + 3, + entry_template, + &entry_iclass +}; + +static xtensa_opcode_internal esync_opcode = { + "esync", + 3, + esync_template, + &sync_iclass +}; + +static xtensa_opcode_internal excw_opcode = { + "excw", + 3, + excw_template, + &excw_iclass +}; + +static xtensa_opcode_internal extui_opcode = { + "extui", + 3, + extui_template, + &exti_iclass +}; + +static xtensa_opcode_internal idtlb_opcode = { + "idtlb", + 3, + idtlb_template, + &itlb_iclass +}; + +static xtensa_opcode_internal idtlba_opcode = { + "idtlba", + 3, + idtlba_template, + &itlba_iclass +}; + +static xtensa_opcode_internal ihi_opcode = { + "ihi", + 3, + ihi_template, + &icache_iclass +}; + +static xtensa_opcode_internal iii_opcode = { + "iii", + 3, + iii_template, + &icache_iclass +}; + +static xtensa_opcode_internal iitlb_opcode = { + "iitlb", + 3, + iitlb_template, + &itlb_iclass +}; + +static xtensa_opcode_internal iitlba_opcode = { + "iitlba", + 3, + iitlba_template, + &itlba_iclass +}; + +static xtensa_opcode_internal ipf_opcode = { + "ipf", + 3, + ipf_template, + &icache_iclass +}; + +static xtensa_opcode_internal isync_opcode = { + "isync", + 3, + isync_template, + &sync_iclass +}; + +static xtensa_opcode_internal j_opcode = { + "j", + 3, + j_template, + &jump_iclass +}; + +static xtensa_opcode_internal jx_opcode = { + "jx", + 3, + jx_template, + &jumpx_iclass +}; + +static xtensa_opcode_internal l16si_opcode = { + "l16si", + 3, + l16si_template, + &l16i_iclass +}; + +static xtensa_opcode_internal l16ui_opcode = { + "l16ui", + 3, + l16ui_template, + &l16i_iclass +}; + +static xtensa_opcode_internal l32e_opcode = { + "l32e", + 3, + l32e_template, + &l32e_iclass +}; + +static xtensa_opcode_internal l32i_opcode = { + "l32i", + 3, + l32i_template, + &l32i_iclass +}; + +static xtensa_opcode_internal l32i_n_opcode = { + "l32i.n", + 2, + l32i_n_template, + &loadi4_iclass +}; + +static xtensa_opcode_internal l32r_opcode = { + "l32r", + 3, + l32r_template, + &l32r_iclass +}; + +static xtensa_opcode_internal l8ui_opcode = { + "l8ui", + 3, + l8ui_template, + &l8i_iclass +}; + +static xtensa_opcode_internal ldct_opcode = { + "ldct", + 3, + ldct_template, + &actl_iclass +}; + +static xtensa_opcode_internal lict_opcode = { + "lict", + 3, + lict_template, + &actl_iclass +}; + +static xtensa_opcode_internal licw_opcode = { + "licw", + 3, + licw_template, + &actl_iclass +}; + +static xtensa_opcode_internal loop_opcode = { + "loop", + 3, + loop_template, + &loop_iclass +}; + +static xtensa_opcode_internal loopgtz_opcode = { + "loopgtz", + 3, + loopgtz_template, + &loop_iclass +}; + +static xtensa_opcode_internal loopnez_opcode = { + "loopnez", + 3, + loopnez_template, + &loop_iclass +}; + +static xtensa_opcode_internal memw_opcode = { + "memw", + 3, + memw_template, + &sync_iclass +}; + +static xtensa_opcode_internal mov_n_opcode = { + "mov.n", + 2, + mov_n_template, + &mov_n_iclass +}; + +static xtensa_opcode_internal moveqz_opcode = { + "moveqz", + 3, + moveqz_template, + &movz_iclass +}; + +static xtensa_opcode_internal movgez_opcode = { + "movgez", + 3, + movgez_template, + &movz_iclass +}; + +static xtensa_opcode_internal movi_opcode = { + "movi", + 3, + movi_template, + &movi_iclass +}; + +static xtensa_opcode_internal movi_n_opcode = { + "movi.n", + 2, + movi_n_template, + &movi_n_iclass +}; + +static xtensa_opcode_internal movltz_opcode = { + "movltz", + 3, + movltz_template, + &movz_iclass +}; + +static xtensa_opcode_internal movnez_opcode = { + "movnez", + 3, + movnez_template, + &movz_iclass +}; + +static xtensa_opcode_internal movsp_opcode = { + "movsp", + 3, + movsp_template, + &movsp_iclass +}; + +static xtensa_opcode_internal neg_opcode = { + "neg", + 3, + neg_template, + &neg_iclass +}; + +static xtensa_opcode_internal nop_n_opcode = { + "nop.n", + 2, + nop_n_template, + &nopn_iclass +}; + +static xtensa_opcode_internal nsa_opcode = { + "nsa", + 3, + nsa_template, + &nsa_iclass +}; + +static xtensa_opcode_internal nsau_opcode = { + "nsau", + 3, + nsau_template, + &nsa_iclass +}; + +static xtensa_opcode_internal or_opcode = { + "or", + 3, + or_template, + &bit_iclass +}; + +static xtensa_opcode_internal pdtlb_opcode = { + "pdtlb", + 3, + pdtlb_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal pitlb_opcode = { + "pitlb", + 3, + pitlb_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal rdtlb0_opcode = { + "rdtlb0", + 3, + rdtlb0_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal rdtlb1_opcode = { + "rdtlb1", + 3, + rdtlb1_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal ret_opcode = { + "ret", + 3, + ret_template, + &return_iclass +}; + +static xtensa_opcode_internal ret_n_opcode = { + "ret.n", + 2, + ret_n_template, + &retn_iclass +}; + +static xtensa_opcode_internal retw_opcode = { + "retw", + 3, + retw_template, + &return_iclass +}; + +static xtensa_opcode_internal retw_n_opcode = { + "retw.n", + 2, + retw_n_template, + &retn_iclass +}; + +static xtensa_opcode_internal rfde_opcode = { + "rfde", + 3, + rfde_template, + &rfe_iclass +}; + +static xtensa_opcode_internal rfe_opcode = { + "rfe", + 3, + rfe_template, + &rfe_iclass +}; + +static xtensa_opcode_internal rfi_opcode = { + "rfi", + 3, + rfi_template, + &rfi_iclass +}; + +static xtensa_opcode_internal rfwo_opcode = { + "rfwo", + 3, + rfwo_template, + &rfe_iclass +}; + +static xtensa_opcode_internal rfwu_opcode = { + "rfwu", + 3, + rfwu_template, + &rfe_iclass +}; + +static xtensa_opcode_internal ritlb0_opcode = { + "ritlb0", + 3, + ritlb0_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal ritlb1_opcode = { + "ritlb1", + 3, + ritlb1_template, + &rtlb_iclass +}; + +static xtensa_opcode_internal rotw_opcode = { + "rotw", + 3, + rotw_template, + &rotw_iclass +}; + +static xtensa_opcode_internal rsil_opcode = { + "rsil", + 3, + rsil_template, + &rsil_iclass +}; + +static xtensa_opcode_internal rsr_opcode = { + "rsr", + 3, + rsr_template, + &rsr_iclass +}; + +static xtensa_opcode_internal rsync_opcode = { + "rsync", + 3, + rsync_template, + &sync_iclass +}; + +static xtensa_opcode_internal s16i_opcode = { + "s16i", + 3, + s16i_template, + &s16i_iclass +}; + +static xtensa_opcode_internal s32e_opcode = { + "s32e", + 3, + s32e_template, + &s32e_iclass +}; + +static xtensa_opcode_internal s32i_opcode = { + "s32i", + 3, + s32i_template, + &s32i_iclass +}; + +static xtensa_opcode_internal s32i_n_opcode = { + "s32i.n", + 2, + s32i_n_template, + &storei4_iclass +}; + +static xtensa_opcode_internal s8i_opcode = { + "s8i", + 3, + s8i_template, + &s8i_iclass +}; + +static xtensa_opcode_internal sdct_opcode = { + "sdct", + 3, + sdct_template, + &acts_iclass +}; + +static xtensa_opcode_internal sict_opcode = { + "sict", + 3, + sict_template, + &acts_iclass +}; + +static xtensa_opcode_internal sicw_opcode = { + "sicw", + 3, + sicw_template, + &acts_iclass +}; + +static xtensa_opcode_internal simcall_opcode = { + "simcall", + 3, + simcall_template, + &syscall_iclass +}; + +static xtensa_opcode_internal sll_opcode = { + "sll", + 3, + sll_template, + &shifts_iclass +}; + +static xtensa_opcode_internal slli_opcode = { + "slli", + 3, + slli_template, + &slli_iclass +}; + +static xtensa_opcode_internal sra_opcode = { + "sra", + 3, + sra_template, + &shiftt_iclass +}; + +static xtensa_opcode_internal srai_opcode = { + "srai", + 3, + srai_template, + &srai_iclass +}; + +static xtensa_opcode_internal src_opcode = { + "src", + 3, + src_template, + &shiftst_iclass +}; + +static xtensa_opcode_internal srl_opcode = { + "srl", + 3, + srl_template, + &shiftt_iclass +}; + +static xtensa_opcode_internal srli_opcode = { + "srli", + 3, + srli_template, + &srli_iclass +}; + +static xtensa_opcode_internal ssa8b_opcode = { + "ssa8b", + 3, + ssa8b_template, + &sar_iclass +}; + +static xtensa_opcode_internal ssa8l_opcode = { + "ssa8l", + 3, + ssa8l_template, + &sar_iclass +}; + +static xtensa_opcode_internal ssai_opcode = { + "ssai", + 3, + ssai_template, + &sari_iclass +}; + +static xtensa_opcode_internal ssl_opcode = { + "ssl", + 3, + ssl_template, + &sar_iclass +}; + +static xtensa_opcode_internal ssr_opcode = { + "ssr", + 3, + ssr_template, + &sar_iclass +}; + +static xtensa_opcode_internal sub_opcode = { + "sub", + 3, + sub_template, + &addsub_iclass +}; + +static xtensa_opcode_internal subx2_opcode = { + "subx2", + 3, + subx2_template, + &addsub_iclass +}; + +static xtensa_opcode_internal subx4_opcode = { + "subx4", + 3, + subx4_template, + &addsub_iclass +}; + +static xtensa_opcode_internal subx8_opcode = { + "subx8", + 3, + subx8_template, + &addsub_iclass +}; + +static xtensa_opcode_internal syscall_opcode = { + "syscall", + 3, + syscall_template, + &syscall_iclass +}; + +static xtensa_opcode_internal waiti_opcode = { + "waiti", + 3, + waiti_template, + &wait_iclass +}; + +static xtensa_opcode_internal wdtlb_opcode = { + "wdtlb", + 3, + wdtlb_template, + &wtlb_iclass +}; + +static xtensa_opcode_internal witlb_opcode = { + "witlb", + 3, + witlb_template, + &wtlb_iclass +}; + +static xtensa_opcode_internal wsr_opcode = { + "wsr", + 3, + wsr_template, + &wsr_iclass +}; + +static xtensa_opcode_internal xor_opcode = { + "xor", + 3, + xor_template, + &bit_iclass +}; + +static xtensa_opcode_internal xsr_opcode = { + "xsr", + 3, + xsr_template, + &xsr_iclass +}; + +static xtensa_opcode_internal * opcodes[149] = { + &abs_opcode, + &add_opcode, + &add_n_opcode, + &addi_opcode, + &addi_n_opcode, + &addmi_opcode, + &addx2_opcode, + &addx4_opcode, + &addx8_opcode, + &and_opcode, + &ball_opcode, + &bany_opcode, + &bbc_opcode, + &bbci_opcode, + &bbs_opcode, + &bbsi_opcode, + &beq_opcode, + &beqi_opcode, + &beqz_opcode, + &beqz_n_opcode, + &bge_opcode, + &bgei_opcode, + &bgeu_opcode, + &bgeui_opcode, + &bgez_opcode, + &blt_opcode, + &blti_opcode, + &bltu_opcode, + &bltui_opcode, + &bltz_opcode, + &bnall_opcode, + &bne_opcode, + &bnei_opcode, + &bnez_opcode, + &bnez_n_opcode, + &bnone_opcode, + &break_opcode, + &break_n_opcode, + &call0_opcode, + &call12_opcode, + &call4_opcode, + &call8_opcode, + &callx0_opcode, + &callx12_opcode, + &callx4_opcode, + &callx8_opcode, + &dhi_opcode, + &dhwb_opcode, + &dhwbi_opcode, + &dii_opcode, + &diwb_opcode, + &diwbi_opcode, + &dpfr_opcode, + &dpfro_opcode, + &dpfw_opcode, + &dpfwo_opcode, + &dsync_opcode, + &entry_opcode, + &esync_opcode, + &excw_opcode, + &extui_opcode, + &idtlb_opcode, + &idtlba_opcode, + &ihi_opcode, + &iii_opcode, + &iitlb_opcode, + &iitlba_opcode, + &ipf_opcode, + &isync_opcode, + &j_opcode, + &jx_opcode, + &l16si_opcode, + &l16ui_opcode, + &l32e_opcode, + &l32i_opcode, + &l32i_n_opcode, + &l32r_opcode, + &l8ui_opcode, + &ldct_opcode, + &lict_opcode, + &licw_opcode, + &loop_opcode, + &loopgtz_opcode, + &loopnez_opcode, + &memw_opcode, + &mov_n_opcode, + &moveqz_opcode, + &movgez_opcode, + &movi_opcode, + &movi_n_opcode, + &movltz_opcode, + &movnez_opcode, + &movsp_opcode, + &neg_opcode, + &nop_n_opcode, + &nsa_opcode, + &nsau_opcode, + &or_opcode, + &pdtlb_opcode, + &pitlb_opcode, + &rdtlb0_opcode, + &rdtlb1_opcode, + &ret_opcode, + &ret_n_opcode, + &retw_opcode, + &retw_n_opcode, + &rfde_opcode, + &rfe_opcode, + &rfi_opcode, + &rfwo_opcode, + &rfwu_opcode, + &ritlb0_opcode, + &ritlb1_opcode, + &rotw_opcode, + &rsil_opcode, + &rsr_opcode, + &rsync_opcode, + &s16i_opcode, + &s32e_opcode, + &s32i_opcode, + &s32i_n_opcode, + &s8i_opcode, + &sdct_opcode, + &sict_opcode, + &sicw_opcode, + &simcall_opcode, + &sll_opcode, + &slli_opcode, + &sra_opcode, + &srai_opcode, + &src_opcode, + &srl_opcode, + &srli_opcode, + &ssa8b_opcode, + &ssa8l_opcode, + &ssai_opcode, + &ssl_opcode, + &ssr_opcode, + &sub_opcode, + &subx2_opcode, + &subx4_opcode, + &subx8_opcode, + &syscall_opcode, + &waiti_opcode, + &wdtlb_opcode, + &witlb_opcode, + &wsr_opcode, + &xor_opcode, + &xsr_opcode +}; + +xtensa_opcode_internal ** +get_opcodes (void) +{ + return &opcodes[0]; +} + +const int +get_num_opcodes (void) +{ + return 149; +} + +#define xtensa_abs_op 0 +#define xtensa_add_op 1 +#define xtensa_add_n_op 2 +#define xtensa_addi_op 3 +#define xtensa_addi_n_op 4 +#define xtensa_addmi_op 5 +#define xtensa_addx2_op 6 +#define xtensa_addx4_op 7 +#define xtensa_addx8_op 8 +#define xtensa_and_op 9 +#define xtensa_ball_op 10 +#define xtensa_bany_op 11 +#define xtensa_bbc_op 12 +#define xtensa_bbci_op 13 +#define xtensa_bbs_op 14 +#define xtensa_bbsi_op 15 +#define xtensa_beq_op 16 +#define xtensa_beqi_op 17 +#define xtensa_beqz_op 18 +#define xtensa_beqz_n_op 19 +#define xtensa_bge_op 20 +#define xtensa_bgei_op 21 +#define xtensa_bgeu_op 22 +#define xtensa_bgeui_op 23 +#define xtensa_bgez_op 24 +#define xtensa_blt_op 25 +#define xtensa_blti_op 26 +#define xtensa_bltu_op 27 +#define xtensa_bltui_op 28 +#define xtensa_bltz_op 29 +#define xtensa_bnall_op 30 +#define xtensa_bne_op 31 +#define xtensa_bnei_op 32 +#define xtensa_bnez_op 33 +#define xtensa_bnez_n_op 34 +#define xtensa_bnone_op 35 +#define xtensa_break_op 36 +#define xtensa_break_n_op 37 +#define xtensa_call0_op 38 +#define xtensa_call12_op 39 +#define xtensa_call4_op 40 +#define xtensa_call8_op 41 +#define xtensa_callx0_op 42 +#define xtensa_callx12_op 43 +#define xtensa_callx4_op 44 +#define xtensa_callx8_op 45 +#define xtensa_dhi_op 46 +#define xtensa_dhwb_op 47 +#define xtensa_dhwbi_op 48 +#define xtensa_dii_op 49 +#define xtensa_diwb_op 50 +#define xtensa_diwbi_op 51 +#define xtensa_dpfr_op 52 +#define xtensa_dpfro_op 53 +#define xtensa_dpfw_op 54 +#define xtensa_dpfwo_op 55 +#define xtensa_dsync_op 56 +#define xtensa_entry_op 57 +#define xtensa_esync_op 58 +#define xtensa_excw_op 59 +#define xtensa_extui_op 60 +#define xtensa_idtlb_op 61 +#define xtensa_idtlba_op 62 +#define xtensa_ihi_op 63 +#define xtensa_iii_op 64 +#define xtensa_iitlb_op 65 +#define xtensa_iitlba_op 66 +#define xtensa_ipf_op 67 +#define xtensa_isync_op 68 +#define xtensa_j_op 69 +#define xtensa_jx_op 70 +#define xtensa_l16si_op 71 +#define xtensa_l16ui_op 72 +#define xtensa_l32e_op 73 +#define xtensa_l32i_op 74 +#define xtensa_l32i_n_op 75 +#define xtensa_l32r_op 76 +#define xtensa_l8ui_op 77 +#define xtensa_ldct_op 78 +#define xtensa_lict_op 79 +#define xtensa_licw_op 80 +#define xtensa_loop_op 81 +#define xtensa_loopgtz_op 82 +#define xtensa_loopnez_op 83 +#define xtensa_memw_op 84 +#define xtensa_mov_n_op 85 +#define xtensa_moveqz_op 86 +#define xtensa_movgez_op 87 +#define xtensa_movi_op 88 +#define xtensa_movi_n_op 89 +#define xtensa_movltz_op 90 +#define xtensa_movnez_op 91 +#define xtensa_movsp_op 92 +#define xtensa_neg_op 93 +#define xtensa_nop_n_op 94 +#define xtensa_nsa_op 95 +#define xtensa_nsau_op 96 +#define xtensa_or_op 97 +#define xtensa_pdtlb_op 98 +#define xtensa_pitlb_op 99 +#define xtensa_rdtlb0_op 100 +#define xtensa_rdtlb1_op 101 +#define xtensa_ret_op 102 +#define xtensa_ret_n_op 103 +#define xtensa_retw_op 104 +#define xtensa_retw_n_op 105 +#define xtensa_rfde_op 106 +#define xtensa_rfe_op 107 +#define xtensa_rfi_op 108 +#define xtensa_rfwo_op 109 +#define xtensa_rfwu_op 110 +#define xtensa_ritlb0_op 111 +#define xtensa_ritlb1_op 112 +#define xtensa_rotw_op 113 +#define xtensa_rsil_op 114 +#define xtensa_rsr_op 115 +#define xtensa_rsync_op 116 +#define xtensa_s16i_op 117 +#define xtensa_s32e_op 118 +#define xtensa_s32i_op 119 +#define xtensa_s32i_n_op 120 +#define xtensa_s8i_op 121 +#define xtensa_sdct_op 122 +#define xtensa_sict_op 123 +#define xtensa_sicw_op 124 +#define xtensa_simcall_op 125 +#define xtensa_sll_op 126 +#define xtensa_slli_op 127 +#define xtensa_sra_op 128 +#define xtensa_srai_op 129 +#define xtensa_src_op 130 +#define xtensa_srl_op 131 +#define xtensa_srli_op 132 +#define xtensa_ssa8b_op 133 +#define xtensa_ssa8l_op 134 +#define xtensa_ssai_op 135 +#define xtensa_ssl_op 136 +#define xtensa_ssr_op 137 +#define xtensa_sub_op 138 +#define xtensa_subx2_op 139 +#define xtensa_subx4_op 140 +#define xtensa_subx8_op 141 +#define xtensa_syscall_op 142 +#define xtensa_waiti_op 143 +#define xtensa_wdtlb_op 144 +#define xtensa_witlb_op 145 +#define xtensa_wsr_op 146 +#define xtensa_xor_op 147 +#define xtensa_xsr_op 148 + +int +decode_insn (const xtensa_insnbuf insn) +{ + switch (get_op0_field (insn)) { + case 0: /* QRST: op0=0000 */ + switch (get_op1_field (insn)) { + case 3: /* RST3: op1=0011 */ + switch (get_op2_field (insn)) { + case 8: /* MOVEQZ: op2=1000 */ + return xtensa_moveqz_op; + case 9: /* MOVNEZ: op2=1001 */ + return xtensa_movnez_op; + case 10: /* MOVLTZ: op2=1010 */ + return xtensa_movltz_op; + case 11: /* MOVGEZ: op2=1011 */ + return xtensa_movgez_op; + case 0: /* RSR: op2=0000 */ + return xtensa_rsr_op; + case 1: /* WSR: op2=0001 */ + return xtensa_wsr_op; + } + break; + case 9: /* LSI4: op1=1001 */ + switch (get_op2_field (insn)) { + case 4: /* S32E: op2=0100 */ + return xtensa_s32e_op; + case 0: /* L32E: op2=0000 */ + return xtensa_l32e_op; + } + break; + case 4: /* EXTUI: op1=010x */ + case 5: /* EXTUI: op1=010x */ + return xtensa_extui_op; + case 0: /* RST0: op1=0000 */ + switch (get_op2_field (insn)) { + case 15: /* SUBX8: op2=1111 */ + return xtensa_subx8_op; + case 0: /* ST0: op2=0000 */ + switch (get_r_field (insn)) { + case 0: /* SNM0: r=0000 */ + switch (get_m_field (insn)) { + case 2: /* JR: m=10 */ + switch (get_n_field (insn)) { + case 0: /* RET: n=00 */ + return xtensa_ret_op; + case 1: /* RETW: n=01 */ + return xtensa_retw_op; + case 2: /* JX: n=10 */ + return xtensa_jx_op; + } + break; + case 3: /* CALLX: m=11 */ + switch (get_n_field (insn)) { + case 0: /* CALLX0: n=00 */ + return xtensa_callx0_op; + case 1: /* CALLX4: n=01 */ + return xtensa_callx4_op; + case 2: /* CALLX8: n=10 */ + return xtensa_callx8_op; + case 3: /* CALLX12: n=11 */ + return xtensa_callx12_op; + } + break; + } + break; + case 1: /* MOVSP: r=0001 */ + return xtensa_movsp_op; + case 2: /* SYNC: r=0010 */ + switch (get_s_field (insn)) { + case 0: /* SYNCT: s=0000 */ + switch (get_t_field (insn)) { + case 2: /* ESYNC: t=0010 */ + return xtensa_esync_op; + case 3: /* DSYNC: t=0011 */ + return xtensa_dsync_op; + case 8: /* EXCW: t=1000 */ + return xtensa_excw_op; + case 12: /* MEMW: t=1100 */ + return xtensa_memw_op; + case 0: /* ISYNC: t=0000 */ + return xtensa_isync_op; + case 1: /* RSYNC: t=0001 */ + return xtensa_rsync_op; + } + break; + } + break; + case 4: /* BREAK: r=0100 */ + return xtensa_break_op; + case 3: /* RFEI: r=0011 */ + switch (get_t_field (insn)) { + case 0: /* RFET: t=0000 */ + switch (get_s_field (insn)) { + case 2: /* RFDE: s=0010 */ + return xtensa_rfde_op; + case 4: /* RFWO: s=0100 */ + return xtensa_rfwo_op; + case 5: /* RFWU: s=0101 */ + return xtensa_rfwu_op; + case 0: /* RFE: s=0000 */ + return xtensa_rfe_op; + } + break; + case 1: /* RFI: t=0001 */ + return xtensa_rfi_op; + } + break; + case 5: /* SCALL: r=0101 */ + switch (get_s_field (insn)) { + case 0: /* SYSCALL: s=0000 */ + return xtensa_syscall_op; + case 1: /* SIMCALL: s=0001 */ + return xtensa_simcall_op; + } + break; + case 6: /* RSIL: r=0110 */ + return xtensa_rsil_op; + case 7: /* WAITI: r=0111 */ + return xtensa_waiti_op; + } + break; + case 1: /* AND: op2=0001 */ + return xtensa_and_op; + case 2: /* OR: op2=0010 */ + return xtensa_or_op; + case 3: /* XOR: op2=0011 */ + return xtensa_xor_op; + case 4: /* ST1: op2=0100 */ + switch (get_r_field (insn)) { + case 15: /* NSAU: r=1111 */ + return xtensa_nsau_op; + case 0: /* SSR: r=0000 */ + return xtensa_ssr_op; + case 1: /* SSL: r=0001 */ + return xtensa_ssl_op; + case 2: /* SSA8L: r=0010 */ + return xtensa_ssa8l_op; + case 3: /* SSA8B: r=0011 */ + return xtensa_ssa8b_op; + case 4: /* SSAI: r=0100 */ + return xtensa_ssai_op; + case 8: /* ROTW: r=1000 */ + return xtensa_rotw_op; + case 14: /* NSA: r=1110 */ + return xtensa_nsa_op; + } + break; + case 8: /* ADD: op2=1000 */ + return xtensa_add_op; + case 5: /* ST4: op2=0101 */ + switch (get_r_field (insn)) { + case 15: /* RDTLB1: r=1111 */ + return xtensa_rdtlb1_op; + case 0: /* IITLBA: r=0000 */ + return xtensa_iitlba_op; + case 3: /* RITLB0: r=0011 */ + return xtensa_ritlb0_op; + case 4: /* IITLB: r=0100 */ + return xtensa_iitlb_op; + case 8: /* IDTLBA: r=1000 */ + return xtensa_idtlba_op; + case 5: /* PITLB: r=0101 */ + return xtensa_pitlb_op; + case 6: /* WITLB: r=0110 */ + return xtensa_witlb_op; + case 7: /* RITLB1: r=0111 */ + return xtensa_ritlb1_op; + case 11: /* RDTLB0: r=1011 */ + return xtensa_rdtlb0_op; + case 12: /* IDTLB: r=1100 */ + return xtensa_idtlb_op; + case 13: /* PDTLB: r=1101 */ + return xtensa_pdtlb_op; + case 14: /* WDTLB: r=1110 */ + return xtensa_wdtlb_op; + } + break; + case 6: /* RT0: op2=0110 */ + switch (get_s_field (insn)) { + case 0: /* NEG: s=0000 */ + return xtensa_neg_op; + case 1: /* ABS: s=0001 */ + return xtensa_abs_op; + } + break; + case 9: /* ADDX2: op2=1001 */ + return xtensa_addx2_op; + case 10: /* ADDX4: op2=1010 */ + return xtensa_addx4_op; + case 11: /* ADDX8: op2=1011 */ + return xtensa_addx8_op; + case 12: /* SUB: op2=1100 */ + return xtensa_sub_op; + case 13: /* SUBX2: op2=1101 */ + return xtensa_subx2_op; + case 14: /* SUBX4: op2=1110 */ + return xtensa_subx4_op; + } + break; + case 1: /* RST1: op1=0001 */ + switch (get_op2_field (insn)) { + case 15: /* IMP: op2=1111 */ + switch (get_r_field (insn)) { + case 0: /* LICT: r=0000 */ + return xtensa_lict_op; + case 1: /* SICT: r=0001 */ + return xtensa_sict_op; + case 2: /* LICW: r=0010 */ + return xtensa_licw_op; + case 3: /* SICW: r=0011 */ + return xtensa_sicw_op; + case 8: /* LDCT: r=1000 */ + return xtensa_ldct_op; + case 9: /* SDCT: r=1001 */ + return xtensa_sdct_op; + } + break; + case 0: /* SLLI: op2=000x */ + case 1: /* SLLI: op2=000x */ + return xtensa_slli_op; + case 2: /* SRAI: op2=001x */ + case 3: /* SRAI: op2=001x */ + return xtensa_srai_op; + case 4: /* SRLI: op2=0100 */ + return xtensa_srli_op; + case 8: /* SRC: op2=1000 */ + return xtensa_src_op; + case 9: /* SRL: op2=1001 */ + return xtensa_srl_op; + case 6: /* XSR: op2=0110 */ + return xtensa_xsr_op; + case 10: /* SLL: op2=1010 */ + return xtensa_sll_op; + case 11: /* SRA: op2=1011 */ + return xtensa_sra_op; + } + break; + } + break; + case 1: /* L32R: op0=0001 */ + return xtensa_l32r_op; + case 2: /* LSAI: op0=0010 */ + switch (get_r_field (insn)) { + case 0: /* L8UI: r=0000 */ + return xtensa_l8ui_op; + case 1: /* L16UI: r=0001 */ + return xtensa_l16ui_op; + case 2: /* L32I: r=0010 */ + return xtensa_l32i_op; + case 4: /* S8I: r=0100 */ + return xtensa_s8i_op; + case 5: /* S16I: r=0101 */ + return xtensa_s16i_op; + case 9: /* L16SI: r=1001 */ + return xtensa_l16si_op; + case 6: /* S32I: r=0110 */ + return xtensa_s32i_op; + case 7: /* CACHE: r=0111 */ + switch (get_t_field (insn)) { + case 15: /* III: t=1111 */ + return xtensa_iii_op; + case 0: /* DPFR: t=0000 */ + return xtensa_dpfr_op; + case 1: /* DPFW: t=0001 */ + return xtensa_dpfw_op; + case 2: /* DPFRO: t=0010 */ + return xtensa_dpfro_op; + case 4: /* DHWB: t=0100 */ + return xtensa_dhwb_op; + case 3: /* DPFWO: t=0011 */ + return xtensa_dpfwo_op; + case 8: /* DCE: t=1000 */ + switch (get_op1_field (insn)) { + case 4: /* DIWB: op1=0100 */ + return xtensa_diwb_op; + case 5: /* DIWBI: op1=0101 */ + return xtensa_diwbi_op; + } + break; + case 5: /* DHWBI: t=0101 */ + return xtensa_dhwbi_op; + case 6: /* DHI: t=0110 */ + return xtensa_dhi_op; + case 7: /* DII: t=0111 */ + return xtensa_dii_op; + case 12: /* IPF: t=1100 */ + return xtensa_ipf_op; + case 14: /* IHI: t=1110 */ + return xtensa_ihi_op; + } + break; + case 10: /* MOVI: r=1010 */ + return xtensa_movi_op; + case 12: /* ADDI: r=1100 */ + return xtensa_addi_op; + case 13: /* ADDMI: r=1101 */ + return xtensa_addmi_op; + } + break; + case 8: /* L32I.N: op0=1000 */ + return xtensa_l32i_n_op; + case 5: /* CALL: op0=0101 */ + switch (get_n_field (insn)) { + case 0: /* CALL0: n=00 */ + return xtensa_call0_op; + case 1: /* CALL4: n=01 */ + return xtensa_call4_op; + case 2: /* CALL8: n=10 */ + return xtensa_call8_op; + case 3: /* CALL12: n=11 */ + return xtensa_call12_op; + } + break; + case 6: /* SI: op0=0110 */ + switch (get_n_field (insn)) { + case 0: /* J: n=00 */ + return xtensa_j_op; + case 1: /* BZ: n=01 */ + switch (get_m_field (insn)) { + case 0: /* BEQZ: m=00 */ + return xtensa_beqz_op; + case 1: /* BNEZ: m=01 */ + return xtensa_bnez_op; + case 2: /* BLTZ: m=10 */ + return xtensa_bltz_op; + case 3: /* BGEZ: m=11 */ + return xtensa_bgez_op; + } + break; + case 2: /* BI0: n=10 */ + switch (get_m_field (insn)) { + case 0: /* BEQI: m=00 */ + return xtensa_beqi_op; + case 1: /* BNEI: m=01 */ + return xtensa_bnei_op; + case 2: /* BLTI: m=10 */ + return xtensa_blti_op; + case 3: /* BGEI: m=11 */ + return xtensa_bgei_op; + } + break; + case 3: /* BI1: n=11 */ + switch (get_m_field (insn)) { + case 0: /* ENTRY: m=00 */ + return xtensa_entry_op; + case 1: /* B1: m=01 */ + switch (get_r_field (insn)) { + case 8: /* LOOP: r=1000 */ + return xtensa_loop_op; + case 9: /* LOOPNEZ: r=1001 */ + return xtensa_loopnez_op; + case 10: /* LOOPGTZ: r=1010 */ + return xtensa_loopgtz_op; + } + break; + case 2: /* BLTUI: m=10 */ + return xtensa_bltui_op; + case 3: /* BGEUI: m=11 */ + return xtensa_bgeui_op; + } + break; + } + break; + case 9: /* S32I.N: op0=1001 */ + return xtensa_s32i_n_op; + case 10: /* ADD.N: op0=1010 */ + return xtensa_add_n_op; + case 7: /* B: op0=0111 */ + switch (get_r_field (insn)) { + case 6: /* BBCI: r=011x */ + case 7: /* BBCI: r=011x */ + return xtensa_bbci_op; + case 0: /* BNONE: r=0000 */ + return xtensa_bnone_op; + case 1: /* BEQ: r=0001 */ + return xtensa_beq_op; + case 2: /* BLT: r=0010 */ + return xtensa_blt_op; + case 4: /* BALL: r=0100 */ + return xtensa_ball_op; + case 14: /* BBSI: r=111x */ + case 15: /* BBSI: r=111x */ + return xtensa_bbsi_op; + case 3: /* BLTU: r=0011 */ + return xtensa_bltu_op; + case 5: /* BBC: r=0101 */ + return xtensa_bbc_op; + case 8: /* BANY: r=1000 */ + return xtensa_bany_op; + case 9: /* BNE: r=1001 */ + return xtensa_bne_op; + case 10: /* BGE: r=1010 */ + return xtensa_bge_op; + case 11: /* BGEU: r=1011 */ + return xtensa_bgeu_op; + case 12: /* BNALL: r=1100 */ + return xtensa_bnall_op; + case 13: /* BBS: r=1101 */ + return xtensa_bbs_op; + } + break; + case 11: /* ADDI.N: op0=1011 */ + return xtensa_addi_n_op; + case 12: /* ST2: op0=1100 */ + switch (get_i_field (insn)) { + case 0: /* MOVI.N: i=0 */ + return xtensa_movi_n_op; + case 1: /* BZ6: i=1 */ + switch (get_z_field (insn)) { + case 0: /* BEQZ.N: z=0 */ + return xtensa_beqz_n_op; + case 1: /* BNEZ.N: z=1 */ + return xtensa_bnez_n_op; + } + break; + } + break; + case 13: /* ST3: op0=1101 */ + switch (get_r_field (insn)) { + case 15: /* S3: r=1111 */ + switch (get_t_field (insn)) { + case 0: /* RET.N: t=0000 */ + return xtensa_ret_n_op; + case 1: /* RETW.N: t=0001 */ + return xtensa_retw_n_op; + case 2: /* BREAK.N: t=0010 */ + return xtensa_break_n_op; + case 3: /* NOP.N: t=0011 */ + return xtensa_nop_n_op; + } + break; + case 0: /* MOV.N: r=0000 */ + return xtensa_mov_n_op; + } + break; + } + return XTENSA_UNDEFINED; +} + +int +interface_version (void) +{ + return 3; +} + +static struct config_struct config_table[] = { + {"IsaMemoryOrder", "BigEndian"}, + {"PIFReadDataBits", "128"}, + {"PIFWriteDataBits", "128"}, + {"IsaCoprocessorCount", "0"}, + {"IsaUseBooleans", "0"}, + {"IsaUseDensityInstruction", "1"}, + {0, 0} +}; + +struct config_struct * get_config_table (void); + +struct config_struct * +get_config_table (void) +{ + return config_table; +} + +xtensa_isa_module xtensa_isa_modules[] = { + { get_num_opcodes, get_opcodes, decode_insn, get_config_table }, + { 0, 0, 0, 0 } +}; diff --git a/gdb/cp-namespace.c b/gdb/cp-namespace.c new file mode 100644 index 0000000..7205cf7 --- /dev/null +++ b/gdb/cp-namespace.c @@ -0,0 +1,266 @@ +/* Helper routines for C++ support in GDB. + Copyright 2003 Free Software Foundation, Inc. + + Contributed by David Carlton. + + This file is part of GDB. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "cp-support.h" +#include "gdb_obstack.h" +#include "symtab.h" +#include "symfile.h" +#include "gdb_assert.h" +#include "block.h" + +/* When set, the file that we're processing seems to have debugging + info for C++ namespaces, so cp-namespace.c shouldn't try to guess + namespace info itself. */ + +unsigned char processing_has_namespace_info; + +/* If processing_has_namespace_info is nonzero, this string should + contain the name of the current namespace. The string is + temporary; copy it if you need it. */ + +const char *processing_current_namespace; + +/* List of using directives that are active in the current file. */ + +static struct using_direct *using_list; + +static struct using_direct *cp_add_using (const char *name, + unsigned int inner_len, + unsigned int outer_len, + struct using_direct *next); + +static struct using_direct *cp_copy_usings (struct using_direct *using, + struct obstack *obstack); + +/* Set up support for dealing with C++ namespace info in the current + symtab. */ + +void cp_initialize_namespace () +{ + processing_has_namespace_info = 0; + using_list = NULL; +} + +/* Add all the using directives we've gathered to the current symtab. + STATIC_BLOCK should be the symtab's static block; OBSTACK is used + for allocation. */ + +void +cp_finalize_namespace (struct block *static_block, + struct obstack *obstack) +{ + if (using_list != NULL) + { + block_set_using (static_block, + cp_copy_usings (using_list, obstack), + obstack); + using_list = NULL; + } +} + +/* Check to see if SYMBOL refers to an object contained within an + anonymous namespace; if so, add an appropriate using directive. */ + +/* Optimize away strlen ("(anonymous namespace)"). */ + +#define ANONYMOUS_NAMESPACE_LEN 21 + +void +cp_scan_for_anonymous_namespaces (const struct symbol *symbol) +{ + if (!processing_has_namespace_info + && SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL) + { + const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol); + unsigned int previous_component; + unsigned int next_component; + const char *len; + + /* Start with a quick-and-dirty check for mention of "(anonymous + namespace)". */ + + if (!cp_is_anonymous (name)) + return; + + previous_component = 0; + next_component = cp_find_first_component (name + previous_component); + + while (name[next_component] == ':') + { + if ((next_component - previous_component) == ANONYMOUS_NAMESPACE_LEN + && strncmp (name + previous_component, + "(anonymous namespace)", + ANONYMOUS_NAMESPACE_LEN) == 0) + { + /* We've found a component of the name that's an + anonymous namespace. So add symbols in it to the + namespace given by the previous component if there is + one, or to the global namespace if there isn't. */ + cp_add_using_directive (name, + previous_component == 0 + ? 0 : previous_component - 2, + next_component); + } + /* The "+ 2" is for the "::". */ + previous_component = next_component + 2; + next_component = (previous_component + + cp_find_first_component (name + + previous_component)); + } + } +} + +/* Add a using directive to using_list. NAME is the start of a string + that should contain the namespaces we want to add as initial + substrings, OUTER_LENGTH is the end of the outer namespace, and + INNER_LENGTH is the end of the inner namespace. If the using + directive in question has already been added, don't add it + twice. */ + +void +cp_add_using_directive (const char *name, unsigned int outer_length, + unsigned int inner_length) +{ + struct using_direct *current; + struct using_direct *new; + + /* Has it already been added? */ + + for (current = using_list; current != NULL; current = current->next) + { + if ((strncmp (current->inner, name, inner_length) == 0) + && (strlen (current->inner) == inner_length) + && (strlen (current->outer) == outer_length)) + return; + } + + using_list = cp_add_using (name, inner_length, outer_length, + using_list); +} + +/* Record the namespace that the function defined by SYMBOL was + defined in, if necessary. BLOCK is the associated block; use + OBSTACK for allocation. */ + +void +cp_set_block_scope (const struct symbol *symbol, + struct block *block, + struct obstack *obstack) +{ + /* Make sure that the name was originally mangled: if not, there + certainly isn't any namespace information to worry about! */ + + if (SYMBOL_CPLUS_DEMANGLED_NAME (symbol) != NULL) + { + if (processing_has_namespace_info) + { + block_set_scope + (block, obsavestring (processing_current_namespace, + strlen (processing_current_namespace), + obstack), + obstack); + } + else + { + /* Try to figure out the appropriate namespace from the + demangled name. */ + + /* FIXME: carlton/2003-04-15: If the function in question is + a method of a class, the name will actually include the + name of the class as well. This should be harmless, but + is a little unfortunate. */ + + const char *name = SYMBOL_CPLUS_DEMANGLED_NAME (symbol); + unsigned int prefix_len = cp_entire_prefix_len (name); + + block_set_scope (block, + obsavestring (name, prefix_len, obstack), + obstack); + } + } +} + +/* Test whether or not NAMESPACE looks like it mentions an anonymous + namespace; return nonzero if so. */ + +int +cp_is_anonymous (const char *namespace) +{ + return (strstr (namespace, "(anonymous namespace)") + != NULL); +} + +/* Create a new struct using direct whose inner namespace is the + initial substring of NAME of leng INNER_LEN and whose outer + namespace is the initial substring of NAME of length OUTER_LENGTH. + Set its next member in the linked list to NEXT; allocate all memory + using xmalloc. It copies the strings, so NAME can be a temporary + string. */ + +static struct using_direct * +cp_add_using (const char *name, + unsigned int inner_len, + unsigned int outer_len, + struct using_direct *next) +{ + struct using_direct *retval; + + gdb_assert (outer_len < inner_len); + + retval = xmalloc (sizeof (struct using_direct)); + retval->inner = savestring (name, inner_len); + retval->outer = savestring (name, outer_len); + retval->next = next; + + return retval; +} + +/* Make a copy of the using directives in the list pointed to by + USING, using OBSTACK to allocate memory. Free all memory pointed + to by USING via xfree. */ + +static struct using_direct * +cp_copy_usings (struct using_direct *using, + struct obstack *obstack) +{ + if (using == NULL) + { + return NULL; + } + else + { + struct using_direct *retval + = obstack_alloc (obstack, sizeof (struct using_direct)); + retval->inner = obsavestring (using->inner, strlen (using->inner), + obstack); + retval->outer = obsavestring (using->outer, strlen (using->outer), + obstack); + retval->next = cp_copy_usings (using->next, obstack); + + xfree (using->inner); + xfree (using->outer); + xfree (using); + + return retval; + } +} diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi new file mode 100644 index 0000000..de48a19 --- /dev/null +++ b/gdb/doc/observer.texi @@ -0,0 +1,70 @@ +@c -*-texinfo-*- +@node GDB Observers +@appendix @value{GDBN} Currently available observers + +@section Implementation rationale +@cindex observers implementation rationale + +An @dfn{observer} is an entity which is interested in being notified +when GDB reaches certain states, or certain events occur in GDB. +The entity being observed is called the @dfn{subject}. To receive +notifications, the observer attaches a callback to the subject. +One subject can have several observers. + +@file{observer.c} implements an internal generic low-level event +notification mechanism. This generic event notification mechanism is +then re-used to implement the exported high-level notification +management routines for all possible notifications. + +The current implementation of the generic observer provides support +for contextual data. This contextual data is given to the subject +when attaching the callback. In return, the subject will provide +this contextual data back to the observer as a parameter of the +callback. + +Note that the current support for the contextual data is only partial, +as it lacks a mechanism that would deallocate this data when the +callback is detached. This is not a problem so far, as this contextual +data is only used internally to hold a function pointer. Later on, if +a certain observer needs to provide support for user-level contextual +data, then the generic notification mechanism will need to be +enhanced to allow the observer to provide a routine to deallocate the +data when attaching the callback. + +The observer implementation is also currently not reentrant. +In particular, it is therefore not possible to call the attach +or detach routines during a notification. + +@section @code{normal_stop} Notifications +@cindex @code{normal_stop} observer +@cindex notification about inferior execution stop + +@value{GDBN} notifies all @code{normal_stop} observers when the +inferior execution has just stopped, the associated messages and +annotations have been printed, and the control is about to be returned +to the user. + +Note that the @code{normal_stop} notification is not emitted when +the execution stops due to a breakpoint, and this breakpoint has +a condition that is not met. If the breakpoint has any associated +commands list, the commands are executed after the notification +is emitted. + +The following interface is available to manage @code{normal_stop} +observers: + +@deftypefun extern struct observer *observer_attach_normal_stop (observer_normal_stop_ftype *@var{f}) +Attach the given @code{normal_stop} callback function @var{f} and +return the associated observer. +@end deftypefun + +@deftypefun extern void observer_detach_normal_stop (struct observer *@var{observer}); +Remove @var{observer} from the list of observers to be notified when +a @code{normal_stop} event occurs. +@end deftypefun + +@deftypefun extern void observer_notify_normal_stop (void); +Send a notification to all @code{normal_stop} observers. +@end deftypefun + + diff --git a/gdb/frame-base.c b/gdb/frame-base.c new file mode 100644 index 0000000..f7ba4be --- /dev/null +++ b/gdb/frame-base.c @@ -0,0 +1,154 @@ +/* Definitions for frame address handler, for GDB, the GNU debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame-base.h" +#include "frame.h" + +/* A default frame base implementations. If it wasn't for the old + FRAME_LOCALS_ADDRESS and FRAME_ARGS_ADDRESS, these could be + combined into a single function. All architectures really need to + override this. */ + +static CORE_ADDR +default_frame_base_address (struct frame_info *next_frame, void **this_cache) +{ + struct frame_info *this_frame = get_prev_frame (next_frame); + return get_frame_base (this_frame); /* sigh! */ +} + +static CORE_ADDR +default_frame_locals_address (struct frame_info *next_frame, void **this_cache) +{ + struct frame_info *this_frame = get_prev_frame (next_frame); + return FRAME_LOCALS_ADDRESS (this_frame); +} + +static CORE_ADDR +default_frame_args_address (struct frame_info *next_frame, void **this_cache) +{ + struct frame_info *this_frame = get_prev_frame (next_frame); + /* FRAME_ARGS_ADDRESS_CORRECT is just like FRAME_ARGS_ADDRESS except + that if it is unsure about the answer, it returns 0 instead of + guessing (this happens on the VAX and i960, for example). + + On most machines, we never have to guess about the args address, + so FRAME_ARGS_ADDRESS{,_CORRECT} are the same. */ +#ifdef FRAME_ARGS_ADDRESS_CORRECT + return FRAME_ARGS_ADDRESS_CORRECT (this_frame); +#else + return FRAME_ARGS_ADDRESS (this_frame); +#endif +} + +const struct frame_base default_frame_base = { + NULL, /* No parent. */ + default_frame_base_address, + default_frame_locals_address, + default_frame_args_address +}; + +static struct gdbarch_data *frame_base_data; + +struct frame_base_table +{ + frame_base_p_ftype **p; + const struct frame_base *default_base; + int nr; +}; + +static void * +frame_base_init (struct gdbarch *gdbarch) +{ + struct frame_base_table *table = XCALLOC (1, struct frame_base_table); + table->default_base = &default_frame_base; + return table; +} + +static void +frame_base_free (struct gdbarch *gdbarch, void *data) +{ + struct frame_base_table *table = + gdbarch_data (gdbarch, frame_base_data); + xfree (table->p); + xfree (table); +} + +static struct frame_base_table * +frame_base_table (struct gdbarch *gdbarch) +{ + struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data); + if (table == NULL) + { + /* ULGH, called during architecture initialization. Patch + things up. */ + table = frame_base_init (gdbarch); + set_gdbarch_data (gdbarch, frame_base_data, table); + } + return table; +} + +/* Append a predicate to the end of the table. */ +static void +append_predicate (struct frame_base_table *table, frame_base_p_ftype *p) +{ + table->p = xrealloc (table->p, ((table->nr + 1) + * sizeof (frame_base_p_ftype *))); + table->p[table->nr] = p; + table->nr++; +} + +void +frame_base_append_predicate (struct gdbarch *gdbarch, + frame_base_p_ftype *p) +{ + struct frame_base_table *table = frame_base_table (gdbarch); + append_predicate (table, p); +} + +void +frame_base_set_default (struct gdbarch *gdbarch, + const struct frame_base *default_base) +{ + struct frame_base_table *table = frame_base_table (gdbarch); + table->default_base = default_base; +} + +const struct frame_base * +frame_base_find_by_pc (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + int i; + struct frame_base_table *table = frame_base_table (gdbarch); + for (i = 0; i < table->nr; i++) + { + const struct frame_base *desc = table->p[i] (pc); + if (desc != NULL) + return desc; + } + return table->default_base; +} + +void +_initialize_frame_base (void) +{ + frame_base_data = register_gdbarch_data (frame_base_init, + frame_base_free); +} diff --git a/gdb/frame-base.h b/gdb/frame-base.h new file mode 100644 index 0000000..5e0d5db --- /dev/null +++ b/gdb/frame-base.h @@ -0,0 +1,94 @@ +/* Definitions for a frame base, for GDB, the GNU debugger. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#if !defined (FRAME_BASE_H) +#define FRAME_BASE_H 1 + +struct frame_info; +struct frame_id; +struct frame_unwind; +struct frame_base; +struct gdbarch; +struct regcache; + +/* Return the frame base methods for the function that contains PC, or + NULL if it can't handle this frame. */ + +typedef const struct frame_base *(frame_base_p_ftype) (CORE_ADDR pc); + +/* Add a frame base handler to the list. The predicates are polled in + the order that they are appended. */ + +extern void frame_base_append_predicate (struct gdbarch *gdbarch, + frame_base_p_ftype *p); + +/* Set the default frame base. If all else fails, this one is + returned. If this isn't set, the default is to use legacy code + that uses things like the frame ID's base (ulgh!). */ + +extern void frame_base_set_default (struct gdbarch *gdbarch, + const struct frame_base *def); + +/* Iterate through the list of frame base handlers until one returns + an implementation. */ + +extern const struct frame_base *frame_base_find_by_pc (struct gdbarch *gdbarch, + CORE_ADDR pc); + +/* Assuming the frame chain: (outer) prev <-> this <-> next (inner); + and that this is a `normal frame'; use the NEXT frame, and its + register unwind method, to determine the address of THIS frame's + `base'. + + The exact meaning of `base' is highly dependant on the type of the + debug info. It is assumed that dwarf2, stabs, ... will each + provide their own methods. + + A typical implmentation will return the same value for base, + locals-base and args-base. That value, however, will likely be + different to the frame ID's stack address. */ + +/* A generic base address. */ + +typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame, + void **this_base_cache); + +/* The base address of the frame's local variables. */ + +typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame, + void **this_base_cache); + +/* The base address of the frame's arguments / parameters. */ + +typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame, + void **this_base_cache); + +struct frame_base +{ + /* If non-NULL, a low-level unwinder that shares its implementation + with this high-level frame-base method. */ + const struct frame_unwind *unwind; + frame_this_base_ftype *this_base; + frame_this_locals_ftype *this_locals; + frame_this_args_ftype *this_args; +}; + +#endif diff --git a/gdb/i386-cygwin-tdep.c b/gdb/i386-cygwin-tdep.c new file mode 100644 index 0000000..5911ec9 --- /dev/null +++ b/gdb/i386-cygwin-tdep.c @@ -0,0 +1,86 @@ +/* Target-dependent code for Cygwin running on i386's, for GDB. + Copyright 2003 Free Software Foundation, Inc. + +This file is part of GDB. + +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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" + +#include "gdb_string.h" +#include "gdbcore.h" +#include "i386-tdep.h" +#include "osabi.h" +#include "frame.h" +#include "dummy-frame.h" + +static int +i386_cygwin_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe) +{ + /* In the context where this is used, we get the saved PC before we've + successfully unwound far enough to be sure what we've got (it may + be a signal handler caller). If we're dealing with a signal + handler caller, this will return valid, which is fine. If not, + it'll make the correct test. */ + return ((get_frame_type (thisframe) == SIGTRAMP_FRAME) || chain != 0); +} +/* Return the chain-pointer for FRAME. In the case of the i386, the + frame's nominal address is the address of a 4-byte word containing + the calling frame's address. */ +static CORE_ADDR +i386_cygwin_frame_chain (struct frame_info *frame) +{ + if (pc_in_dummy_frame (get_frame_pc (frame))) + return get_frame_base (frame); + + if (get_frame_type (frame) == SIGTRAMP_FRAME + || i386_frameless_signal_p (frame)) + return get_frame_base (frame); + + return read_memory_unsigned_integer (get_frame_base (frame), 4); +} + +static void +i386_cygwin_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->struct_return = reg_struct_return; + set_gdbarch_deprecated_frame_chain (gdbarch, i386_cygwin_frame_chain); + set_gdbarch_deprecated_frame_chain_valid (gdbarch, i386_cygwin_frame_chain_valid); +} + +static enum gdb_osabi +i386_cygwin_osabi_sniffer (bfd * abfd) +{ + char *target_name = bfd_get_target (abfd); + + /* Interix also uses pei-i386. + We need a way to distinguish between the two. */ + if (strcmp (target_name, "pei-i386") == 0) + return GDB_OSABI_CYGWIN; + + return GDB_OSABI_UNKNOWN; +} + +void +_initialize_i386_cygwin_tdep (void) +{ + gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour, + i386_cygwin_osabi_sniffer); + + gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_CYGWIN, + i386_cygwin_init_abi); +} diff --git a/gdb/infttrace.h b/gdb/infttrace.h new file mode 100644 index 0000000..d3330e3 --- /dev/null +++ b/gdb/infttrace.h @@ -0,0 +1,28 @@ +/* Low level Unix child interface to ttrace, for GDB when running under HP-UX. + + Copyright 2003 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef INFTTRACE_H +#define INFTTRACE_H + +extern int parent_attach_all (int, PTRACE_ARG3_TYPE, int); +extern pid_t hppa_switched_threads (pid_t gdb_pid); + +#endif diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c new file mode 100644 index 0000000..eb1d67a --- /dev/null +++ b/gdb/mi/mi-cmd-file.c @@ -0,0 +1,67 @@ +/* MI Command Set - breakpoint and watchpoint commands. + Copyright 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Cygnus Solutions (a Red Hat company). + + This file is part of GDB. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "mi-cmds.h" +#include "mi-getopt.h" +#include "ui-out.h" +#include "symtab.h" +#include "source.h" + +/* Return to the client the absolute path and line number of the + current file being executed. */ + +enum mi_cmd_result +mi_cmd_file_list_exec_source_file(char *command, char **argv, int argc) +{ + struct symtab_and_line st; + int optind = 0; + char *optarg; + + if ( !mi_valid_noargs("mi_cmd_file_list_exec_source_file", argc, argv) ) + error ("mi_cmd_file_list_exec_source_file: Usage: No args"); + + + /* Set the default file and line, also get them */ + set_default_source_symtab_and_line(); + st = get_current_source_symtab_and_line(); + + /* We should always get a symtab. + Apparently, filename does not need to be tested for NULL. + The documentation in symtab.h suggests it will always be correct */ + if (!st.symtab) + error ("mi_cmd_file_list_exec_source_file: No symtab"); + + /* Extract the fullname if it is not known yet */ + if (st.symtab->fullname == NULL) + symtab_to_filename (st.symtab); + + /* We may not be able to open the file (not available). */ + if (st.symtab->fullname == NULL) + error ("mi_cmd_file_list_exec_source_file: File not found"); + + /* Print to the user the line, filename and fullname */ + ui_out_field_int (uiout, "line", st.line); + ui_out_field_string (uiout, "file", st.symtab->filename); + ui_out_field_string (uiout, "fullname", st.symtab->fullname); + + return MI_CMD_DONE; +} diff --git a/gdb/testsuite/gdb.arch/e500-abi.c b/gdb/testsuite/gdb.arch/e500-abi.c new file mode 100644 index 0000000..e215612 --- /dev/null +++ b/gdb/testsuite/gdb.arch/e500-abi.c @@ -0,0 +1,106 @@ +#include + +/* Test PowerPC SPU extensions. */ + +#define vector __attribute__((vector_size(8))) + +vector unsigned short f_vec; +vector short g_vec; +vector float h_vec; +vector float i_vec; +vector unsigned int l_vec; +vector int m_vec; +vector int n_vec; + +/* dummy variables used in the testfile */ +vector unsigned int a_vec_d = {1, 1}; +vector int b_vec_d = {0, 0}; +vector float c_vec_d = {1.0, 1.0}; +vector unsigned int d_vec_d = {0, 0}; +vector int e_vec_d = {1, 1}; +vector unsigned short f_vec_d = {1, 1, 1, 1}; +vector short g_vec_d = {1, 1, 1, 1}; +vector float h_vec_d = {1.0, 1.0}; +vector float i_vec_d = {2.0, 2.0}; +vector unsigned int l_vec_d = {0, 0}; +vector int m_vec_d = {0, 0}; + + +vector int +vec_func (vector unsigned int a_vec_f, + vector int b_vec_f, + vector float c_vec_f, + vector unsigned int d_vec_f, + vector int e_vec_f, + vector unsigned short f_vec_f, + vector short g_vec_f, + vector float h_vec_f, + vector float i_vec_f, + vector unsigned int l_vec_f, + vector int m_vec_f) +{ + vector int n_vec; + + + int x,y,z; + x = 2; + y = 3; + + z = x + y; + z++; + n_vec = __ev_and(a_vec_f, b_vec_f); + n_vec = __ev_or(c_vec_f, d_vec_f); + n_vec = __ev_or(e_vec_f, f_vec_f); + n_vec = __ev_and(g_vec_f, h_vec_f); + n_vec = __ev_and(i_vec_f, l_vec_f); + n_vec = __ev_or(m_vec_f, a_vec_f); + + return n_vec; +} + +void marker(void) {}; + +int +main (void) +{ + vector unsigned int a_vec; + vector int b_vec; + vector float c_vec; + vector unsigned int d_vec; + vector int e_vec; + + vector int res_vec; + + a_vec = (vector unsigned int)__ev_create_u64 ((uint64_t) 55); + b_vec = __ev_create_s64 ((int64_t) 66); + c_vec = (vector float) __ev_create_fs (3.14F, 2.18F); + d_vec = (vector unsigned int) __ev_create_u32 ((uint32_t) 5, (uint32_t) 4); + e_vec = (vector int) __ev_create_s32 ((int32_t) 5, (int32_t) 6); + f_vec = (vector unsigned short) __ev_create_u16 ((uint16_t) 6, (uint16_t) 6, (uint16_t) 7, (uint16_t) 1); + g_vec = (vector short) __ev_create_s16 ((int16_t) 6, (int16_t) 6, (int16_t) 7, (int16_t) 9); + h_vec = (vector float) __ev_create_sfix32_fs (3.0F, 2.0F); + i_vec = (vector float) __ev_create_ufix32_fs (3.0F, 2.0F); + l_vec = (vector unsigned int) __ev_create_ufix32_u32 (3U, 5U); + m_vec = (vector int) __ev_create_sfix32_s32 (6, 9); + + marker (); + +#if 0 +/* This line is useful for cut-n-paste from a gdb session. */ +vec_func(a_vec,b_vec,c_vec,d_vec,e_vec,f_vec,g_vec,h_vec,i_vec,l_vec,m_vec) +#endif + + res_vec = vec_func (a_vec, /* goes in r3 */ + b_vec, /* goes in r4 */ + c_vec, /* goes in r5 */ + d_vec, /* goes in r6 */ + e_vec, /* goes in r7 */ + f_vec, /* goes in r8 */ + g_vec, /* goes in r9 */ + h_vec, /* goes in r10 */ + i_vec, /* goes in stack */ + l_vec, /* goes in stack */ + m_vec); /* goes in stack */ + + return 0; +} diff --git a/gdb/testsuite/gdb.arch/e500-abi.exp b/gdb/testsuite/gdb.arch/e500-abi.exp new file mode 100644 index 0000000..0d11ad3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/e500-abi.exp @@ -0,0 +1,90 @@ +# Copyright 2003 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu +# + +# Tests for Powerpc e500 ABI + + +if $tracelevel then { + strace $tracelevel +} + +# +# This file uses e500-abi.c for input. +# + +set prms_id 0 +set bug_id 0 + +if ![istarget "powerpc-*eabispe"] then { + verbose "Skipping e500 abi tests." + return +} + +set testfile "e500-abi" +set binfile ${objdir}/${subdir}/${testfile} + +set src1 ${srcdir}/${subdir}/${testfile}.c + +if { [gdb_compile ${src1} ${binfile} executable {debug additional_flags=-w}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# +# Run to `main' where we begin our tests. +# + +if ![runto_main] then { + gdb_suppress_tests +} + +gdb_test "b marker" "Breakpoint 2 at.*file.*e500-abi.c, line \[0-9\]+." "break marker" +gdb_test "continue" "Breakpoint 2.*marker.*e500-abi.c.*" "continue to marker" +gdb_test "finish" "Run till exit from .0.*marker.*at.*e500-abi.c.*main \\(\\) at.*e500-abi.c.*res_vec = vec_func \\(a_vec,.*goes in r3.*" "back to main (1)" + +# now all the arguments of vec_func are initialized + +set pattern "vec_func .a_vec_f=.0, 55., b_vec_f=.0, 66., c_vec_f=.3.14.*2.18.*, d_vec_f=.5, 4., e_vec_f=.5, 6., f_vec_f=.6, 6, 7, 1., g_vec_f=.6, 6, 7, 9., h_vec_f=.3, 2., i_vec_f=.3, 2., l_vec_f=.3, 5., m_vec_f=.6, 9.." + +set pattern1 $pattern +append pattern1 " at.*e500-abi.c.*x = 2;" + +# Now let's call the function. This function has > 8 args, +# the last ones will go on the stack. +gdb_test "p vec_func(a_vec,b_vec,c_vec,d_vec,e_vec,f_vec,g_vec,h_vec,i_vec,l_vec,m_vec)" \ +".\[0-9\]+ = .6, 63." "call inferior function with vectors (1) " + +# Let's call the function again with dummy arguments. This is to clean +# up the contents of the ev registers before the next call. +gdb_test "p vec_func(a_vec_d,b_vec_d,c_vec_d,d_vec_d,e_vec_d,f_vec_d,g_vec_d,h_vec_d,i_vec_d,l_vec_d,m_vec_d)" \ +".\[0-9\]+ = .1, 1." "call inferior function with vectors (2) " + +# Let's step into the function, to see if the args are printed correctly. +gdb_test "step" \ + $pattern1 \ + "step into vec_func" + +# Let's see if the result is returned correctly. +gdb_test "finish" \ + "Run till exit from .0.* at.*e500-abi.c.*main.*res_vec = vec_func .a_vec,.*goes in r3.*Value returned is.*= .6, 63." \ + "vector value returned correctly" diff --git a/gdb/testsuite/gdb.arch/e500-regs.c b/gdb/testsuite/gdb.arch/e500-regs.c new file mode 100644 index 0000000..bae5f39 --- /dev/null +++ b/gdb/testsuite/gdb.arch/e500-regs.c @@ -0,0 +1,38 @@ +#include +#include + +#define vector __attribute__((vector_size(8))) + + +vector int +vector_fun (vector int a, vector int b) +{ + vector int c; + a = (vector int) __ev_create_s32 (2, 2); + b = (vector int) __ev_create_s32 (3, 3); + + c = __ev_and (a, b); + return c; +} + +int +main () +{ + vector int y; + vector int x; + vector int z; + int a; + + /* This line may look unnecessary but we do need it, because we want to + have a line to do a next over (so that gdb refetches the registers) + and we don't want the code to change any vector registers. + The splat operations below modify the VRs, + so we don't want to execute them yet. */ + a = 9; + x = (vector int) __ev_create_s32 (-2, -2); + y = (vector int) __ev_create_s32 (1, 1); + + z = vector_fun (x, y); + + return 0; +} diff --git a/gdb/testsuite/gdb.arch/e500-regs.exp b/gdb/testsuite/gdb.arch/e500-regs.exp new file mode 100644 index 0000000..9224704 --- /dev/null +++ b/gdb/testsuite/gdb.arch/e500-regs.exp @@ -0,0 +1,229 @@ +# Copyright 2003 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu +# + +# Tests for Powerpc E500 register setting and fetching + +if $tracelevel then { + strace $tracelevel +} + +# +# Test the use of registers, especially E500 registers, for Powerpc. +# This file uses e500-regs.c for input. +# + +set prms_id 0 +set bug_id 0 + +if ![istarget "powerpc-*eabispe"] then { + verbose "Skipping e500 register tests." + return +} + +set testfile "e500-regs" +set binfile ${objdir}/${subdir}/${testfile} +set src1 ${srcdir}/${subdir}/${testfile}.c + +if { [gdb_compile ${src1} ${binfile} executable {debug additional_flags=-w}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# +# Run to `main' where we begin our tests. +# + +if ![runto_main] then { + gdb_suppress_tests +} + +# set all the registers integer portions to 1 +for {set i 0} {$i < 32} {incr i 1} { + for {set j 0} {$j < 2} {incr j 1} { + gdb_test "set \$ev$i.v2_int32\[$j\] = 1" "" "set reg ev$i.v4si.f\[$j\]" + } +} + +# Now execute some target code, so that GDB's register cache is flushed. + +#gdb_test "next" "" "" + +send_gdb "show endian\n" +gdb_expect { + -re "(The target endianness is set automatically .currently )(big|little)( endian.*)$gdb_prompt $" { + pass "endianness" + set endianness $expect_out(2,string) + } + -re ".*$gdb_prompt $" { + fail "couldn't get endianness" + } + timeout { fail "(timeout) endianness" } +} + +# And then read the E500 registers back, to see that +# a) the register write above worked, and +# b) the register read (below) also works. + +if {$endianness == "big"} { +set vector_register ".uint64 = 0x100000001, v2_float = .0x0, 0x0., v2_int32 = .0x1, 0x1., v4_int16 = .0x0, 0x1, 0x0, 0x1., v8_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." +} else { +set vector_register ".uint64 = 0x100000001, v2_float = .0x0, 0x0., v2_int32 = .0x1, 0x1., v4_int16 = .0x1, 0x0, 0x1, 0x0., v8_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.." +} + +for {set i 0} {$i < 32} {incr i 1} { + gdb_test "info reg ev$i" "ev$i.*$vector_register" "info reg ev$i" +} + +# Test wether the GPRs are updated accordingly. (GPRs are just the lower +# 32 bits of the EV registers.) + +set general_register "0x1\[ \t\]+1" + +for {set i 0} {$i < 32} {incr i 1} { + gdb_test "info reg r$i" "r$i.*$general_register" "info reg r$i" +} + +# Now redo the same tests, but using the print command. +# Note: in LE case, the char array is printed WITHOUT the last character. +# Gdb treats the terminating null char in the array like the terminating +# null char in a string and doesn't print it. This is not a failure, but +# the way gdb works. + +if {$endianness == "big"} { + set decimal_vector ".uint64 = 4294967297, v2_float = .1.*e-45, 1.*e-45., v2_int32 = .1, 1., v4_int16 = .0, 1, 0, 1., v8_int8 = ..000.000.000.001.000.000.000.001.." +} else { + set decimal_vector ".uint64 = 0x0000000100000001, v2_float = .1.*e-45, 1.*e-45., v2_int32 = .1, 1., v4_int16 = .1, 0, 1, 0., v8_int8 = ..001.000.000.000.001.000.000.000.001.000.000.000.001.000.000.." +} + +for {set i 0} {$i < 32} {incr i 1} { + gdb_test "print \$ev$i" ".* = $decimal_vector" "print ev$i" +} + +for {set i 0} {$i < 32} {incr i 1} { + set pattern$i ".*ev$i.*" + append pattern$i $vector_register +} + +send_gdb "info vector\n" +gdb_expect_list "info vector" ".*$gdb_prompt $" { +[$pattern0] +[$pattern1] +[$pattern2] +[$pattern3] +[$pattern4] +[$pattern5] +[$pattern6] +[$pattern7] +[$pattern8] +[$pattern9] +[$pattern10] +[$pattern11] +[$pattern12] +[$pattern13] +[$pattern14] +[$pattern15] +[$pattern16] +[$pattern17] +[$pattern18] +[$pattern19] +[$pattern20] +[$pattern21] +[$pattern22] +[$pattern23] +[$pattern24] +[$pattern25] +[$pattern26] +[$pattern27] +[$pattern28] +[$pattern29] +[$pattern30] +[$pattern31] +} + +# We must restart everything, because we have set important registers to +# some unusual values. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +if ![runto_main] then { + gdb_suppress_tests +} + +gdb_test "break vector_fun" \ + "Breakpoint 2 at.*e500-regs.c, line \[0-9\]+\\." \ + "Set breakpoint at vector_fun" + +# Actually it is nuch easier to see these results printed in hex. +# gdb_test "set output-radix 16" \ +# "Output radix now set to decimal 16, hex 10, octal 20." \ +# "Set output radix to hex" + +gdb_test "continue" \ + "Breakpoint 2, vector_fun .a=.-2, -2., b=.1, 1.*e500-regs.c.*ev_create_s32 .2, 2.;" \ + "continue to vector_fun" + +# Do a next over the assignment to vector 'a'. +gdb_test "next" ".*b = \\(vector int\\) __ev_create_s32 \\(3, 3\\);" \ + "next (1)" + +# Do a next over the assignment to vector 'b'. +gdb_test "next" "c = __ev_and \\(a, b\\);" \ + "next (2)" + +# Now 'a' should be '0x02020202...' and 'b' should be '0x03030303...' +gdb_test "print/x a" \ + ".*= .0x2, 0x2." \ + "print vector parameter a" + +gdb_test "print/x b" \ + ".*= .0x3, 0x3." \ + "print vector parameter b" + +# If we do an 'up' now, and print 'x' and 'y' we should see the values they +# have in main, not the values they have in vector_fun. +gdb_test "up" ".1.*main \\(\\) at.*e500-regs.c.*z = vector_fun \\(x, y\\);" \ + "up to main" + +gdb_test "print x" \ + ".*= .-2, -2." \ + "print vector x" + +gdb_test "print y" \ + ".*= .1, 1." \ + "print vector y" + +# now go back to vector_func and do a finish, to see if we can print the return +# value correctly. + +gdb_test "down" \ + ".0 vector_fun \\(a=.2, 2., b=.3, 3.\\) at.*e500-regs.c.*c = __ev_and \\(a, b\\);" \ + "down to vector_fun" + +gdb_test "finish" \ + "Run till exit from .0 vector_fun \\(a=.2, 2., b=.3, 3.\\) at.*e500-regs.c.*main \\(\\) at.*e500-regs.c.*z = vector_fun \\(x, y\\);.*Value returned is.*= .2, 2." \ + "finish returned correct value" + + + diff --git a/gdb/testsuite/gdb.asm/m68hc11.inc b/gdb/testsuite/gdb.asm/m68hc11.inc new file mode 100644 index 0000000..90795e3 --- /dev/null +++ b/gdb/testsuite/gdb.asm/m68hc11.inc @@ -0,0 +1,49 @@ + comment "subroutine prologue" + .macro gdbasm_enter + ldx _.frame + pshx + sts _.frame + .endm + + comment "subroutine epilogue" + .macro gdbasm_leave + pulx + stx _.frame + rts + .endm + + .macro gdbasm_call subr + jsr \subr + .endm + + .macro gdbasm_several_nops + nop + nop + nop + nop + .endm + + comment "exit (0)" + .macro gdbasm_exit0 + clra + clrb + wai + .endm + + comment "crt0 startup" + .macro gdbasm_startup + .sect .data + .globl _.frame +_.frame: .word 0 + .previous + lds #0x2000 + clr _.frame + clr _.frame+1 + .endm + + comment "Declare a data variable" + .macro gdbasm_datavar name value + .data +\name: + .long \value + .endm diff --git a/gdb/testsuite/gdb.base/gdb1090.c b/gdb/testsuite/gdb.base/gdb1090.c new file mode 100644 index 0000000..cd9e2cd --- /dev/null +++ b/gdb/testsuite/gdb.base/gdb1090.c @@ -0,0 +1,48 @@ +/* Test program for multi-register variable. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of the gdb testsuite. + + 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 2 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + This file was written by Michael Elizabeth Chastain (mec@shout.net). */ + +struct s_2_by_4 +{ + int field_0; + int field_1; +}; + +void marker (struct s_2_by_4 s_whatever) +{ + s_whatever = s_whatever; + return; +} + +void foo () +{ + /* I want this variable in a register but I can't really force it */ + register struct s_2_by_4 s24; + s24.field_0 = 1170; + s24.field_1 = 64701; + marker (s24); + return; +} + +int main () +{ + foo (); +} diff --git a/gdb/testsuite/gdb.base/gdb1090.exp b/gdb/testsuite/gdb.base/gdb1090.exp new file mode 100644 index 0000000..20da3b1 --- /dev/null +++ b/gdb/testsuite/gdb.base/gdb1090.exp @@ -0,0 +1,67 @@ +# Copyright 2003 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Tests for PR gdb/1090. +# 2003-02-23 Michael Chastain + +# This file is part of the gdb testsuite. + +if $tracelevel then { + strace $tracelevel + } + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +set testfile "gdb1090" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if ![runto marker] then { + perror "couldn't run to breakpoint" + continue +} +gdb_test "up" ".*foo.*" "up from marker" + +send_gdb "print s24\n" +gdb_expect { + -re "\\\$\[0-9\]* = \\{field_0 = 1170, field_1 = 64701\\}\r\n$gdb_prompt $" { + pass "print s24" + } + -re "\\\$\[0-9\]* = \\{field_0 = 1170, field_1 = .*\\}\r\n$gdb_prompt $" { + # happens with gcc 2.95.3, which actually puts s24 in registers. + # gdb cannot find the second register and prints garbage. + kfail "gdb/1090" "print s24" + } + -re ".*$gdb_prompt $" { + fail "print s24" + } + timeout { + fail "print s24 (timeout)" + } +} diff --git a/gdb/testsuite/gdb.c++/maint.exp b/gdb/testsuite/gdb.c++/maint.exp new file mode 100644 index 0000000..6e1da97 --- /dev/null +++ b/gdb/testsuite/gdb.c++/maint.exp @@ -0,0 +1,79 @@ +# Copyright 2003 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + + +# This file tests C++-specific maintenance commands and help on those. + +# Currently, no source file is used. + +if $tracelevel then { + strace $tracelevel + } + +# Test the help messages. + +proc test_help {} { + gdb_test "help maintenance cplus" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous." + + gdb_test "help maint cp" "C\\+\\+ maintenance commands.\r\n\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous." + + gdb_test "maint cp" "\"maintenance cplus\" must be followed by the name of a command.\r\nList of maintenance cplus subcommands:\r\n\r\nmaintenance cplus first_component -- Print the first class/namespace component of NAME\r\n\r\nType \"help maintenance cplus\" followed by maintenance cplus subcommand name for full documentation.\r\nCommand name abbreviations are allowed if unambiguous." + + gdb_test "help maint cp first_component" "Print the first class/namespace component of NAME." +} + +# This is used when NAME should contain only a single component. Be +# careful to make sure that parentheses get escaped properly. +proc test_single_component {name} { + set matchname [string_to_regexp "$name"] + gdb_test "maint cp first_component $name" "$matchname" +} + +proc test_first_component {} { + test_single_component "foo" + test_single_component "operator<<" + test_single_component "operator>>" + test_single_component "operator ->" + test_single_component "operator()" + test_single_component "operator>" + test_single_component "operator<" + test_single_component "operator ->" + test_single_component "operator ->" + + test_single_component "foo()" + test_single_component "foo(int)" + test_single_component "foo(X::Y)" + test_single_component "foo(X::Y, A::B)" + test_single_component "foo(std::basic_streambuf >)" + test_single_component "operator>(X::Y)" + + gdb_test "maint cp first_component foo::bar" "foo" + gdb_test "maint cp first_component foo::bar::baz" "foo" + gdb_test "maint cp first_component C::bar" "C" + gdb_test "maint cp first_component C > >::bar" "C > >" +} + +gdb_exit +gdb_start + +test_help +test_first_component + +gdb_exit +return 0 diff --git a/gdb/testsuite/gdb.gdb/observer.exp b/gdb/testsuite/gdb.gdb/observer.exp new file mode 100644 index 0000000..390df8d --- /dev/null +++ b/gdb/testsuite/gdb.gdb/observer.exp @@ -0,0 +1,274 @@ +# Copyright 2003 +# 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Joel Brobecker (brobecker@gnat.com), derived +# from xfullpath.exp. + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +# are we on a target board +if [is_remote target] { + return +} + +if [istarget "m68k*-*-hpux*"] then { + # The top-level makefile passes CFLAGS= (no -g) for hp300. This probably + # should be fixed (it is only needed for gcc bootstrapping, not gdb), + # but until then..... + setup_xfail "*-*-*" + fail "cannot test self if compiled without debug info" + return -1 +} + +proc setup_test { executable } { + global gdb_prompt + global timeout + + # load yourself into the debugger + # This can take a relatively long time, particularly for testing where + # the executable is being accessed over a network, or where gdb does not + # support partial symbols for a particular target and has to load the + # entire symbol table. Set the timeout to 10 minutes, which should be + # adequate for most environments (it *has* timed out with 5 min on a + # SPARCstation SLC under moderate load, so this isn't unreasonable). + # After gdb is started, set the timeout to 30 seconds for the duration + # of this test, and then back to the original value. + + set oldtimeout $timeout + set timeout 600 + verbose "Timeout is now $timeout seconds" 2 + if {[gdb_load $executable] <0} then { + set timeout $oldtimeout + verbose "Timeout is now $timeout seconds" 2 + return -1 + } + set timeout $oldtimeout + verbose "Timeout is now $timeout seconds" 2 + + # Set a breakpoint at main + gdb_test "break captured_main" \ + "Breakpoint.*at.* file.*, line.*" \ + "breakpoint in captured_main" + + # run yourself + # It may take a very long time for the inferior gdb to start (lynx), + # so we bump it back up for the duration of this command. + set timeout 600 + + set description "run until breakpoint at captured_main" + send_gdb "run -nw\n" + gdb_expect { + -re "Starting program.*Breakpoint \[0-9\]+,.*captured_main .data.* at .*main.c:.*$gdb_prompt $" { + pass "$description" + } + -re "Starting program.*Breakpoint \[0-9\]+,.*captured_main .data.*$gdb_prompt $" { + xfail "$description (line numbers scrambled?)" + } + -re "vfork: No more processes.*$gdb_prompt $" { + fail "$description (out of virtual memory)" + set timeout $oldtimeout + verbose "Timeout is now $timeout seconds" 2 + return -1 + } + -re ".*$gdb_prompt $" { + fail "$description" + set timeout $oldtimeout + verbose "Timeout is now $timeout seconds" 2 + return -1 + } + timeout { + fail "$description (timeout)" + } + } + + set timeout $oldtimeout + verbose "Timeout is now $timeout seconds" 2 + + return 0 +} + +proc attach_first_observer { } { + gdb_test "set \$first_obs = observer_attach_normal_stop (&observer_test_first_notification_function)" \ + "" "attach first observer" +} + +proc attach_second_observer { } { + gdb_test "set \$second_obs = observer_attach_normal_stop (&observer_test_second_notification_function)" \ + "" "attach second observer" +} + +proc attach_third_observer { } { + gdb_test "set \$third_obs = observer_attach_normal_stop (&observer_test_third_notification_function)" \ + "" "attach third observer" +} + +proc detach_first_observer { } { + gdb_test "call observer_detach_normal_stop (\$first_obs)" \ + "" "detach first observer" +} + +proc detach_second_observer { } { + gdb_test "call observer_detach_normal_stop (\$second_obs)" \ + "" "detach second observer" +} + +proc detach_third_observer { } { + gdb_test "call observer_detach_normal_stop (\$third_obs)" \ + "" "detach third observer" +} + +proc check_counters { first second third message } { + gdb_test "print observer_test_first_observer" \ + ".\[0-9\]+ =.*$first" \ + "check first observer counter value ($message)" + gdb_test "print observer_test_second_observer" \ + ".\[0-9\]+ =.*$second" \ + "check second observer counter value ($message)" + gdb_test "print observer_test_third_observer" \ + ".\[0-9\]+ =.*$third" \ + "check third observer counter value ($message)" +} + +proc reset_counters { } { + gdb_test "set variable observer_test_first_observer = 0" "" \ + "reset first observer counter" + gdb_test "set variable observer_test_second_observer = 0" "" \ + "reset second observer counter" + gdb_test "set variable observer_test_third_observer = 0" "" \ + "reset third observer counter" +} + +proc test_normal_stop_notifications { first second third message } { + reset_counters + gdb_test "call observer_notify_normal_stop ()" "" \ + "sending notification ($message)" + check_counters $first $second $third $message +} + +proc test_observer_normal_stop { executable } { + + set setup_result [setup_test $executable] + if {$setup_result <0} then { + return -1 + } + + # First, try sending a notification without any observer attached. + test_normal_stop_notifications 0 0 0 "no observer" + + # Now, attach one observer, and send a notification. + attach_second_observer + test_normal_stop_notifications 0 1 0 "one observer" + + # Remove the observer, and send a notification. + detach_second_observer + test_normal_stop_notifications 0 0 0 "no observer" + + # With a new observer. + attach_first_observer + test_normal_stop_notifications 1 0 0 "a new observer" + + # With 2 observers. + attach_second_observer + test_normal_stop_notifications 1 1 0 "2 observers" + + # With 3 observers. + attach_third_observer + test_normal_stop_notifications 1 1 1 "3 observers" + + # Remove middle observer. + detach_second_observer + test_normal_stop_notifications 1 0 1 "middle observer removed" + + # Remove first observer. + detach_first_observer + test_normal_stop_notifications 0 0 1 "first observer removed" + + # Remove last observer. + detach_third_observer + test_normal_stop_notifications 0 0 0 "last observer removed" + + # Go back to 3 observers, and remove them in a different order... + attach_first_observer + attach_second_observer + attach_third_observer + test_normal_stop_notifications 1 1 1 "3 observers again" + + # Remove the third observer. + detach_third_observer + test_normal_stop_notifications 1 1 0 "third observer removed" + + # Remove the second observer. + detach_second_observer + test_normal_stop_notifications 1 0 0 "second observer removed" + + # Remove the first observer, no more observers. + detach_first_observer + test_normal_stop_notifications 0 0 0 "last observer removed" + + return 0 +} + +# Find a pathname to a file that we would execute if the shell was asked +# to run $arg using the current PATH. + +proc find_gdb { arg } { + + # If the arg directly specifies an existing executable file, then + # simply use it. + + if [file executable $arg] then { + return $arg + } + + set result [which $arg] + if [string match "/" [ string range $result 0 0 ]] then { + return $result + } + + # If everything fails, just return the unqualified pathname as default + # and hope for best. + + return $arg +} + +# Run the test with self. +# Copy the file executable file in case this OS doesn't like to edit its own +# text space. + +set GDB_FULLPATH [find_gdb $GDB] + +# Remove any old copy lying around. +remote_file host delete x$tool + +gdb_start +set file [remote_download host $GDB_FULLPATH x$tool] +set result [test_observer_normal_stop $file]; +gdb_exit; +catch "remote_file host delete $file"; + +if {$result <0} then { + warning "Couldn't test self" + return -1 +} diff --git a/gdb/testsuite/gdb.mi/mi-file.exp b/gdb/testsuite/gdb.mi/mi-file.exp new file mode 100644 index 0000000..2ffdcbf --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-file.exp @@ -0,0 +1,65 @@ +# Copyright 1999 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# +# Test essential Machine interface (MI) operations +# +# Verify that, using the MI, we can run a simple program and perform basic +# debugging activities like: insert breakpoints, run the program, +# step, next, continue until it ends and, last but not least, quit. +# +# The goal is not to test gdb functionality, which is done by other tests, +# but to verify the correct output response to MI operations. +# + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +gdb_exit +if [mi_gdb_start] { + continue +} + +set testfile "basics" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DFAKEARGV}] != "" } { + gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." +} + +mi_delete_breakpoints +mi_gdb_reinitialize_dir $srcdir/$subdir +mi_gdb_load ${binfile} + +proc test_tbreak_creation_and_listing {} { + global srcfile + global srcdir + global subdir + set srcfilepath [string_to_regexp ${srcdir}/${subdir}/${srcfile}] + + # get the path and absolute path to the current executable + mi_gdb_test "111-file-list-exec-source-file" \ + "111\\\^done,line=\"23\",file=\"${srcfilepath}\",fullname=\"/.*/${srcfile}\"" \ + "request path info of current source file (${srcfile})" +} + +test_tbreak_creation_and_listing + +mi_gdb_exit +return 0 diff --git a/include/elf/xtensa.h b/include/elf/xtensa.h new file mode 100644 index 0000000..394ee41 --- /dev/null +++ b/include/elf/xtensa.h @@ -0,0 +1,87 @@ +/* Xtensa ELF support for BFD. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the Xtensa ELF ABI. */ + +#ifndef _ELF_XTENSA_H +#define _ELF_XTENSA_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_xtensa_reloc_type) + RELOC_NUMBER (R_XTENSA_NONE, 0) + RELOC_NUMBER (R_XTENSA_32, 1) + RELOC_NUMBER (R_XTENSA_RTLD, 2) + RELOC_NUMBER (R_XTENSA_GLOB_DAT, 3) + RELOC_NUMBER (R_XTENSA_JMP_SLOT, 4) + RELOC_NUMBER (R_XTENSA_RELATIVE, 5) + RELOC_NUMBER (R_XTENSA_PLT, 6) + RELOC_NUMBER (R_XTENSA_OP0, 8) + RELOC_NUMBER (R_XTENSA_OP1, 9) + RELOC_NUMBER (R_XTENSA_OP2, 10) + RELOC_NUMBER (R_XTENSA_ASM_EXPAND, 11) + RELOC_NUMBER (R_XTENSA_ASM_SIMPLIFY, 12) + RELOC_NUMBER (R_XTENSA_GNU_VTINHERIT, 15) + RELOC_NUMBER (R_XTENSA_GNU_VTENTRY, 16) +END_RELOC_NUMBERS (R_XTENSA_max) + +/* Processor-specific flags for the ELF header e_flags field. */ + +/* Four-bit Xtensa machine type field. */ +#define EF_XTENSA_MACH 0x0000000f + +/* Various CPU types. */ +#define E_XTENSA_MACH 0x00000000 + +/* Leave bits 0xf0 alone in case we ever have more than 16 cpu types. + Highly unlikely, but what the heck. */ + +#define EF_XTENSA_XT_INSN 0x00000100 +#define EF_XTENSA_XT_LIT 0x00000200 + + +/* Processor-specific dynamic array tags. */ + +/* Offset of the table that records the GOT location(s). */ +#define DT_XTENSA_GOT_LOC_OFF 0x70000000 + +/* Number of entries in the GOT location table. */ +#define DT_XTENSA_GOT_LOC_SZ 0x70000001 + + +/* Definitions for instruction and literal property tables. The + instruction tables for ".gnu.linkonce.t.*" sections are placed in + the following sections: + + instruction tables: .gnu.linkonce.x.* + literal tables: .gnu.linkonce.p.* +*/ + +#define XTENSA_INSN_SEC_NAME ".xt.insn" +#define XTENSA_LIT_SEC_NAME ".xt.lit" + +typedef struct property_table_entry_t +{ + bfd_vma address; + bfd_vma size; +} property_table_entry; + +#endif /* _ELF_XTENSA_H */ diff --git a/include/xtensa-config.h b/include/xtensa-config.h new file mode 100644 index 0000000..b47cbd7 --- /dev/null +++ b/include/xtensa-config.h @@ -0,0 +1,64 @@ +/* Xtensa configuration settings. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. + + 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 2, 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef XTENSA_CONFIG_H +#define XTENSA_CONFIG_H + +/* The macros defined here match those with the same names in the Xtensa + compile-time HAL (Hardware Abstraction Layer). Please refer to the + Xtensa System Software Reference Manual for documentation of these + macros. */ + +#define XCHAL_HAVE_BE 1 +#define XCHAL_HAVE_DENSITY 1 +#define XCHAL_HAVE_MAC16 0 +#define XCHAL_HAVE_MUL16 0 +#define XCHAL_HAVE_MUL32 0 +#define XCHAL_HAVE_DIV32 0 +#define XCHAL_HAVE_NSA 1 +#define XCHAL_HAVE_MINMAX 0 +#define XCHAL_HAVE_SEXT 0 +#define XCHAL_HAVE_LOOPS 1 +#define XCHAL_HAVE_BOOLEANS 0 +#define XCHAL_HAVE_FP 0 +#define XCHAL_HAVE_FP_DIV 0 +#define XCHAL_HAVE_FP_RECIP 0 +#define XCHAL_HAVE_FP_SQRT 0 +#define XCHAL_HAVE_FP_RSQRT 0 +#define XCHAL_HAVE_WINDOWED 1 + +#define XCHAL_ICACHE_SIZE 8192 +#define XCHAL_DCACHE_SIZE 8192 +#define XCHAL_ICACHE_LINESIZE 16 +#define XCHAL_DCACHE_LINESIZE 16 +#define XCHAL_ICACHE_LINEWIDTH 4 +#define XCHAL_DCACHE_LINEWIDTH 4 +#define XCHAL_DCACHE_IS_WRITEBACK 0 + +#define XCHAL_HAVE_MMU 1 +#define XCHAL_MMU_MIN_PTE_PAGE_SIZE 12 + +#define XCHAL_HAVE_DEBUG 1 +#define XCHAL_NUM_IBREAK 2 +#define XCHAL_NUM_DBREAK 2 +#define XCHAL_DEBUGLEVEL 4 + +#define XCHAL_EXTRA_SA_SIZE 0 +#define XCHAL_EXTRA_SA_ALIGN 1 + +#endif /* !XTENSA_CONFIG_H */ diff --git a/include/xtensa-isa-internal.h b/include/xtensa-isa-internal.h new file mode 100644 index 0000000..d2244c5 --- /dev/null +++ b/include/xtensa-isa-internal.h @@ -0,0 +1,114 @@ +/* Internal definitions for configurable Xtensa ISA support. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Use the statically-linked version for the GNU tools. */ +#define STATIC_LIBISA 1 + +#define ISA_INTERFACE_VERSION 3 + +struct config_struct +{ + char *param_name; + char *param_value; +}; + +/* Encode/decode function types for immediate operands. */ +typedef uint32 (*xtensa_immed_decode_fn) (uint32); +typedef xtensa_encode_result (*xtensa_immed_encode_fn) (uint32 *); + +/* Field accessor function types. */ +typedef uint32 (*xtensa_get_field_fn) (const xtensa_insnbuf); +typedef void (*xtensa_set_field_fn) (xtensa_insnbuf, uint32); + +/* PC-relative relocation function types. */ +typedef uint32 (*xtensa_do_reloc_fn) (uint32, uint32); +typedef uint32 (*xtensa_undo_reloc_fn) (uint32, uint32); + +/* Instruction decode function type. */ +typedef int (*xtensa_insn_decode_fn) (const xtensa_insnbuf); + +/* Instruction encoding template function type (each of these functions + returns a constant template; they exist only to make it easier for the + TIE compiler to generate endian-independent DLLs). */ +typedef xtensa_insnbuf (*xtensa_encoding_template_fn) (void); + + +typedef struct xtensa_operand_internal_struct +{ + char *operand_kind; /* e.g., "a", "f", "i", "l".... */ + char inout; /* '<', '>', or '='. */ + char isPCRelative; /* Is this a PC-relative offset? */ + xtensa_get_field_fn get_field; /* Get encoded value of the field. */ + xtensa_set_field_fn set_field; /* Set field with an encoded value. */ + xtensa_immed_encode_fn encode; /* Encode the operand value. */ + xtensa_immed_decode_fn decode; /* Decode the value from the field. */ + xtensa_do_reloc_fn do_reloc; /* Perform a PC-relative relocation. */ + xtensa_undo_reloc_fn undo_reloc; /* Undo a PC-relative relocation. */ +} xtensa_operand_internal; + + +typedef struct xtensa_iclass_internal_struct +{ + int num_operands; /* Size of "operands" array. */ + xtensa_operand_internal **operands; /* Array of operand structures. */ +} xtensa_iclass_internal; + + +typedef struct xtensa_opcode_internal_struct +{ + const char *name; /* Opcode mnemonic. */ + int length; /* Length in bytes of the insn. */ + xtensa_encoding_template_fn template; /* Fn returning encoding template. */ + xtensa_iclass_internal *iclass; /* Iclass for this opcode. */ +} xtensa_opcode_internal; + + +typedef struct opname_lookup_entry_struct +{ + const char *key; /* Opcode mnemonic. */ + xtensa_opcode opcode; /* Internal opcode number. */ +} opname_lookup_entry; + + +typedef struct xtensa_isa_internal_struct +{ + int is_big_endian; /* Endianness. */ + int insn_size; /* Maximum length in bytes. */ + int insnbuf_size; /* Number of insnbuf_words. */ + int num_opcodes; /* Total number for all modules. */ + xtensa_opcode_internal **opcode_table;/* Indexed by internal opcode #. */ + int num_modules; /* Number of modules (DLLs) loaded. */ + int *module_opcode_base; /* Starting opcode # for each module. */ + xtensa_insn_decode_fn *module_decode_fn; /* Decode fn for each module. */ + opname_lookup_entry *opname_lookup_table; /* Lookup table for each module. */ + struct config_struct *config; /* Table of configuration parameters. */ + int has_density; /* Is density option available? */ +} xtensa_isa_internal; + + +typedef struct xtensa_isa_module_struct +{ + const int (*get_num_opcodes_fn) (void); + xtensa_opcode_internal **(*get_opcodes_fn) (void); + int (*decode_insn_fn) (const xtensa_insnbuf); + struct config_struct *(*get_config_table_fn) (void); +} xtensa_isa_module; + +extern xtensa_isa_module xtensa_isa_modules[]; + diff --git a/include/xtensa-isa.h b/include/xtensa-isa.h new file mode 100644 index 0000000..54f750c --- /dev/null +++ b/include/xtensa-isa.h @@ -0,0 +1,230 @@ +/* Interface definition for configurable Xtensa ISA support. + Copyright 2003 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef XTENSA_LIBISA_H +#define XTENSA_LIBISA_H + +/* Use the statically-linked version for the GNU tools. */ +#define STATIC_LIBISA 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef uint32 +#define uint32 unsigned int +#endif + +/* This file defines the interface to the Xtensa ISA library. This library + contains most of the ISA-specific information for a particular Xtensa + processor. For example, the set of valid instructions, their opcode + encodings and operand fields are all included here. To support Xtensa's + configurability and user-defined instruction extensions (i.e., TIE), the + library is initialized by loading one or more dynamic libraries; only a + small set of interface code is present in the statically-linked portion + of the library. + + This interface basically defines four abstract data types. + + . an instruction buffer - for holding the raw instruction bits + . ISA info - information about the ISA as a whole + . opcode info - information about individual instructions + . operand info - information about specific instruction operands + + It would be nice to implement these as classes in C++, but the library is + implemented in C to match the expectations of the GNU tools. + Instead, the interface defines a set of functions to access each data + type. With the exception of the instruction buffer, the internal + representations of the data structures are hidden. All accesses must be + made through the functions defined here. */ + +typedef void* xtensa_isa; +typedef void* xtensa_operand; + + +/* Opcodes are represented here using sequential integers beginning with 0. + The specific value used for a particular opcode is only fixed for a + particular instantiation of an xtensa_isa structure, so these values + should only be used internally. */ +typedef int xtensa_opcode; + +/* Define a unique value for undefined opcodes ("static const int" doesn't + seem to work for this because EGCS 1.0.3 on i686-Linux without -O won't + allow it to be used as an initializer). */ +#define XTENSA_UNDEFINED -1 + + +typedef int libisa_module_specifier; + +extern xtensa_isa xtensa_isa_init (void); + + +/* Instruction buffers. */ + +typedef uint32 xtensa_insnbuf_word; +typedef xtensa_insnbuf_word *xtensa_insnbuf; + +/* Get the size in words of the xtensa_insnbuf array. */ +extern int xtensa_insnbuf_size (xtensa_isa); + +/* Allocate (with malloc) an xtensa_insnbuf of the right size. */ +extern xtensa_insnbuf xtensa_insnbuf_alloc (xtensa_isa); + +/* Release (with free) an xtensa_insnbuf of the right size. */ +extern void xtensa_insnbuf_free (xtensa_insnbuf); + +/* Inward and outward conversion from memory images (byte streams) to our + internal instruction representation. */ +extern void xtensa_insnbuf_to_chars (xtensa_isa, const xtensa_insnbuf, + char *); + +extern void xtensa_insnbuf_from_chars (xtensa_isa, xtensa_insnbuf, + const char *); + + +/* ISA information. */ + +/* Load the ISA information from a shared library. If successful, this returns + a value which identifies the ISA for use in subsequent calls to the ISA + library; otherwise, it returns NULL. Multiple ISAs can be loaded to support + heterogeneous multiprocessor systems. */ +extern xtensa_isa xtensa_load_isa (libisa_module_specifier); + +/* Extend an existing set of ISA information by loading an additional shared + library of ISA information. This is primarily intended for loading TIE + extensions. If successful, the return value is non-zero. */ +extern int xtensa_extend_isa (xtensa_isa, libisa_module_specifier); + +/* The default ISA. This variable is set automatically to the ISA most + recently loaded and is provided as a convenience. An exception is the GNU + opcodes library, where there is a fixed interface that does not allow + passing the ISA as a parameter and the ISA must be taken from this global + variable. (Note: Since this variable is just a convenience, it is not + exported when libisa is built as a DLL, due to the hassle of dealing with + declspecs.) */ +extern xtensa_isa xtensa_default_isa; + + +/* Deallocate an xtensa_isa structure. */ +extern void xtensa_isa_free (xtensa_isa); + +/* Get the maximum instruction size in bytes. */ +extern int xtensa_insn_maxlength (xtensa_isa); + +/* Get the total number of opcodes for this processor. */ +extern int xtensa_num_opcodes (xtensa_isa); + +/* Translate a mnemonic name to an opcode. Returns XTENSA_UNDEFINED if + the name is not a valid opcode mnemonic. */ +extern xtensa_opcode xtensa_opcode_lookup (xtensa_isa, const char *); + +/* Decode a binary instruction buffer. Returns the opcode or + XTENSA_UNDEFINED if the instruction is illegal. */ +extern xtensa_opcode xtensa_decode_insn (xtensa_isa, const xtensa_insnbuf); + + +/* Opcode information. */ + +/* Set the opcode field(s) in a binary instruction buffer. The operand + fields are set to zero. */ +extern void xtensa_encode_insn (xtensa_isa, xtensa_opcode, xtensa_insnbuf); + +/* Get the mnemonic name for an opcode. */ +extern const char * xtensa_opcode_name (xtensa_isa, xtensa_opcode); + +/* Find the length (in bytes) of an instruction. */ +extern int xtensa_insn_length (xtensa_isa, xtensa_opcode); + +/* Find the length of an instruction by looking only at the first byte. */ +extern int xtensa_insn_length_from_first_byte (xtensa_isa, char); + +/* Find the number of operands for an instruction. */ +extern int xtensa_num_operands (xtensa_isa, xtensa_opcode); + +/* Get the information about operand number "opnd" of a particular opcode. */ +extern xtensa_operand xtensa_get_operand (xtensa_isa, xtensa_opcode, int); + +/* Operand information. */ + +/* Find the kind of operand. There are three possibilities: + 1) PC-relative immediates (e.g., "l", "L"). These can be identified with + the xtensa_operand_isPCRelative function. + 2) non-PC-relative immediates ("i"). + 3) register-file short names (e.g., "a", "b", "m" and others defined + via TIE). */ +extern char * xtensa_operand_kind (xtensa_operand); + +/* Check if an operand is an input ('<'), output ('>'), or inout ('=') + operand. Note: The output operand of a conditional assignment + (e.g., movnez) appears here as an inout ('=') even if it is declared + in the TIE code as an output ('>'); this allows the compiler to + properly handle register allocation for conditional assignments. */ +extern char xtensa_operand_inout (xtensa_operand); + +/* Get and set the raw (encoded) value of the field for the specified + operand. The "set" function does not check if the value fits in the + field; that is done by the "encode" function below. */ +extern uint32 xtensa_operand_get_field (xtensa_operand, const xtensa_insnbuf); + +extern void xtensa_operand_set_field (xtensa_operand, xtensa_insnbuf, uint32); + + +/* Encode and decode operands. The raw bits in the operand field + may be encoded in a variety of different ways. These functions hide the + details of that encoding. The encode function has a special return type + (xtensa_encode_result) to indicate success or the reason for failure; the + encoded value is returned through the argument pointer. The decode function + has no possibility of failure and returns the decoded value. */ + +typedef enum +{ + xtensa_encode_result_ok, + xtensa_encode_result_align, + xtensa_encode_result_not_in_table, + xtensa_encode_result_too_low, + xtensa_encode_result_too_high, + xtensa_encode_result_not_ok, + xtensa_encode_result_max = xtensa_encode_result_not_ok +} xtensa_encode_result; + +extern xtensa_encode_result xtensa_operand_encode (xtensa_operand, uint32 *); + +extern uint32 xtensa_operand_decode (xtensa_operand, uint32); + + +/* For PC-relative offset operands, the interpretation of the offset may vary + between opcodes, e.g., is it relative to the current PC or that of the next + instruction? The following functions are defined to perform PC-relative + relocations and to undo them (as in the disassembler). The first function + takes the desired address and the PC of the current instruction and returns + the unencoded value to be stored in the offset field. The second function + takes the unencoded offset value and the current PC and returns the address. + Note that these functions do not replace the encode/decode functions; the + operands must be encoded/decoded separately. */ + +extern int xtensa_operand_isPCRelative (xtensa_operand); + +extern uint32 xtensa_operand_do_reloc (xtensa_operand, uint32, uint32); + +extern uint32 xtensa_operand_undo_reloc (xtensa_operand, uint32, uint32); + +#ifdef __cplusplus +} +#endif +#endif /* XTENSA_LIBISA_H */ diff --git a/libiberty/mempcpy.c b/libiberty/mempcpy.c new file mode 100644 index 0000000..b0dccfa --- /dev/null +++ b/libiberty/mempcpy.c @@ -0,0 +1,48 @@ +/* Implement the mempcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental void* mempcpy (void *@var{out}, const void *@var{in}, size_t @var{length}) + +Copies @var{length} bytes from memory region @var{in} to region +@var{out}. Returns a pointer to @var{out} + @var{length}. + +@end deftypefn + +*/ + +#include +#ifdef ANSI_PROTOTYPES +#include +#else +#define size_t unsigned long +#endif + +extern PTR memcpy PARAMS ((PTR, const PTR, size_t)); + +PTR +mempcpy (dst, src, len) + PTR dst; + const PTR src; + size_t len; +{ + return (char *) memcpy (dst, src, len) + len; +} diff --git a/libiberty/stpcpy.c b/libiberty/stpcpy.c new file mode 100644 index 0000000..a589642 --- /dev/null +++ b/libiberty/stpcpy.c @@ -0,0 +1,49 @@ +/* Implement the stpcpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src}) + +Copies the string @var{src} into @var{dst}. Returns a pointer to +@var{dst} + strlen(@var{src}). + +@end deftypefn + +*/ + +#include +#ifdef ANSI_PROTOTYPES +#include +#else +#define size_t unsigned long +#endif + +extern size_t strlen PARAMS ((const char *)); +extern PTR memcpy PARAMS ((PTR, const PTR, size_t)); + +char * +stpcpy (dst, src) + char *dst; + const char *src; +{ + const size_t len = strlen (src); + return (char *) memcpy (dst, src, len + 1) + len; +} diff --git a/libiberty/stpncpy.c b/libiberty/stpncpy.c new file mode 100644 index 0000000..cb67b4d --- /dev/null +++ b/libiberty/stpncpy.c @@ -0,0 +1,54 @@ +/* Implement the stpncpy function. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Kaveh R. Ghazi . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* + +@deftypefn Supplemental char* stpncpy (char *@var{dst}, const char *@var{src}, size_t @var{len}) + +Copies the string @var{src} into @var{dst}, copying exactly @var{len} +and padding with zeros if necessary. If @var{len} < strlen(@var{src}) +then return @var{dst} + @var{len}, otherwise returns @var{dst} + +strlen(@var{src}). + +@end deftypefn + +*/ + +#include +#ifdef ANSI_PROTOTYPES +#include +#else +#define size_t unsigned long +#endif + +extern size_t strlen PARAMS ((const char *)); +extern char *strncpy PARAMS ((char *, const char *, size_t)); + +char * +stpncpy (dst, src, len) + char *dst; + const char *src; + size_t len; +{ + size_t n = strlen (src); + if (n > len) + n = len; + return strncpy (dst, src, len) + n; +} diff --git a/opcodes/xtensa-dis.c b/opcodes/xtensa-dis.c new file mode 100644 index 0000000..bf5f5bf --- /dev/null +++ b/opcodes/xtensa-dis.c @@ -0,0 +1,526 @@ +/* xtensa-dis.c. Disassembly functions for Xtensa. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com) + + This file is part of GDB, GAS, and the GNU binutils. + + GDB, GAS, and the GNU binutils are free software; you can redistribute + them and/or modify them under the terms of the GNU General Public + License as published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GDB, GAS, and the GNU binutils are distributed in the hope that they + 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 file; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include +#include +#include +#include +#include "xtensa-isa.h" +#include "ansidecl.h" +#include "sysdep.h" +#include "dis-asm.h" + +#include + +#ifndef MAX +#define MAX(a,b) (a > b ? a : b) +#endif + +static char* state_names[256] = +{ + "lbeg", /* 0 */ + "lend", /* 1 */ + "lcount", /* 2 */ + "sar", /* 3 */ + "br", /* 4 */ + + "reserved_5", /* 5 */ + "reserved_6", /* 6 */ + "reserved_7", /* 7 */ + + "av", /* 8 */ + "avh", /* 9 */ + "bv", /* 10 */ + "sav", /* 11 */ + "scompare1", /* 12 */ + + "reserved_13", /* 13 */ + "reserved_14", /* 14 */ + "reserved_15", /* 15 */ + + "acclo", /* 16 */ + "acchi", /* 17 */ + + "reserved_18", /* 18 */ + "reserved_19", /* 19 */ + "reserved_20", /* 20 */ + "reserved_21", /* 21 */ + "reserved_22", /* 22 */ + "reserved_23", /* 23 */ + "reserved_24", /* 24 */ + "reserved_25", /* 25 */ + "reserved_26", /* 26 */ + "reserved_27", /* 27 */ + "reserved_28", /* 28 */ + "reserved_29", /* 29 */ + "reserved_30", /* 30 */ + "reserved_31", /* 31 */ + + "mr0", /* 32 */ + "mr1", /* 33 */ + "mr2", /* 34 */ + "mr3", /* 35 */ + + "reserved_36", /* 36 */ + "reserved_37", /* 37 */ + "reserved_38", /* 38 */ + "reserved_39", /* 39 */ + "reserved_40", /* 40 */ + "reserved_41", /* 41 */ + "reserved_42", /* 42 */ + "reserved_43", /* 43 */ + "reserved_44", /* 44 */ + "reserved_45", /* 45 */ + "reserved_46", /* 46 */ + "reserved_47", /* 47 */ + "reserved_48", /* 48 */ + "reserved_49", /* 49 */ + "reserved_50", /* 50 */ + "reserved_51", /* 51 */ + "reserved_52", /* 52 */ + "reserved_53", /* 53 */ + "reserved_54", /* 54 */ + "reserved_55", /* 55 */ + "reserved_56", /* 56 */ + "reserved_57", /* 57 */ + "reserved_58", /* 58 */ + "reserved_59", /* 59 */ + "reserved_60", /* 60 */ + "reserved_61", /* 61 */ + "reserved_62", /* 62 */ + "reserved_63", /* 63 */ + + "reserved_64", /* 64 */ + "reserved_65", /* 65 */ + "reserved_66", /* 66 */ + "reserved_67", /* 67 */ + "reserved_68", /* 68 */ + "reserved_69", /* 69 */ + "reserved_70", /* 70 */ + "reserved_71", /* 71 */ + + "wb", /* 72 */ + "ws", /* 73 */ + + "reserved_74", /* 74 */ + "reserved_75", /* 75 */ + "reserved_76", /* 76 */ + "reserved_77", /* 77 */ + "reserved_78", /* 78 */ + "reserved_79", /* 79 */ + "reserved_80", /* 80 */ + "reserved_81", /* 81 */ + "reserved_82", /* 82 */ + + "ptevaddr", /* 83 */ + + "reserved_84", /* 84 */ + "reserved_85", /* 85 */ + "reserved_86", /* 86 */ + "reserved_87", /* 87 */ + "reserved_88", /* 88 */ + "reserved_89", /* 89 */ + + "rasid", /* 90 */ + "itlbcfg", /* 91 */ + "dtlbcfg", /* 92 */ + + "reserved_93", /* 93 */ + "reserved_94", /* 94 */ + "reserved_95", /* 95 */ + + "ibreakenable", /* 96 */ + + "reserved_97", /* 97 */ + + "cacheattr", /* 98 */ + + "reserved_99", /* 99 */ + "reserved_100", /* 100 */ + "reserved_101", /* 101 */ + "reserved_102", /* 102 */ + "reserved_103", /* 103 */ + + "ddr", /* 104 */ + + "reserved_105", /* 105 */ + "reserved_106", /* 106 */ + "reserved_107", /* 107 */ + "reserved_108", /* 108 */ + "reserved_109", /* 109 */ + "reserved_110", /* 110 */ + "reserved_111", /* 111 */ + "reserved_112", /* 112 */ + "reserved_113", /* 113 */ + "reserved_114", /* 114 */ + "reserved_115", /* 115 */ + "reserved_116", /* 116 */ + "reserved_117", /* 117 */ + "reserved_118", /* 118 */ + "reserved_119", /* 119 */ + "reserved_120", /* 120 */ + "reserved_121", /* 121 */ + "reserved_122", /* 122 */ + "reserved_123", /* 123 */ + "reserved_124", /* 124 */ + "reserved_125", /* 125 */ + "reserved_126", /* 126 */ + "reserved_127", /* 127 */ + + "ibreaka0", /* 128 */ + "ibreaka1", /* 129 */ + "ibreaka2", /* 130 */ + "ibreaka3", /* 131 */ + "ibreaka4", /* 132 */ + "ibreaka5", /* 133 */ + "ibreaka6", /* 134 */ + "ibreaka7", /* 135 */ + "ibreaka8", /* 136 */ + "ibreaka9", /* 137 */ + "ibreaka10", /* 138 */ + "ibreaka11", /* 139 */ + "ibreaka12", /* 140 */ + "ibreaka13", /* 141 */ + "ibreaka14", /* 142 */ + "ibreaka15", /* 143 */ + + "dbreaka0", /* 144 */ + "dbreaka1", /* 145 */ + "dbreaka2", /* 146 */ + "dbreaka3", /* 147 */ + "dbreaka4", /* 148 */ + "dbreaka5", /* 149 */ + "dbreaka6", /* 150 */ + "dbreaka7", /* 151 */ + "dbreaka8", /* 152 */ + "dbreaka9", /* 153 */ + "dbreaka10", /* 154 */ + "dbreaka11", /* 155 */ + "dbreaka12", /* 156 */ + "dbreaka13", /* 157 */ + "dbreaka14", /* 158 */ + "dbreaka15", /* 159 */ + + "dbreakc0", /* 160 */ + "dbreakc1", /* 161 */ + "dbreakc2", /* 162 */ + "dbreakc3", /* 163 */ + "dbreakc4", /* 164 */ + "dbreakc5", /* 165 */ + "dbreakc6", /* 166 */ + "dbreakc7", /* 167 */ + "dbreakc8", /* 168 */ + "dbreakc9", /* 169 */ + "dbreakc10", /* 170 */ + "dbreakc11", /* 171 */ + "dbreakc12", /* 172 */ + "dbreakc13", /* 173 */ + "dbreakc14", /* 174 */ + "dbreakc15", /* 175 */ + + "reserved_176", /* 176 */ + + "epc1", /* 177 */ + "epc2", /* 178 */ + "epc3", /* 179 */ + "epc4", /* 180 */ + "epc5", /* 181 */ + "epc6", /* 182 */ + "epc7", /* 183 */ + "epc8", /* 184 */ + "epc9", /* 185 */ + "epc10", /* 186 */ + "epc11", /* 187 */ + "epc12", /* 188 */ + "epc13", /* 189 */ + "epc14", /* 190 */ + "epc15", /* 191 */ + "depc", /* 192 */ + + "reserved_193", /* 193 */ + + "eps2", /* 194 */ + "eps3", /* 195 */ + "eps4", /* 196 */ + "eps5", /* 197 */ + "eps6", /* 198 */ + "eps7", /* 199 */ + "eps8", /* 200 */ + "eps9", /* 201 */ + "eps10", /* 202 */ + "eps11", /* 203 */ + "eps12", /* 204 */ + "eps13", /* 205 */ + "eps14", /* 206 */ + "eps15", /* 207 */ + + "reserved_208", /* 208 */ + + "excsave1", /* 209 */ + "excsave2", /* 210 */ + "excsave3", /* 211 */ + "excsave4", /* 212 */ + "excsave5", /* 213 */ + "excsave6", /* 214 */ + "excsave7", /* 215 */ + "excsave8", /* 216 */ + "excsave9", /* 217 */ + "excsave10", /* 218 */ + "excsave11", /* 219 */ + "excsave12", /* 220 */ + "excsave13", /* 221 */ + "excsave14", /* 222 */ + "excsave15", /* 223 */ + "cpenable", /* 224 */ + + "reserved_225", /* 225 */ + + "interrupt", /* 226 */ + "interrupt2", /* 227 */ + "intenable", /* 228 */ + + "reserved_229", /* 229 */ + + "ps", /* 230 */ + + "reserved_231", /* 231 */ + + "exccause", /* 232 */ + "debugcause", /* 233 */ + "ccount", /* 234 */ + "prid", /* 235 */ + "icount", /* 236 */ + "icountlvl", /* 237 */ + "excvaddr", /* 238 */ + + "reserved_239", /* 239 */ + + "ccompare0", /* 240 */ + "ccompare1", /* 241 */ + "ccompare2", /* 242 */ + "ccompare3", /* 243 */ + + "misc0", /* 244 */ + "misc1", /* 245 */ + "misc2", /* 246 */ + "misc3", /* 247 */ + + "reserved_248", /* 248 */ + "reserved_249", /* 249 */ + "reserved_250", /* 250 */ + "reserved_251", /* 251 */ + "reserved_252", /* 252 */ + "reserved_253", /* 253 */ + "reserved_254", /* 254 */ + "reserved_255", /* 255 */ +}; + + +int show_raw_fields; + +static int fetch_data + PARAMS ((struct disassemble_info *info, bfd_vma memaddr, int numBytes)); +static void print_xtensa_operand + PARAMS ((bfd_vma, struct disassemble_info *, xtensa_operand, + unsigned operand_val, int print_sr_name)); + +struct dis_private { + bfd_byte *byte_buf; + jmp_buf bailout; +}; + +static int +fetch_data (info, memaddr, numBytes) + struct disassemble_info *info; + bfd_vma memaddr; + int numBytes; +{ + int length, status = 0; + struct dis_private *priv = (struct dis_private *) info->private_data; + int insn_size = (numBytes != 0 ? numBytes : + xtensa_insn_maxlength (xtensa_default_isa)); + + /* Read the maximum instruction size, padding with zeros if we go past + the end of the text section. This code will automatically adjust + length when we hit the end of the buffer. */ + + memset (priv->byte_buf, 0, insn_size); + for (length = insn_size; length > 0; length--) + { + status = (*info->read_memory_func) (memaddr, priv->byte_buf, length, + info); + if (status == 0) + return length; + } + (*info->memory_error_func) (status, memaddr, info); + longjmp (priv->bailout, 1); + /*NOTREACHED*/ +} + + +static void +print_xtensa_operand (memaddr, info, opnd, operand_val, print_sr_name) + bfd_vma memaddr; + struct disassemble_info *info; + xtensa_operand opnd; + unsigned operand_val; + int print_sr_name; +{ + char *kind = xtensa_operand_kind (opnd); + int signed_operand_val; + + if (show_raw_fields) + { + if (operand_val < 0xa) + (*info->fprintf_func) (info->stream, "%u", operand_val); + else + (*info->fprintf_func) (info->stream, "0x%x", operand_val); + return; + } + + operand_val = xtensa_operand_decode (opnd, operand_val); + signed_operand_val = (int) operand_val; + + if (xtensa_operand_isPCRelative (opnd)) + { + operand_val = xtensa_operand_undo_reloc (opnd, operand_val, memaddr); + info->target = operand_val; + (*info->print_address_func) (info->target, info); + } + else if (!strcmp (kind, "i")) + { + if (print_sr_name + && signed_operand_val >= 0 + && signed_operand_val <= 255) + (*info->fprintf_func) (info->stream, "%s", + state_names[signed_operand_val]); + else if ((signed_operand_val > -256) && (signed_operand_val < 256)) + (*info->fprintf_func) (info->stream, "%d", signed_operand_val); + else + (*info->fprintf_func) (info->stream, "0x%x",signed_operand_val); + } + else + (*info->fprintf_func) (info->stream, "%s%u", kind, operand_val); +} + + +/* Print the Xtensa instruction at address MEMADDR on info->stream. + Returns length of the instruction in bytes. */ + +int +print_insn_xtensa (memaddr, info) + bfd_vma memaddr; + struct disassemble_info *info; +{ + unsigned operand_val; + int bytes_fetched, size, maxsize, i, noperands; + xtensa_isa isa; + xtensa_opcode opc; + char *op_name; + int print_sr_name; + struct dis_private priv; + static bfd_byte *byte_buf = NULL; + static xtensa_insnbuf insn_buffer = NULL; + + if (!xtensa_default_isa) + (void) xtensa_isa_init (); + + info->target = 0; + maxsize = xtensa_insn_maxlength (xtensa_default_isa); + + /* Set bytes_per_line to control the amount of whitespace between the hex + values and the opcode. For Xtensa, we always print one "chunk" and we + vary bytes_per_chunk to determine how many bytes to print. (objdump + would apparently prefer that we set bytes_per_chunk to 1 and vary + bytes_per_line but that makes it hard to fit 64-bit instructions on + an 80-column screen.) The value of bytes_per_line here is not exactly + right, because objdump adds an extra space for each chunk so that the + amount of whitespace depends on the chunk size. Oh well, it's good + enough.... Note that we set the minimum size to 4 to accomodate + literal pools. */ + info->bytes_per_line = MAX (maxsize, 4); + + /* Allocate buffers the first time through. */ + if (!insn_buffer) + insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa); + if (!byte_buf) + byte_buf = (bfd_byte *) malloc (MAX (maxsize, 4)); + + priv.byte_buf = byte_buf; + + info->private_data = (PTR) &priv; + if (setjmp (priv.bailout) != 0) + /* Error return. */ + return -1; + + /* Don't set "isa" before the setjmp to keep the compiler from griping. */ + isa = xtensa_default_isa; + + /* Fetch the maximum size instruction. */ + bytes_fetched = fetch_data (info, memaddr, 0); + + /* Copy the bytes into the decode buffer. */ + memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) * + sizeof (xtensa_insnbuf_word))); + xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf); + + opc = xtensa_decode_insn (isa, insn_buffer); + if (opc == XTENSA_UNDEFINED + || ((size = xtensa_insn_length (isa, opc)) > bytes_fetched)) + { + (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]); + return 1; + } + + op_name = (char *) xtensa_opcode_name (isa, opc); + (*info->fprintf_func) (info->stream, "%s", op_name); + + print_sr_name = (!strcasecmp (op_name, "wsr") + || !strcasecmp (op_name, "xsr") + || !strcasecmp (op_name, "rsr")); + + /* Print the operands (if any). */ + noperands = xtensa_num_operands (isa, opc); + if (noperands > 0) + { + int first = 1; + + (*info->fprintf_func) (info->stream, "\t"); + for (i = 0; i < noperands; i++) + { + xtensa_operand opnd = xtensa_get_operand (isa, opc, i); + + if (first) + first = 0; + else + (*info->fprintf_func) (info->stream, ", "); + operand_val = xtensa_operand_get_field (opnd, insn_buffer); + print_xtensa_operand (memaddr, info, opnd, operand_val, + print_sr_name); + } + } + + info->bytes_per_chunk = size; + info->display_endian = info->endian; + + return size; +} + diff --git a/sim/arm/iwmmxt.c b/sim/arm/iwmmxt.c new file mode 100644 index 0000000..72444f6 --- /dev/null +++ b/sim/arm/iwmmxt.c @@ -0,0 +1,3730 @@ +/* iwmmxt.c -- Intel(r) Wireless MMX(tm) technology co-processor interface. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by matthew green (mrg@redhat.com). + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "armdefs.h" +#include "armos.h" +#include "armemu.h" +#include "ansidecl.h" +#include "iwmmxt.h" + +/* #define DEBUG 1 */ + +/* Intel(r) Wireless MMX(tm) technology co-processor. + It uses co-processor numbers (0 and 1). There are 16 vector registers wRx + and 16 control registers wCx. Co-processors 0 and 1 are used in MCR/MRC + to access wRx and wCx respectively. */ + +static ARMdword wR[16]; +static ARMword wC[16] = { 0x69051010 }; + +#define SUBSTR(w,t,m,n) ((t)(w << ((sizeof (t) * 8 - 1) - (n))) \ + >> (((sizeof (t) * 8 - 1) - (n)) + (m))) +#define wCBITS(w,x,y) SUBSTR (wC[w], ARMword, x, y) +#define wRBITS(w,x,y) SUBSTR (wR[w], ARMdword, x, y) +#define wCID 0 +#define wCon 1 +#define wCSSF 2 +#define wCASF 3 +#define wCGR0 8 +#define wCGR1 9 +#define wCGR2 10 +#define wCGR3 11 + +/* Bits in the wCon register. */ +#define WCON_CUP (1 << 0) +#define WCON_MUP (1 << 1) + +/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */ +#define SIMD8_SET(x, v, n, b) (x) |= ((v != 0) << ((((b) + 1) * 4) + (n))) +#define SIMD16_SET(x, v, n, h) (x) |= ((v != 0) << ((((h) + 1) * 8) + (n))) +#define SIMD32_SET(x, v, n, w) (x) |= ((v != 0) << ((((w) + 1) * 16) + (n))) +#define SIMD64_SET(x, v, n) (x) |= ((v != 0) << (32 + (n))) + +/* Flags to pass as "n" above. */ +#define SIMD_NBIT -1 +#define SIMD_ZBIT -2 +#define SIMD_CBIT -3 +#define SIMD_VBIT -4 + +/* Various status bit macros. */ +#define NBIT8(x) ((x) & 0x80) +#define NBIT16(x) ((x) & 0x8000) +#define NBIT32(x) ((x) & 0x80000000) +#define NBIT64(x) ((x) & 0x8000000000000000ULL) +#define ZBIT8(x) (((x) & 0xff) == 0) +#define ZBIT16(x) (((x) & 0xffff) == 0) +#define ZBIT32(x) (((x) & 0xffffffff) == 0) +#define ZBIT64(x) (x == 0) + +/* Access byte/half/word "n" of register "x". */ +#define wRBYTE(x,n) wRBITS ((x), (n) * 8, (n) * 8 + 7) +#define wRHALF(x,n) wRBITS ((x), (n) * 16, (n) * 16 + 15) +#define wRWORD(x,n) wRBITS ((x), (n) * 32, (n) * 32 + 31) + +/* Macro to handle how the G bit selects wCGR registers. */ +#define DECODE_G_BIT(state, instr, shift) \ +{ \ + unsigned int reg; \ + \ + reg = BITS (0, 3); \ + \ + if (BIT (8)) /* G */ \ + { \ + if (reg < wCGR0 || reg > wCGR3) \ + { \ + ARMul_UndefInstr (state, instr); \ + return ARMul_DONE; \ + } \ + shift = wC [reg]; \ + } \ + else \ + shift = wR [reg]; \ + \ + shift &= 0xff; \ +} + +/* Index calculations for the satrv[] array. */ +#define BITIDX8(x) (x) +#define BITIDX16(x) (((x) + 1) * 2 - 1) +#define BITIDX32(x) (((x) + 1) * 4 - 1) + +/* Sign extension macros. */ +#define EXTEND8(a) ((a) & 0x80 ? ((a) | 0xffffff00) : (a)) +#define EXTEND16(a) ((a) & 0x8000 ? ((a) | 0xffff0000) : (a)) +#define EXTEND32(a) ((a) & 0x80000000ULL ? ((a) | 0xffffffff00000000ULL) : (a)) + +/* Set the wCSSF from 8 values. */ +#define SET_wCSSF(a,b,c,d,e,f,g,h) \ + wC[wCSSF] = (((h) != 0) << 7) | (((g) != 0) << 6) \ + | (((f) != 0) << 5) | (((e) != 0) << 4) \ + | (((d) != 0) << 3) | (((c) != 0) << 2) \ + | (((b) != 0) << 1) | (((a) != 0) << 0); + +/* Set the wCSSR from an array with 8 values. */ +#define SET_wCSSFvec(v) \ + SET_wCSSF((v)[0],(v)[1],(v)[2],(v)[3],(v)[4],(v)[5],(v)[6],(v)[7]) + +/* Size qualifiers for vector operations. */ +#define Bqual 0 +#define Hqual 1 +#define Wqual 2 +#define Dqual 3 + +/* Saturation qualifiers for vector operations. */ +#define NoSaturation 0 +#define UnsignedSaturation 1 +#define SignedSaturation 3 + + +/* Prototypes. */ +static ARMword Add32 (ARMword, ARMword, int *, int *, ARMword); +static ARMdword AddS32 (ARMdword, ARMdword, int *, int *); +static ARMdword AddU32 (ARMdword, ARMdword, int *, int *); +static ARMword AddS16 (ARMword, ARMword, int *, int *); +static ARMword AddU16 (ARMword, ARMword, int *, int *); +static ARMword AddS8 (ARMword, ARMword, int *, int *); +static ARMword AddU8 (ARMword, ARMword, int *, int *); +static ARMword Sub32 (ARMword, ARMword, int *, int *, ARMword); +static ARMdword SubS32 (ARMdword, ARMdword, int *, int *); +static ARMdword SubU32 (ARMdword, ARMdword, int *, int *); +static ARMword SubS16 (ARMword, ARMword, int *, int *); +static ARMword SubS8 (ARMword, ARMword, int *, int *); +static ARMword SubU16 (ARMword, ARMword, int *, int *); +static ARMword SubU8 (ARMword, ARMword, int *, int *); +static unsigned char IwmmxtSaturateU8 (signed short, int *); +static signed char IwmmxtSaturateS8 (signed short, int *); +static unsigned short IwmmxtSaturateU16 (signed int, int *); +static signed short IwmmxtSaturateS16 (signed int, int *); +static unsigned long IwmmxtSaturateU32 (signed long long, int *); +static signed long IwmmxtSaturateS32 (signed long long, int *); +static ARMword Compute_Iwmmxt_Address (ARMul_State *, ARMword, int *); +static ARMdword Iwmmxt_Load_Double_Word (ARMul_State *, ARMword); +static ARMword Iwmmxt_Load_Word (ARMul_State *, ARMword); +static ARMword Iwmmxt_Load_Half_Word (ARMul_State *, ARMword); +static ARMword Iwmmxt_Load_Byte (ARMul_State *, ARMword); +static void Iwmmxt_Store_Double_Word (ARMul_State *, ARMword, ARMdword); +static void Iwmmxt_Store_Word (ARMul_State *, ARMword, ARMword); +static void Iwmmxt_Store_Half_Word (ARMul_State *, ARMword, ARMword); +static void Iwmmxt_Store_Byte (ARMul_State *, ARMword, ARMword); +static int Process_Instruction (ARMul_State *, ARMword); + +static int TANDC (ARMul_State *, ARMword); +static int TBCST (ARMul_State *, ARMword); +static int TEXTRC (ARMul_State *, ARMword); +static int TEXTRM (ARMul_State *, ARMword); +static int TINSR (ARMul_State *, ARMword); +static int TMCR (ARMul_State *, ARMword); +static int TMCRR (ARMul_State *, ARMword); +static int TMIA (ARMul_State *, ARMword); +static int TMIAPH (ARMul_State *, ARMword); +static int TMIAxy (ARMul_State *, ARMword); +static int TMOVMSK (ARMul_State *, ARMword); +static int TMRC (ARMul_State *, ARMword); +static int TMRRC (ARMul_State *, ARMword); +static int TORC (ARMul_State *, ARMword); +static int WACC (ARMul_State *, ARMword); +static int WADD (ARMul_State *, ARMword); +static int WALIGNI (ARMword); +static int WALIGNR (ARMul_State *, ARMword); +static int WAND (ARMword); +static int WANDN (ARMword); +static int WAVG2 (ARMword); +static int WCMPEQ (ARMul_State *, ARMword); +static int WCMPGT (ARMul_State *, ARMword); +static int WLDR (ARMul_State *, ARMword); +static int WMAC (ARMword); +static int WMADD (ARMword); +static int WMAX (ARMul_State *, ARMword); +static int WMIN (ARMul_State *, ARMword); +static int WMUL (ARMword); +static int WOR (ARMword); +static int WPACK (ARMul_State *, ARMword); +static int WROR (ARMul_State *, ARMword); +static int WSAD (ARMword); +static int WSHUFH (ARMword); +static int WSLL (ARMul_State *, ARMword); +static int WSRA (ARMul_State *, ARMword); +static int WSRL (ARMul_State *, ARMword); +static int WSTR (ARMul_State *, ARMword); +static int WSUB (ARMul_State *, ARMword); +static int WUNPCKEH (ARMul_State *, ARMword); +static int WUNPCKEL (ARMul_State *, ARMword); +static int WUNPCKIH (ARMul_State *, ARMword); +static int WUNPCKIL (ARMul_State *, ARMword); +static int WXOR (ARMword); + +/* This function does the work of adding two 32bit values + together, and calculating if a carry has occurred. */ + +static ARMword +Add32 (ARMword a1, + ARMword a2, + int * carry_ptr, + int * overflow_ptr, + ARMword sign_mask) +{ + ARMword result = (a1 + a2); + unsigned int uresult = (unsigned int) result; + unsigned int ua1 = (unsigned int) a1; + + /* If (result == a1) and (a2 == 0), + or (result > a2) then we have no carry. */ + * carry_ptr = ((uresult == ua1) ? (a2 != 0) : (uresult < ua1)); + + /* Overflow occurs when both arguments are the + same sign, but the result is a different sign. */ + * overflow_ptr = ( ( (result & sign_mask) && !(a1 & sign_mask) && !(a2 & sign_mask)) + || (!(result & sign_mask) && (a1 & sign_mask) && (a2 & sign_mask))); + + return result; +} + +static ARMdword +AddS32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr) +{ + ARMdword result; + unsigned int uresult; + unsigned int ua1; + + a1 = EXTEND32 (a1); + a2 = EXTEND32 (a2); + + result = a1 + a2; + uresult = (unsigned int) result; + ua1 = (unsigned int) a1; + + * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1)); + + * overflow_ptr = ( ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL)) + || (!(result & 0x80000000ULL) && (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL))); + + return result; +} + +static ARMdword +AddU32 (ARMdword a1, ARMdword a2, int * carry_ptr, int * overflow_ptr) +{ + ARMdword result; + unsigned int uresult; + unsigned int ua1; + + a1 &= 0xffffffff; + a2 &= 0xffffffff; + + result = a1 + a2; + uresult = (unsigned int) result; + ua1 = (unsigned int) a1; + + * carry_ptr = ((uresult == a1) ? (a2 != 0) : (uresult < ua1)); + + * overflow_ptr = ( ( (result & 0x80000000ULL) && !(a1 & 0x80000000ULL) && !(a2 & 0x80000000ULL)) + || (!(result & 0x80000000ULL) && (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL))); + + return result; +} + +static ARMword +AddS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 = EXTEND16 (a1); + a2 = EXTEND16 (a2); + + return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); +} + +static ARMword +AddU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 &= 0xffff; + a2 &= 0xffff; + + return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); +} + +static ARMword +AddS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 = EXTEND8 (a1); + a2 = EXTEND8 (a2); + + return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80); +} + +static ARMword +AddU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 &= 0xff; + a2 &= 0xff; + + return Add32 (a1, a2, carry_ptr, overflow_ptr, 0x80); +} + +static ARMword +Sub32 (ARMword a1, + ARMword a2, + int * borrow_ptr, + int * overflow_ptr, + ARMword sign_mask) +{ + ARMword result = (a1 - a2); + unsigned int ua1 = (unsigned int) a1; + unsigned int ua2 = (unsigned int) a2; + + /* A borrow occurs if a2 is (unsigned) larger than a1. + However the carry flag is *cleared* if a borrow occurs. */ + * borrow_ptr = ! (ua2 > ua1); + + /* Overflow occurs when a negative number is subtracted from a + positive number and the result is negative or a positive + number is subtracted from a negative number and the result is + positive. */ + * overflow_ptr = ( (! (a1 & sign_mask) && (a2 & sign_mask) && (result & sign_mask)) + || ((a1 & sign_mask) && ! (a2 & sign_mask) && ! (result & sign_mask))); + + return result; +} + +static ARMdword +SubS32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr) +{ + ARMdword result; + unsigned int ua1; + unsigned int ua2; + + a1 = EXTEND32 (a1); + a2 = EXTEND32 (a2); + + result = a1 - a2; + ua1 = (unsigned int) a1; + ua2 = (unsigned int) a2; + + * borrow_ptr = ! (ua2 > ua1); + + * overflow_ptr = ( (! (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL) && (result & 0x80000000ULL)) + || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL))); + + return result; +} + +static ARMword +SubS16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 = EXTEND16 (a1); + a2 = EXTEND16 (a2); + + return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); +} + +static ARMword +SubS8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 = EXTEND8 (a1); + a2 = EXTEND8 (a2); + + return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80); +} + +static ARMword +SubU16 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 &= 0xffff; + a2 &= 0xffff; + + return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x8000); +} + +static ARMword +SubU8 (ARMword a1, ARMword a2, int * carry_ptr, int * overflow_ptr) +{ + a1 &= 0xff; + a2 &= 0xff; + + return Sub32 (a1, a2, carry_ptr, overflow_ptr, 0x80); +} + +static ARMdword +SubU32 (ARMdword a1, ARMdword a2, int * borrow_ptr, int * overflow_ptr) +{ + ARMdword result; + unsigned int ua1; + unsigned int ua2; + + a1 &= 0xffffffff; + a2 &= 0xffffffff; + + result = a1 - a2; + ua1 = (unsigned int) a1; + ua2 = (unsigned int) a2; + + * borrow_ptr = ! (ua2 > ua1); + + * overflow_ptr = ( (! (a1 & 0x80000000ULL) && (a2 & 0x80000000ULL) && (result & 0x80000000ULL)) + || ((a1 & 0x80000000ULL) && ! (a2 & 0x80000000ULL) && ! (result & 0x80000000ULL))); + + return result; +} + +/* For the saturation. */ + +static unsigned char +IwmmxtSaturateU8 (signed short val, int * sat) +{ + unsigned char rv; + + if (val < 0) + { + rv = 0; + *sat = 1; + } + else if (val > 0xff) + { + rv = 0xff; + *sat = 1; + } + else + { + rv = val & 0xff; + *sat = 0; + } + return rv; +} + +static signed char +IwmmxtSaturateS8 (signed short val, int * sat) +{ + signed char rv; + + if (val < -0x80) + { + rv = -0x80; + *sat = 1; + } + else if (val > 0x7f) + { + rv = 0x7f; + *sat = 1; + } + else + { + rv = val & 0xff; + *sat = 0; + } + return rv; +} + +static unsigned short +IwmmxtSaturateU16 (signed int val, int * sat) +{ + unsigned short rv; + + if (val < 0) + { + rv = 0; + *sat = 1; + } + else if (val > 0xffff) + { + rv = 0xffff; + *sat = 1; + } + else + { + rv = val & 0xffff; + *sat = 0; + } + return rv; +} + +static signed short +IwmmxtSaturateS16 (signed int val, int * sat) +{ + signed short rv; + + if (val < -0x8000) + { + rv = - 0x8000; + *sat = 1; + } + else if (val > 0x7fff) + { + rv = 0x7fff; + *sat = 1; + } + else + { + rv = val & 0xffff; + *sat = 0; + } + return rv; +} + +static unsigned long +IwmmxtSaturateU32 (signed long long val, int * sat) +{ + unsigned long rv; + + if (val < 0) + { + rv = 0; + *sat = 1; + } + else if (val > 0xffffffff) + { + rv = 0xffffffff; + *sat = 1; + } + else + { + rv = val & 0xffffffff; + *sat = 0; + } + return rv; +} + +static signed long +IwmmxtSaturateS32 (signed long long val, int * sat) +{ + signed long rv; + + if (val < -0x80000000LL) + { + rv = -0x80000000; + *sat = 1; + } + else if (val > 0x7fffffff) + { + rv = 0x7fffffff; + *sat = 1; + } + else + { + rv = val & 0xffffffff; + *sat = 0; + } + return rv; +} + +/* Intel(r) Wireless MMX(tm) technology Acessor functions. */ + +unsigned +IwmmxtLDC (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword data) +{ + return ARMul_CANT; +} + +unsigned +IwmmxtSTC (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword * data) +{ + return ARMul_CANT; +} + +unsigned +IwmmxtMRC (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword * value) +{ + return ARMul_CANT; +} + +unsigned +IwmmxtMCR (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword value) +{ + return ARMul_CANT; +} + +unsigned +IwmmxtCDP (ARMul_State * state, unsigned type, ARMword instr) +{ + return ARMul_CANT; +} + +/* Intel(r) Wireless MMX(tm) technology instruction implementations. */ + +static int +TANDC (ARMul_State * state, ARMword instr) +{ + ARMword cpsr; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tandc\n"); +#endif + + /* The Rd field must be r15. */ + if (BITS (12, 15) != 15) + return ARMul_CANT; + + /* The CRn field must be r3. */ + if (BITS (16, 19) != 3) + return ARMul_CANT; + + /* The CRm field must be r0. */ + if (BITS (0, 3) != 0) + return ARMul_CANT; + + cpsr = ARMul_GetCPSR (state) & 0x0fffffff; + + switch (BITS (22, 23)) + { + case Bqual: + cpsr |= ( (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 24, 27) + & wCBITS (wCASF, 20, 23) & wCBITS (wCASF, 16, 19) + & wCBITS (wCASF, 12, 15) & wCBITS (wCASF, 8, 11) + & wCBITS (wCASF, 4, 7) & wCBITS (wCASF, 0, 3)) << 28); + break; + + case Hqual: + cpsr |= ( (wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 20, 23) + & wCBITS (wCASF, 12, 15) & wCBITS (wCASF, 4, 7)) << 28); + break; + + case Wqual: + cpsr |= ((wCBITS (wCASF, 28, 31) & wCBITS (wCASF, 12, 15)) << 28); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + ARMul_SetCPSR (state, cpsr); + + return ARMul_DONE; +} + +static int +TBCST (ARMul_State * state, ARMword instr) +{ + ARMdword Rn; + int wRd; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tbcst\n"); +#endif + + Rn = state->Reg [BITS (12, 15)]; + if (BITS (12, 15) == 15) + Rn &= 0xfffffffc; + + wRd = BITS (16, 19); + + switch (BITS (6, 7)) + { + case Bqual: + Rn &= 0xff; + wR [wRd] = (Rn << 56) | (Rn << 48) | (Rn << 40) | (Rn << 32) + | (Rn << 24) | (Rn << 16) | (Rn << 8) | Rn; + break; + + case Hqual: + Rn &= 0xffff; + wR [wRd] = (Rn << 48) | (Rn << 32) | (Rn << 16) | Rn; + break; + + case Wqual: + Rn &= 0xffffffff; + wR [wRd] = (Rn << 32) | Rn; + break; + + default: + ARMul_UndefInstr (state, instr); + break; + } + + wC [wCon] |= WCON_MUP; + return ARMul_DONE; +} + +static int +TEXTRC (ARMul_State * state, ARMword instr) +{ + ARMword cpsr; + ARMword selector; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "textrc\n"); +#endif + + /* The Rd field must be r15. */ + if (BITS (12, 15) != 15) + return ARMul_CANT; + + /* The CRn field must be r3. */ + if (BITS (16, 19) != 3) + return ARMul_CANT; + + /* The CRm field must be 0xxx. */ + if (BIT (3) != 0) + return ARMul_CANT; + + selector = BITS (0, 2); + cpsr = ARMul_GetCPSR (state) & 0x0fffffff; + + switch (BITS (22, 23)) + { + case Bqual: selector *= 4; break; + case Hqual: selector = ((selector & 3) * 8) + 4; break; + case Wqual: selector = ((selector & 1) * 16) + 12; break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + cpsr |= wCBITS (wCASF, selector, selector + 3) << 28; + ARMul_SetCPSR (state, cpsr); + + return ARMul_DONE; +} + +static int +TEXTRM (ARMul_State * state, ARMword instr) +{ + ARMword Rd; + int offset; + int wRn; + int sign; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "textrm\n"); +#endif + + wRn = BITS (16, 19); + sign = BIT (3); + offset = BITS (0, 2); + + switch (BITS (22, 23)) + { + case Bqual: + offset *= 8; + Rd = wRBITS (wRn, offset, offset + 7); + if (sign) + Rd = EXTEND8 (Rd); + break; + + case Hqual: + offset = (offset & 3) * 16; + Rd = wRBITS (wRn, offset, offset + 15); + if (sign) + Rd = EXTEND16 (Rd); + break; + + case Wqual: + offset = (offset & 1) * 32; + Rd = wRBITS (wRn, offset, offset + 31); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + if (BITS (12, 15) == 15) + ARMul_UndefInstr (state, instr); + else + state->Reg [BITS (12, 15)] = Rd; + + return ARMul_DONE; +} + +static int +TINSR (ARMul_State * state, ARMword instr) +{ + ARMdword data; + ARMword offset; + int wRd; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tinsr\n"); +#endif + + wRd = BITS (16, 19); + data = state->Reg [BITS (12, 15)]; + offset = BITS (0, 2); + + switch (BITS (6, 7)) + { + case Bqual: + data &= 0xff; + switch (offset) + { + case 0: wR [wRd] = data | (wRBITS (wRd, 8, 63) << 8); break; + case 1: wR [wRd] = wRBITS (wRd, 0, 7) | (data << 8) | (wRBITS (wRd, 16, 63) << 16); break; + case 2: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 24, 63) << 24); break; + case 3: wR [wRd] = wRBITS (wRd, 0, 23) | (data << 24) | (wRBITS (wRd, 32, 63) << 32); break; + case 4: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 40, 63) << 40); break; + case 5: wR [wRd] = wRBITS (wRd, 0, 39) | (data << 40) | (wRBITS (wRd, 48, 63) << 48); break; + case 6: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48) | (wRBITS (wRd, 56, 63) << 56); break; + case 7: wR [wRd] = wRBITS (wRd, 0, 55) | (data << 56); break; + } + break; + + case Hqual: + data &= 0xffff; + + switch (offset & 3) + { + case 0: wR [wRd] = data | (wRBITS (wRd, 16, 63) << 16); break; + case 1: wR [wRd] = wRBITS (wRd, 0, 15) | (data << 16) | (wRBITS (wRd, 32, 63) << 32); break; + case 2: wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32) | (wRBITS (wRd, 48, 63) << 48); break; + case 3: wR [wRd] = wRBITS (wRd, 0, 47) | (data << 48); break; + } + break; + + case Wqual: + if (offset & 1) + wR [wRd] = wRBITS (wRd, 0, 31) | (data << 32); + else + wR [wRd] = (wRBITS (wRd, 32, 63) << 32) | data; + break; + + default: + ARMul_UndefInstr (state, instr); + break; + } + + wC [wCon] |= WCON_MUP; + return ARMul_DONE; +} + +static int +TMCR (ARMul_State * state, ARMword instr) +{ + ARMword val; + int wCreg; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmcr\n"); +#endif + + if (BITS (0, 3) != 0) + return ARMul_CANT; + + val = state->Reg [BITS (12, 15)]; + if (BITS (12, 15) == 15) + val &= 0xfffffffc; + + wCreg = BITS (16, 19); + + switch (wCreg) + { + case wCID: + /* The wCID register is read only. */ + break; + + case wCon: + /* Writing to the MUP or CUP bits clears them. */ + wC [wCon] &= ~ (val & 0x3); + break; + + case wCSSF: + /* Only the bottom 8 bits can be written to. + The higher bits write as zero. */ + wC [wCSSF] = (val & 0xff); + wC [wCon] |= WCON_CUP; + break; + + default: + wC [wCreg] = val; + wC [wCon] |= WCON_CUP; + break; + } + + return ARMul_DONE; +} + +static int +TMCRR (ARMul_State * state, ARMword instr) +{ + ARMdword RdHi = state->Reg [BITS (16, 19)]; + ARMword RdLo = state->Reg [BITS (12, 15)]; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmcrr\n"); +#endif + + if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15)) + return ARMul_CANT; + + wR [BITS (0, 3)] = (RdHi << 32) | RdLo; + + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +TMIA (ARMul_State * state, ARMword instr) +{ + signed long long a, b; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmia\n"); +#endif + + if ((BITS (0, 3) == 15) || (BITS (12, 15) == 15)) + { + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + a = state->Reg [BITS (0, 3)]; + b = state->Reg [BITS (12, 15)]; + + a = EXTEND32 (a); + b = EXTEND32 (b); + + wR [BITS (5, 8)] += a * b; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +TMIAPH (ARMul_State * state, ARMword instr) +{ + signed long a, b, result; + signed long long r; + ARMword Rm = state->Reg [BITS (0, 3)]; + ARMword Rs = state->Reg [BITS (12, 15)]; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmiaph\n"); +#endif + + if (BITS (0, 3) == 15 || BITS (12, 15) == 15) + { + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + a = SUBSTR (Rs, ARMword, 16, 31); + b = SUBSTR (Rm, ARMword, 16, 31); + + a = EXTEND16 (a); + b = EXTEND16 (b); + + result = a * b; + + r = result; + r = EXTEND32 (r); + + wR [BITS (5, 8)] += r; + + a = SUBSTR (Rs, ARMword, 0, 15); + b = SUBSTR (Rm, ARMword, 0, 15); + + a = EXTEND16 (a); + b = EXTEND16 (b); + + result = a * b; + + r = result; + r = EXTEND32 (r); + + wR [BITS (5, 8)] += r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +TMIAxy (ARMul_State * state, ARMword instr) +{ + ARMword Rm; + ARMword Rs; + long long temp; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmiaxy\n"); +#endif + + if (BITS (0, 3) == 15 || BITS (12, 15) == 15) + { + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + Rm = state->Reg [BITS (0, 3)]; + if (BIT (17)) + Rm >>= 16; + else + Rm &= 0xffff; + + Rs = state->Reg [BITS (12, 15)]; + if (BIT (16)) + Rs >>= 16; + else + Rs &= 0xffff; + + if (Rm & (1 << 15)) + Rm -= 1 << 16; + + if (Rs & (1 << 15)) + Rs -= 1 << 16; + + Rm *= Rs; + temp = Rm; + + if (temp & (1 << 31)) + temp -= 1ULL << 32; + + wR [BITS (5, 8)] += temp; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +TMOVMSK (ARMul_State * state, ARMword instr) +{ + ARMdword result; + int wRn; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmovmsk\n"); +#endif + + /* The CRm field must be r0. */ + if (BITS (0, 3) != 0) + return ARMul_CANT; + + wRn = BITS (16, 19); + + switch (BITS (22, 23)) + { + case Bqual: + result = ( (wRBITS (wRn, 63, 63) << 7) + | (wRBITS (wRn, 55, 55) << 6) + | (wRBITS (wRn, 47, 47) << 5) + | (wRBITS (wRn, 39, 39) << 4) + | (wRBITS (wRn, 31, 31) << 3) + | (wRBITS (wRn, 23, 23) << 2) + | (wRBITS (wRn, 15, 15) << 1) + | (wRBITS (wRn, 7, 7) << 0)); + break; + + case Hqual: + result = ( (wRBITS (wRn, 63, 63) << 3) + | (wRBITS (wRn, 47, 47) << 2) + | (wRBITS (wRn, 31, 31) << 1) + | (wRBITS (wRn, 15, 15) << 0)); + break; + + case Wqual: + result = (wRBITS (wRn, 63, 63) << 1) | wRBITS (wRn, 31, 31); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + state->Reg [BITS (12, 15)] = result; + + return ARMul_DONE; +} + +static int +TMRC (ARMul_State * state, ARMword instr) +{ + int reg = BITS (12, 15); + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmrc\n"); +#endif + + if (BITS (0, 3) != 0) + return ARMul_CANT; + + if (reg == 15) + ARMul_UndefInstr (state, instr); + else + state->Reg [reg] = wC [BITS (16, 19)]; + + return ARMul_DONE; +} + +static int +TMRRC (ARMul_State * state, ARMword instr) +{ + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "tmrrc\n"); +#endif + + if ((BITS (16, 19) == 15) || (BITS (12, 15) == 15) || (BITS (4, 11) != 0)) + ARMul_UndefInstr (state, instr); + else + { + state->Reg [BITS (16, 19)] = wRBITS (BITS (0, 3), 32, 63); + state->Reg [BITS (12, 15)] = wRBITS (BITS (0, 3), 0, 31); + } + + return ARMul_DONE; +} + +static int +TORC (ARMul_State * state, ARMword instr) +{ + ARMword cpsr = ARMul_GetCPSR (state); + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "torc\n"); +#endif + + /* The Rd field must be r15. */ + if (BITS (12, 15) != 15) + return ARMul_CANT; + + /* The CRn field must be r3. */ + if (BITS (16, 19) != 3) + return ARMul_CANT; + + /* The CRm field must be r0. */ + if (BITS (0, 3) != 0) + return ARMul_CANT; + + cpsr &= 0x0fffffff; + + switch (BITS (22, 23)) + { + case Bqual: + cpsr |= ( (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 24, 27) + | wCBITS (wCASF, 20, 23) | wCBITS (wCASF, 16, 19) + | wCBITS (wCASF, 12, 15) | wCBITS (wCASF, 8, 11) + | wCBITS (wCASF, 4, 7) | wCBITS (wCASF, 0, 3)) << 28); + break; + + case Hqual: + cpsr |= ( (wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 20, 23) + | wCBITS (wCASF, 12, 15) | wCBITS (wCASF, 4, 7)) << 28); + break; + + case Wqual: + cpsr |= ((wCBITS (wCASF, 28, 31) | wCBITS (wCASF, 12, 15)) << 28); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + ARMul_SetCPSR (state, cpsr); + + return ARMul_DONE; +} + +static int +WACC (ARMul_State * state, ARMword instr) +{ + int wRn; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wacc\n"); +#endif + + wRn = BITS (16, 19); + + switch (BITS (22, 23)) + { + case Bqual: + wR [BITS (12, 15)] = + wRBITS (wRn, 56, 63) + wRBITS (wRn, 48, 55) + + wRBITS (wRn, 40, 47) + wRBITS (wRn, 32, 39) + + wRBITS (wRn, 24, 31) + wRBITS (wRn, 16, 23) + + wRBITS (wRn, 8, 15) + wRBITS (wRn, 0, 7); + break; + + case Hqual: + wR [BITS (12, 15)] = + wRBITS (wRn, 48, 63) + wRBITS (wRn, 32, 47) + + wRBITS (wRn, 16, 31) + wRBITS (wRn, 0, 15); + break; + + case Wqual: + wR [BITS (12, 15)] = wRBITS (wRn, 32, 63) + wRBITS (wRn, 0, 31); + break; + + default: + ARMul_UndefInstr (state, instr); + break; + } + + wC [wCon] |= WCON_MUP; + return ARMul_DONE; +} + +static int +WADD (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword x; + ARMdword s; + ARMword psr = 0; + int i; + int carry; + int overflow; + int satrv[8]; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wadd\n"); +#endif + + /* Add two numbers using the specified function, + leaving setting the carry bit as required. */ +#define ADDx(x, y, m, f) \ + (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \ + wRBITS (BITS ( 0, 3), (x), (y)) & (m), \ + & carry, & overflow) + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 8; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8); + satrv [BITIDX8 (i)] = 0; + r |= (s & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddU8); + x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i)); + r |= (x & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX8 (i)]) + { + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = ADDx ((i * 8), (i * 8) + 7, 0xff, AddS8); + x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i)); + r |= (x & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX8 (i)]) + { + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + case Hqual: + satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; + + for (i = 0; i < 4; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16); + satrv [BITIDX16 (i)] = 0; + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddU16); + x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i)); + r |= (x & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX16 (i)]) + { + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = ADDx ((i * 16), (i * 16) + 15, 0xffff, AddS16); + x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i)); + r |= (x & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX16 (i)]) + { + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + case Wqual: + satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; + + for (i = 0; i < 2; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32); + satrv [BITIDX32 (i)] = 0; + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddU32); + x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i)); + r |= (x & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX32 (i)]) + { + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = ADDx ((i * 32), (i * 32) + 31, 0xffffffff, AddS32); + x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i)); + r |= (x & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX32 (i)]) + { + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_MUP | WCON_CUP); + + SET_wCSSFvec (satrv); + +#undef ADDx + + return ARMul_DONE; +} + +static int +WALIGNI (ARMword instr) +{ + int shift = BITS (20, 22) * 8; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "waligni\n"); +#endif + + if (shift) + wR [BITS (12, 15)] = + wRBITS (BITS (16, 19), shift, 63) + | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift))); + else + wR [BITS (12, 15)] = wR [BITS (16, 19)]; + + wC [wCon] |= WCON_MUP; + return ARMul_DONE; +} + +static int +WALIGNR (ARMul_State * state, ARMword instr) +{ + int shift = (wC [BITS (20, 21) + 8] & 0x7) * 8; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "walignr\n"); +#endif + + if (shift) + wR [BITS (12, 15)] = + wRBITS (BITS (16, 19), shift, 63) + | (wRBITS (BITS (0, 3), 0, shift) << ((64 - shift))); + else + wR [BITS (12, 15)] = wR [BITS (16, 19)]; + + wC [wCon] |= WCON_MUP; + return ARMul_DONE; +} + +static int +WAND (ARMword instr) +{ + ARMdword result; + ARMword psr = 0; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wand\n"); +#endif + + result = wR [BITS (16, 19)] & wR [BITS (0, 3)]; + wR [BITS (12, 15)] = result; + + SIMD64_SET (psr, (result == 0), SIMD_ZBIT); + SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); + + wC [wCASF] = psr; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WANDN (ARMword instr) +{ + ARMdword result; + ARMword psr = 0; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wandn\n"); +#endif + + result = wR [BITS (16, 19)] & ~ wR [BITS (0, 3)]; + wR [BITS (12, 15)] = result; + + SIMD64_SET (psr, (result == 0), SIMD_ZBIT); + SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); + + wC [wCASF] = psr; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WAVG2 (ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + int round = BIT (20) ? 1 : 0; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wavg2\n"); +#endif + +#define AVG2x(x, y, m) (((wRBITS (BITS (16, 19), (x), (y)) & (m)) \ + + (wRBITS (BITS ( 0, 3), (x), (y)) & (m)) \ + + round) / 2) + + if (BIT (22)) + { + for (i = 0; i < 4; i++) + { + s = AVG2x ((i * 16), (i * 16) + 15, 0xffff) & 0xffff; + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + r |= s << (i * 16); + } + } + else + { + for (i = 0; i < 8; i++) + { + s = AVG2x ((i * 8), (i * 8) + 7, 0xff) & 0xff; + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + r |= s << (i * 8); + } + } + + wR [BITS (12, 15)] = r; + wC [wCASF] = psr; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WCMPEQ (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wcmpeq\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 8; i++) + { + s = wRBYTE (BITS (16, 19), i) == wRBYTE (BITS (0, 3), i) ? 0xff : 0; + r |= s << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + } + break; + + case Hqual: + for (i = 0; i < 4; i++) + { + s = wRHALF (BITS (16, 19), i) == wRHALF (BITS (0, 3), i) ? 0xffff : 0; + r |= s << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + { + s = wRWORD (BITS (16, 19), i) == wRWORD (BITS (0, 3), i) ? 0xffffffff : 0; + r |= s << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WCMPGT (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wcmpgt\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + if (BIT (21)) + { + /* Use a signed comparison. */ + for (i = 0; i < 8; i++) + { + signed char a, b; + + a = wRBYTE (BITS (16, 19), i); + b = wRBYTE (BITS (0, 3), i); + + s = (a > b) ? 0xff : 0; + r |= s << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + } + } + else + { + for (i = 0; i < 8; i++) + { + s = (wRBYTE (BITS (16, 19), i) > wRBYTE (BITS (0, 3), i)) + ? 0xff : 0; + r |= s << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + } + } + break; + + case Hqual: + if (BIT (21)) + { + for (i = 0; i < 4; i++) + { + signed int a, b; + + a = wRHALF (BITS (16, 19), i); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i); + b = EXTEND16 (b); + + s = (a > b) ? 0xffff : 0; + r |= s << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + } + else + { + for (i = 0; i < 4; i++) + { + s = (wRHALF (BITS (16, 19), i) > wRHALF (BITS (0, 3), i)) + ? 0xffff : 0; + r |= s << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + } + break; + + case Wqual: + if (BIT (21)) + { + for (i = 0; i < 2; i++) + { + signed long a, b; + + a = wRWORD (BITS (16, 19), i); + b = wRWORD (BITS (0, 3), i); + + s = (a > b) ? 0xffffffff : 0; + r |= s << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + } + else + { + for (i = 0; i < 2; i++) + { + s = (wRWORD (BITS (16, 19), i) > wRWORD (BITS (0, 3), i)) + ? 0xffffffff : 0; + r |= s << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static ARMword +Compute_Iwmmxt_Address (ARMul_State * state, ARMword instr, int * pFailed) +{ + ARMword Rn; + ARMword addr; + ARMword offset; + ARMword multiplier; + + * pFailed = 0; + Rn = BITS (16, 19); + addr = state->Reg [Rn]; + offset = BITS (0, 7); + multiplier = BIT (8) ? 4 : 1; + + if (BIT (24)) /* P */ + { + /* Pre Indexed Addressing. */ + if (BIT (23)) + addr += offset * multiplier; + else + addr -= offset * multiplier; + + /* Immediate Pre-Indexed. */ + if (BIT (21)) /* W */ + { + if (Rn == 15) + { + /* Writeback into R15 is UNPREDICTABLE. */ +#ifdef DEBUG + fprintf (stderr, "iWMMXt: writeback into r15\n"); +#endif + * pFailed = 1; + } + else + state->Reg [Rn] = addr; + } + } + else + { + /* Post Indexed Addressing. */ + if (BIT (21)) /* W */ + { + /* Handle the write back of the final address. */ + if (Rn == 15) + { + /* Writeback into R15 is UNPREDICTABLE. */ +#ifdef DEBUG + fprintf (stderr, "iWMMXt: writeback into r15\n"); +#endif + * pFailed = 1; + } + else + { + ARMword increment; + + if (BIT (23)) + increment = offset * multiplier; + else + increment = - (offset * multiplier); + + state->Reg [Rn] = addr + increment; + } + } + else + { + /* P == 0, W == 0, U == 0 is UNPREDICTABLE. */ + if (BIT (23) == 0) + { +#ifdef DEBUG + fprintf (stderr, "iWMMXt: undefined addressing mode\n"); +#endif + * pFailed = 1; + } + } + } + + return addr; +} + +static ARMdword +Iwmmxt_Load_Double_Word (ARMul_State * state, ARMword address) +{ + ARMdword value; + + /* The address must be aligned on a 8 byte boundary. */ + if (address & 0x7) + { + fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word load from 0x%x\n", + (state->Reg[15] - 8) & ~0x3, address); +#ifdef DEBUG +#endif + /* No need to check for alignment traps. An unaligned + double word load with alignment trapping disabled is + UNPREDICTABLE. */ + ARMul_Abort (state, ARMul_DataAbortV); + } + + /* Load the words. */ + if (! state->bigendSig) + { + value = ARMul_LoadWordN (state, address + 4); + value <<= 32; + value |= ARMul_LoadWordN (state, address); + } + else + { + value = ARMul_LoadWordN (state, address); + value <<= 32; + value |= ARMul_LoadWordN (state, address + 4); + } + + /* Check for data aborts. */ + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); + else + ARMul_Icycles (state, 2, 0L); + + return value; +} + +static ARMword +Iwmmxt_Load_Word (ARMul_State * state, ARMword address) +{ + ARMword value; + + /* Check for a misaligned address. */ + if (address & 3) + { + if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) + ARMul_Abort (state, ARMul_DataAbortV); + else + address &= ~ 3; + } + + value = ARMul_LoadWordN (state, address); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); + else + ARMul_Icycles (state, 1, 0L); + + return value; +} + +static ARMword +Iwmmxt_Load_Half_Word (ARMul_State * state, ARMword address) +{ + ARMword value; + + /* Check for a misaligned address. */ + if (address & 1) + { + if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) + ARMul_Abort (state, ARMul_DataAbortV); + else + address &= ~ 1; + } + + value = ARMul_LoadHalfWord (state, address); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); + else + ARMul_Icycles (state, 1, 0L); + + return value; +} + +static ARMword +Iwmmxt_Load_Byte (ARMul_State * state, ARMword address) +{ + ARMword value; + + value = ARMul_LoadByte (state, address); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); + else + ARMul_Icycles (state, 1, 0L); + + return value; +} + +static void +Iwmmxt_Store_Double_Word (ARMul_State * state, ARMword address, ARMdword value) +{ + /* The address must be aligned on a 8 byte boundary. */ + if (address & 0x7) + { + fprintf (stderr, "iWMMXt: At addr 0x%x: Unaligned double word store to 0x%x\n", + (state->Reg[15] - 8) & ~0x3, address); +#ifdef DEBUG +#endif + /* No need to check for alignment traps. An unaligned + double word store with alignment trapping disabled is + UNPREDICTABLE. */ + ARMul_Abort (state, ARMul_DataAbortV); + } + + /* Store the words. */ + if (! state->bigendSig) + { + ARMul_StoreWordN (state, address, value); + ARMul_StoreWordN (state, address + 4, value >> 32); + } + else + { + ARMul_StoreWordN (state, address + 4, value); + ARMul_StoreWordN (state, address, value >> 32); + } + + /* Check for data aborts. */ + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); + else + ARMul_Icycles (state, 2, 0L); +} + +static void +Iwmmxt_Store_Word (ARMul_State * state, ARMword address, ARMword value) +{ + /* Check for a misaligned address. */ + if (address & 3) + { + if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) + ARMul_Abort (state, ARMul_DataAbortV); + else + address &= ~ 3; + } + + ARMul_StoreWordN (state, address, value); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); +} + +static void +Iwmmxt_Store_Half_Word (ARMul_State * state, ARMword address, ARMword value) +{ + /* Check for a misaligned address. */ + if (address & 1) + { + if ((read_cp15_reg (1, 0, 0) & ARMul_CP15_R1_ALIGN)) + ARMul_Abort (state, ARMul_DataAbortV); + else + address &= ~ 1; + } + + ARMul_StoreHalfWord (state, address, value); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); +} + +static void +Iwmmxt_Store_Byte (ARMul_State * state, ARMword address, ARMword value) +{ + ARMul_StoreByte (state, address, value); + + if (state->Aborted) + ARMul_Abort (state, ARMul_DataAbortV); +} + +static int +WLDR (ARMul_State * state, ARMword instr) +{ + ARMword address; + int failed; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wldr\n"); +#endif + + address = Compute_Iwmmxt_Address (state, instr, & failed); + if (failed) + return ARMul_CANT; + + if (BITS (28, 31) == 0xf) + { + /* WLDRW wCx */ + wC [BITS (12, 15)] = Iwmmxt_Load_Word (state, address); + } + else if (BIT (8) == 0) + { + if (BIT (22) == 0) + /* WLDRB */ + wR [BITS (12, 15)] = Iwmmxt_Load_Byte (state, address); + else + /* WLDRH */ + wR [BITS (12, 15)] = Iwmmxt_Load_Half_Word (state, address); + } + else + { + if (BIT (22) == 0) + /* WLDRW wRd */ + wR [BITS (12, 15)] = Iwmmxt_Load_Word (state, address); + else + /* WLDRD */ + wR [BITS (12, 15)] = Iwmmxt_Load_Double_Word (state, address); + } + + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WMAC (ARMword instr) +{ + int i; + ARMdword t = 0; + ARMword a, b; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wmac\n"); +#endif + + for (i = 0; i < 4; i++) + { + if (BIT (21)) + { + /* Signed. */ + signed long s; + + a = wRHALF (BITS (16, 19), i); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i); + b = EXTEND16 (b); + + s = (signed long) a * (signed long) b; + + (signed long long) t += s; + } + else + { + /* Unsigned. */ + a = wRHALF (BITS (16, 19), i); + b = wRHALF (BITS ( 0, 3), i); + + t += a * b; + } + } + + if (BIT (20)) + wR [BITS (12, 15)] = 0; + + if (BIT (21)) /* Signed. */ + (signed long long) wR[BITS (12, 15)] += (signed long long) t; + else + wR [BITS (12, 15)] += t; + + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WMADD (ARMword instr) +{ + ARMdword r = 0; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wmadd\n"); +#endif + + for (i = 0; i < 2; i++) + { + ARMdword s1, s2; + + if (BIT (21)) /* Signed. */ + { + signed long a, b; + + a = wRHALF (BITS (16, 19), i * 2); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i * 2); + b = EXTEND16 (b); + + (signed long) s1 = a * b; + + a = wRHALF (BITS (16, 19), i * 2 + 1); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i * 2 + 1); + b = EXTEND16 (b); + + (signed long) s2 = a * b; + } + else /* Unsigned. */ + { + unsigned long a, b; + + a = wRHALF (BITS (16, 19), i * 2); + b = wRHALF (BITS ( 0, 3), i * 2); + + (unsigned long) s1 = a * b; + + a = wRHALF (BITS (16, 19), i * 2 + 1); + b = wRHALF (BITS ( 0, 3), i * 2 + 1); + + (signed long) s2 = a * b; + } + + r |= (ARMdword) ((s1 + s2) & 0xffffffff) << (i ? 32 : 0); + } + + wR [BITS (12, 15)] = r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WMAX (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wmax\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 8; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRBYTE (BITS (16, 19), i); + a = EXTEND8 (a); + + b = wRBYTE (BITS (0, 3), i); + b = EXTEND8 (b); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xff) << (i * 8); + } + else /* Unsigned. */ + { + unsigned int a, b; + + a = wRBYTE (BITS (16, 19), i); + b = wRBYTE (BITS (0, 3), i); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xff) << (i * 8); + } + break; + + case Hqual: + for (i = 0; i < 4; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRHALF (BITS (16, 19), i); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i); + b = EXTEND16 (b); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xffff) << (i * 16); + } + else /* Unsigned. */ + { + unsigned int a, b; + + a = wRHALF (BITS (16, 19), i); + b = wRHALF (BITS (0, 3), i); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xffff) << (i * 16); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRWORD (BITS (16, 19), i); + b = wRWORD (BITS (0, 3), i); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xffffffff) << (i * 32); + } + else + { + unsigned int a, b; + + a = wRWORD (BITS (16, 19), i); + b = wRWORD (BITS (0, 3), i); + + if (a > b) + s = a; + else + s = b; + + r |= (s & 0xffffffff) << (i * 32); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wR [BITS (12, 15)] = r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WMIN (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wmin\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 8; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRBYTE (BITS (16, 19), i); + a = EXTEND8 (a); + + b = wRBYTE (BITS (0, 3), i); + b = EXTEND8 (b); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xff) << (i * 8); + } + else /* Unsigned. */ + { + unsigned int a, b; + + a = wRBYTE (BITS (16, 19), i); + b = wRBYTE (BITS (0, 3), i); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xff) << (i * 8); + } + break; + + case Hqual: + for (i = 0; i < 4; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRHALF (BITS (16, 19), i); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i); + b = EXTEND16 (b); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xffff) << (i * 16); + } + else + { + /* Unsigned. */ + unsigned int a, b; + + a = wRHALF (BITS (16, 19), i); + b = wRHALF (BITS ( 0, 3), i); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xffff) << (i * 16); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + if (BIT (21)) /* Signed. */ + { + int a, b; + + a = wRWORD (BITS (16, 19), i); + b = wRWORD (BITS ( 0, 3), i); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xffffffff) << (i * 32); + } + else + { + unsigned int a, b; + + a = wRWORD (BITS (16, 19), i); + b = wRWORD (BITS (0, 3), i); + + if (a < b) + s = a; + else + s = b; + + r |= (s & 0xffffffff) << (i * 32); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wR [BITS (12, 15)] = r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WMUL (ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wmul\n"); +#endif + + for (i = 0; i < 4; i++) + if (BIT (21)) /* Signed. */ + { + long a, b; + + a = wRHALF (BITS (16, 19), i); + a = EXTEND16 (a); + + b = wRHALF (BITS (0, 3), i); + b = EXTEND16 (b); + + s = a * b; + + if (BIT (20)) + r |= ((s >> 16) & 0xffff) << (i * 16); + else + r |= (s & 0xffff) << (i * 16); + } + else /* Unsigned. */ + { + unsigned long a, b; + + a = wRHALF (BITS (16, 19), i); + b = wRHALF (BITS (0, 3), i); + + s = a * b; + + if (BIT (20)) + r |= ((s >> 16) & 0xffff) << (i * 16); + else + r |= (s & 0xffff) << (i * 16); + } + + wR [BITS (12, 15)] = r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WOR (ARMword instr) +{ + ARMword psr = 0; + ARMdword result; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wor\n"); +#endif + + result = wR [BITS (16, 19)] | wR [BITS (0, 3)]; + wR [BITS (12, 15)] = result; + + SIMD64_SET (psr, (result == 0), SIMD_ZBIT); + SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); + + wC [wCASF] = psr; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WPACK (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword x; + ARMdword s; + int i; + int satrv[8]; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wpack\n"); +#endif + + switch (BITS (22, 23)) + { + case Hqual: + for (i = 0; i < 8; i++) + { + x = wRHALF (i < 4 ? BITS (16, 19) : BITS (0, 3), i & 3); + + switch (BITS (20, 21)) + { + case UnsignedSaturation: + s = IwmmxtSaturateU8 (x, satrv + BITIDX8 (i)); + break; + + case SignedSaturation: + s = IwmmxtSaturateS8 (x, satrv + BITIDX8 (i)); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + r |= (s & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; + + for (i = 0; i < 4; i++) + { + x = wRWORD (i < 2 ? BITS (16, 19) : BITS (0, 3), i & 1); + + switch (BITS (20, 21)) + { + case UnsignedSaturation: + s = IwmmxtSaturateU16 (x, satrv + BITIDX16 (i)); + break; + + case SignedSaturation: + s = IwmmxtSaturateS16 (x, satrv + BITIDX16 (i)); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Dqual: + satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; + + for (i = 0; i < 2; i++) + { + x = wR [i ? BITS (0, 3) : BITS (16, 19)]; + + switch (BITS (20, 21)) + { + case UnsignedSaturation: + s = IwmmxtSaturateU32 (x, satrv + BITIDX32 (i)); + break; + + case SignedSaturation: + s = IwmmxtSaturateS32 (x, satrv + BITIDX32 (i)); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + SET_wCSSFvec (satrv); + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WROR (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + ARMword psr = 0; + int i; + int shift; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wror\n"); +#endif + + DECODE_G_BIT (state, instr, shift); + + switch (BITS (22, 23)) + { + case Hqual: + shift &= 0xf; + for (i = 0; i < 4; i++) + { + s = ((wRHALF (BITS (16, 19), i) & 0xffff) << (16 - shift)) + | ((wRHALF (BITS (16, 19), i) & 0xffff) >> shift); + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + shift &= 0x1f; + for (i = 0; i < 2; i++) + { + s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << (32 - shift)) + | ((wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift); + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Dqual: + shift &= 0x3f; + r = (wR [BITS (16, 19)] >> shift) + | (wR [BITS (16, 19)] << (64 - shift)); + + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WSAD (ARMword instr) +{ + ARMdword r; + int s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wsad\n"); +#endif + + /* Z bit. */ + r = BIT (20) ? 0 : (wR [BITS (12, 15)] & 0xffffffff); + + if (BIT (22)) + /* Half. */ + for (i = 0; i < 4; i++) + { + s = (wRHALF (BITS (16, 19), i) - wRHALF (BITS (0, 3), i)); + r += abs (s); + } + else + /* Byte. */ + for (i = 0; i < 8; i++) + { + s = (wRBYTE (BITS (16, 19), i) - wRBYTE (BITS (0, 3), i)); + r += abs (s); + } + + wR [BITS (12, 15)] = r; + wC [wCon] |= WCON_MUP; + + return ARMul_DONE; +} + +static int +WSHUFH (ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + int imm8; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wshufh\n"); +#endif + + imm8 = (BITS (20, 23) << 4) | BITS (0, 3); + + for (i = 0; i < 4; i++) + { + s = wRHALF (BITS (16, 19), ((imm8 >> (i * 2) & 3)) & 0xff); + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WSLL (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + ARMword psr = 0; + int i; + unsigned shift; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wsll\n"); +#endif + + DECODE_G_BIT (state, instr, shift); + + switch (BITS (22, 23)) + { + case Hqual: + for (i = 0; i < 4; i++) + { + if (shift > 15) + s = 0; + else + s = ((wRHALF (BITS (16, 19), i) & 0xffff) << shift); + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + { + if (shift > 31) + s = 0; + else + s = ((wRWORD (BITS (16, 19), i) & 0xffffffff) << shift); + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Dqual: + if (shift > 63) + r = 0; + else + r = ((wR[BITS (16, 19)] & 0xffffffffffffffff) << shift); + + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WSRA (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + ARMword psr = 0; + int i; + unsigned shift; + signed long t; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wsra\n"); +#endif + + DECODE_G_BIT (state, instr, shift); + + switch (BITS (22, 23)) + { + case Hqual: + for (i = 0; i < 4; i++) + { + if (shift > 15) + t = (wRHALF (BITS (16, 19), i) & 0x8000) ? 0xffff : 0; + else + { + t = wRHALF (BITS (16, 19), i); + t = EXTEND16 (t); + t >>= shift; + } + + s = t; + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + { + if (shift > 31) + t = (wRWORD (BITS (16, 19), i) & 0x80000000) ? 0xffffffff : 0; + else + { + t = wRWORD (BITS (16, 19), i); + t >>= shift; + } + s = t; + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Dqual: + if (shift > 63) + r = (wR [BITS (16, 19)] & 0x8000000000000000) ? 0xffffffffffffffff : 0; + else + r = ((signed long long) (wR[BITS (16, 19)] & 0xffffffffffffffff) >> shift); + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WSRL (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMdword s; + ARMword psr = 0; + int i; + unsigned int shift; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wsrl\n"); +#endif + + DECODE_G_BIT (state, instr, shift); + + switch (BITS (22, 23)) + { + case Hqual: + for (i = 0; i < 4; i++) + { + if (shift > 15) + s = 0; + else + s = ((unsigned) (wRHALF (BITS (16, 19), i) & 0xffff) >> shift); + + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + for (i = 0; i < 2; i++) + { + if (shift > 31) + s = 0; + else + s = ((unsigned long) (wRWORD (BITS (16, 19), i) & 0xffffffff) >> shift); + + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Dqual: + if (shift > 63) + r = 0; + else + r = (wR [BITS (16, 19)] & 0xffffffffffffffff) >> shift; + + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WSTR (ARMul_State * state, ARMword instr) +{ + ARMword address; + int failed; + + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wstr\n"); +#endif + + address = Compute_Iwmmxt_Address (state, instr, & failed); + if (failed) + return ARMul_CANT; + + if (BITS (28, 31) == 0xf) + { + /* WSTRW wCx */ + Iwmmxt_Store_Word (state, address, wC [BITS (12, 15)]); + } + else if (BIT (8) == 0) + { + if (BIT (22) == 0) + /* WSTRB */ + Iwmmxt_Store_Byte (state, address, wR [BITS (12, 15)]); + else + /* WSTRH */ + Iwmmxt_Store_Half_Word (state, address, wR [BITS (12, 15)]); + } + else + { + if (BIT (22) == 0) + /* WSTRW wRd */ + Iwmmxt_Store_Word (state, address, wR [BITS (12, 15)]); + else + /* WSTRD */ + Iwmmxt_Store_Double_Word (state, address, wR [BITS (12, 15)]); + } + + return ARMul_DONE; +} + +static int +WSUB (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword x; + ARMdword s; + int i; + int carry; + int overflow; + int satrv[8]; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wsub\n"); +#endif + +/* Subtract two numbers using the specified function, + leaving setting the carry bit as required. */ +#define SUBx(x, y, m, f) \ + (*f) (wRBITS (BITS (16, 19), (x), (y)) & (m), \ + wRBITS (BITS ( 0, 3), (x), (y)) & (m), & carry, & overflow) + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 8; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8); + satrv [BITIDX8 (i)] = 0; + r |= (s & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (s), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (s), SIMD_ZBIT, i); + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubU8); + x = IwmmxtSaturateU8 (s, satrv + BITIDX8 (i)); + r |= (x & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX8 (i)]) + { + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = SUBx ((i * 8), (i * 8) + 7, 0xff, SubS8); + x = IwmmxtSaturateS8 (s, satrv + BITIDX8 (i)); + r |= (x & 0xff) << (i * 8); + SIMD8_SET (psr, NBIT8 (x), SIMD_NBIT, i); + SIMD8_SET (psr, ZBIT8 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX8 (i)]) + { + SIMD8_SET (psr, carry, SIMD_CBIT, i); + SIMD8_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + case Hqual: + satrv[0] = satrv[2] = satrv[4] = satrv[6] = 0; + + for (i = 0; i < 4; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16); + satrv [BITIDX16 (i)] = 0; + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubU16); + x = IwmmxtSaturateU16 (s, satrv + BITIDX16 (i)); + r |= (x & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (x & 0xffff), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX16 (i)]) + { + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = SUBx ((i * 16), (i * 16) + 15, 0xffff, SubS16); + x = IwmmxtSaturateS16 (s, satrv + BITIDX16 (i)); + r |= (x & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (x), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX16 (i)]) + { + SIMD16_SET (psr, carry, SIMD_CBIT, i); + SIMD16_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + case Wqual: + satrv[0] = satrv[1] = satrv[2] = satrv[4] = satrv[5] = satrv[6] = 0; + + for (i = 0; i < 2; i++) + { + switch (BITS (20, 21)) + { + case NoSaturation: + s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32); + satrv[BITIDX32 (i)] = 0; + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + break; + + case UnsignedSaturation: + s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubU32); + x = IwmmxtSaturateU32 (s, satrv + BITIDX32 (i)); + r |= (x & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX32 (i)]) + { + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + case SignedSaturation: + s = SUBx ((i * 32), (i * 32) + 31, 0xffffffff, SubS32); + x = IwmmxtSaturateS32 (s, satrv + BITIDX32 (i)); + r |= (x & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (x), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (x), SIMD_ZBIT, i); + if (! satrv [BITIDX32 (i)]) + { + SIMD32_SET (psr, carry, SIMD_CBIT, i); + SIMD32_SET (psr, overflow, SIMD_VBIT, i); + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + } + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wR [BITS (12, 15)] = r; + wC [wCASF] = psr; + SET_wCSSFvec (satrv); + wC [wCon] |= (WCON_CUP | WCON_MUP); + +#undef SUBx + + return ARMul_DONE; +} + +static int +WUNPCKEH (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wunpckeh\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 4; i++) + { + s = wRBYTE (BITS (16, 19), i + 4); + + if (BIT (21) && NBIT8 (s)) + s |= 0xff00; + + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Hqual: + for (i = 0; i < 2; i++) + { + s = wRHALF (BITS (16, 19), i + 2); + + if (BIT (21) && NBIT16 (s)) + s |= 0xffff0000; + + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + r = wRWORD (BITS (16, 19), 1); + + if (BIT (21) && NBIT32 (r)) + r |= 0xffffffff00000000; + + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WUNPCKEL (ARMul_State * state, ARMword instr) +{ + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wunpckel\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 4; i++) + { + s = wRBYTE (BITS (16, 19), i); + + if (BIT (21) && NBIT8 (s)) + s |= 0xff00; + + r |= (s & 0xffff) << (i * 16); + SIMD16_SET (psr, NBIT16 (s), SIMD_NBIT, i); + SIMD16_SET (psr, ZBIT16 (s), SIMD_ZBIT, i); + } + break; + + case Hqual: + for (i = 0; i < 2; i++) + { + s = wRHALF (BITS (16, 19), i); + + if (BIT (21) && NBIT16 (s)) + s |= 0xffff0000; + + r |= (s & 0xffffffff) << (i * 32); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, i); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, i); + } + break; + + case Wqual: + r = wRWORD (BITS (16, 19), 0); + + if (BIT (21) && NBIT32 (r)) + r |= 0xffffffff00000000; + + SIMD64_SET (psr, NBIT64 (r), SIMD_NBIT); + SIMD64_SET (psr, ZBIT64 (r), SIMD_ZBIT); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WUNPCKIH (ARMul_State * state, ARMword instr) +{ + ARMword a, b; + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wunpckih\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 4; i++) + { + a = wRBYTE (BITS (16, 19), i + 4); + b = wRBYTE (BITS ( 0, 3), i + 4); + s = a | (b << 8); + r |= (s & 0xffff) << (i * 16); + SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2); + SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2); + SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1); + SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1); + } + break; + + case Hqual: + for (i = 0; i < 2; i++) + { + a = wRHALF (BITS (16, 19), i + 2); + b = wRHALF (BITS ( 0, 3), i + 2); + s = a | (b << 16); + r |= (s & 0xffffffff) << (i * 32); + SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2)); + SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2)); + SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1); + SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1); + } + break; + + case Wqual: + a = wRWORD (BITS (16, 19), 1); + s = wRWORD (BITS ( 0, 3), 1); + r = a | (s << 32); + + SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0); + SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WUNPCKIL (ARMul_State * state, ARMword instr) +{ + ARMword a, b; + ARMdword r = 0; + ARMword psr = 0; + ARMdword s; + int i; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wunpckil\n"); +#endif + + switch (BITS (22, 23)) + { + case Bqual: + for (i = 0; i < 4; i++) + { + a = wRBYTE (BITS (16, 19), i); + b = wRBYTE (BITS ( 0, 3), i); + s = a | (b << 8); + r |= (s & 0xffff) << (i * 16); + SIMD8_SET (psr, NBIT8 (a), SIMD_NBIT, i * 2); + SIMD8_SET (psr, ZBIT8 (a), SIMD_ZBIT, i * 2); + SIMD8_SET (psr, NBIT8 (b), SIMD_NBIT, (i * 2) + 1); + SIMD8_SET (psr, ZBIT8 (b), SIMD_ZBIT, (i * 2) + 1); + } + break; + + case Hqual: + for (i = 0; i < 2; i++) + { + a = wRHALF (BITS (16, 19), i); + b = wRHALF (BITS ( 0, 3), i); + s = a | (b << 16); + r |= (s & 0xffffffff) << (i * 32); + SIMD16_SET (psr, NBIT16 (a), SIMD_NBIT, (i * 2)); + SIMD16_SET (psr, ZBIT16 (a), SIMD_ZBIT, (i * 2)); + SIMD16_SET (psr, NBIT16 (b), SIMD_NBIT, (i * 2) + 1); + SIMD16_SET (psr, ZBIT16 (b), SIMD_ZBIT, (i * 2) + 1); + } + break; + + case Wqual: + a = wRWORD (BITS (16, 19), 0); + s = wRWORD (BITS ( 0, 3), 0); + r = a | (s << 32); + + SIMD32_SET (psr, NBIT32 (a), SIMD_NBIT, 0); + SIMD32_SET (psr, ZBIT32 (a), SIMD_ZBIT, 0); + SIMD32_SET (psr, NBIT32 (s), SIMD_NBIT, 1); + SIMD32_SET (psr, ZBIT32 (s), SIMD_ZBIT, 1); + break; + + default: + ARMul_UndefInstr (state, instr); + return ARMul_DONE; + } + + wC [wCASF] = psr; + wR [BITS (12, 15)] = r; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +static int +WXOR (ARMword instr) +{ + ARMword psr = 0; + ARMdword result; + + if ((read_cp15_reg (15, 0, 1) & 3) != 3) + return ARMul_CANT; + +#ifdef DEBUG + fprintf (stderr, "wxor\n"); +#endif + + result = wR [BITS (16, 19)] ^ wR [BITS (0, 3)]; + wR [BITS (12, 15)] = result; + + SIMD64_SET (psr, (result == 0), SIMD_ZBIT); + SIMD64_SET (psr, (result & (1ULL << 63)), SIMD_NBIT); + + wC [wCASF] = psr; + wC [wCon] |= (WCON_CUP | WCON_MUP); + + return ARMul_DONE; +} + +/* This switch table is moved to a seperate function in order + to work around a compiler bug in the host compiler... */ + +static int +Process_Instruction (ARMul_State * state, ARMword instr) +{ + int status = ARMul_BUSY; + + switch ((BITS (20, 23) << 8) | BITS (4, 11)) + { + case 0x000: status = WOR (instr); break; + case 0x011: status = TMCR (state, instr); break; + case 0x100: status = WXOR (instr); break; + case 0x111: status = TMRC (state, instr); break; + case 0x300: status = WANDN (instr); break; + case 0x200: status = WAND (instr); break; + + case 0x810: case 0xa10: + status = WMADD (instr); break; + + case 0x10e: case 0x50e: case 0x90e: case 0xd0e: + status = WUNPCKIL (state, instr); break; + case 0x10c: case 0x50c: case 0x90c: case 0xd0c: + status = WUNPCKIH (state, instr); break; + case 0x012: case 0x112: case 0x412: case 0x512: + status = WSAD (instr); break; + case 0x010: case 0x110: case 0x210: case 0x310: + status = WMUL (instr); break; + case 0x410: case 0x510: case 0x610: case 0x710: + status = WMAC (instr); break; + case 0x006: case 0x406: case 0x806: case 0xc06: + status = WCMPEQ (state, instr); break; + case 0x800: case 0x900: case 0xc00: case 0xd00: + status = WAVG2 (instr); break; + case 0x802: case 0x902: case 0xa02: case 0xb02: + status = WALIGNR (state, instr); break; + case 0x601: case 0x605: case 0x609: case 0x60d: + status = TINSR (state, instr); break; + case 0x107: case 0x507: case 0x907: case 0xd07: + status = TEXTRM (state, instr); break; + case 0x117: case 0x517: case 0x917: case 0xd17: + status = TEXTRC (state, instr); break; + case 0x401: case 0x405: case 0x409: case 0x40d: + status = TBCST (state, instr); break; + case 0x113: case 0x513: case 0x913: case 0xd13: + status = TANDC (state, instr); break; + case 0x01c: case 0x41c: case 0x81c: case 0xc1c: + status = WACC (state, instr); break; + case 0x115: case 0x515: case 0x915: case 0xd15: + status = TORC (state, instr); break; + case 0x103: case 0x503: case 0x903: case 0xd03: + status = TMOVMSK (state, instr); break; + case 0x106: case 0x306: case 0x506: case 0x706: + case 0x906: case 0xb06: case 0xd06: case 0xf06: + status = WCMPGT (state, instr); break; + case 0x00e: case 0x20e: case 0x40e: case 0x60e: + case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e: + status = WUNPCKEL (state, instr); break; + case 0x00c: case 0x20c: case 0x40c: case 0x60c: + case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c: + status = WUNPCKEH (state, instr); break; + case 0x204: case 0x604: case 0xa04: case 0xe04: + case 0x214: case 0x614: case 0xa14: case 0xe14: + status = WSRL (state, instr); break; + case 0x004: case 0x404: case 0x804: case 0xc04: + case 0x014: case 0x414: case 0x814: case 0xc14: + status = WSRA (state, instr); break; + case 0x104: case 0x504: case 0x904: case 0xd04: + case 0x114: case 0x514: case 0x914: case 0xd14: + status = WSLL (state, instr); break; + case 0x304: case 0x704: case 0xb04: case 0xf04: + case 0x314: case 0x714: case 0xb14: case 0xf14: + status = WROR (state, instr); break; + case 0x116: case 0x316: case 0x516: case 0x716: + case 0x916: case 0xb16: case 0xd16: case 0xf16: + status = WMIN (state, instr); break; + case 0x016: case 0x216: case 0x416: case 0x616: + case 0x816: case 0xa16: case 0xc16: case 0xe16: + status = WMAX (state, instr); break; + case 0x002: case 0x102: case 0x202: case 0x302: + case 0x402: case 0x502: case 0x602: case 0x702: + status = WALIGNI (instr); break; + case 0x01a: case 0x11a: case 0x21a: case 0x31a: + case 0x41a: case 0x51a: case 0x61a: case 0x71a: + case 0x81a: case 0x91a: case 0xa1a: case 0xb1a: + case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a: + status = WSUB (state, instr); break; + case 0x01e: case 0x11e: case 0x21e: case 0x31e: + case 0x41e: case 0x51e: case 0x61e: case 0x71e: + case 0x81e: case 0x91e: case 0xa1e: case 0xb1e: + case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e: + status = WSHUFH (instr); break; + case 0x018: case 0x118: case 0x218: case 0x318: + case 0x418: case 0x518: case 0x618: case 0x718: + case 0x818: case 0x918: case 0xa18: case 0xb18: + case 0xc18: case 0xd18: case 0xe18: case 0xf18: + status = WADD (state, instr); break; + case 0x008: case 0x108: case 0x208: case 0x308: + case 0x408: case 0x508: case 0x608: case 0x708: + case 0x808: case 0x908: case 0xa08: case 0xb08: + case 0xc08: case 0xd08: case 0xe08: case 0xf08: + status = WPACK (state, instr); break; + case 0x201: case 0x203: case 0x205: case 0x207: + case 0x209: case 0x20b: case 0x20d: case 0x20f: + case 0x211: case 0x213: case 0x215: case 0x217: + case 0x219: case 0x21b: case 0x21d: case 0x21f: + switch (BITS (16, 19)) + { + case 0x0: status = TMIA (state, instr); break; + case 0x8: status = TMIAPH (state, instr); break; + case 0xc: + case 0xd: + case 0xe: + case 0xf: status = TMIAxy (state, instr); break; + default: break; + } + break; + default: + break; + } + return status; +} + +/* Process a possibly Intel(r) Wireless MMX(tm) technology instruction. + Return true if the instruction was handled. */ + +int +ARMul_HandleIwmmxt (ARMul_State * state, ARMword instr) +{ + int status = ARMul_BUSY; + + if (BITS (24, 27) == 0xe) + { + status = Process_Instruction (state, instr); + } + else if (BITS (25, 27) == 0x6) + { + if (BITS (4, 11) == 0x0 && BITS (20, 24) == 0x4) + status = TMCRR (state, instr); + else if (BITS (9, 11) == 0x0) + { + if (BIT (20) == 0x0) + status = WSTR (state, instr); + else if (BITS (20, 24) == 0x5) + status = TMRRC (state, instr); + else + status = WLDR (state, instr); + } + } + + if (status == ARMul_CANT) + { + /* If the instruction was a recognised but illegal, + perform the abort here rather than returning false. + If we return false then ARMul_MRC may be called which + will still abort, but which also perform the register + transfer... */ + ARMul_Abort (state, ARMul_UndefinedInstrV); + status = ARMul_DONE; + } + + return status == ARMul_DONE; +} + +int +Fetch_Iwmmxt_Register (unsigned int regnum, unsigned char * memory) +{ + if (regnum >= 16) + { + memcpy (memory, wC + (regnum - 16), sizeof wC [0]); + return sizeof wC [0]; + } + else + { + memcpy (memory, wR + regnum, sizeof wR [0]); + return sizeof wR [0]; + } +} + +int +Store_Iwmmxt_Register (unsigned int regnum, unsigned char * memory) +{ + if (regnum >= 16) + { + memcpy (wC + (regnum - 16), memory, sizeof wC [0]); + return sizeof wC [0]; + } + else + { + memcpy (wR + regnum, memory, sizeof wR [0]); + return sizeof wR [0]; + } +} diff --git a/sim/arm/iwmmxt.h b/sim/arm/iwmmxt.h new file mode 100644 index 0000000..e25feab --- /dev/null +++ b/sim/arm/iwmmxt.h @@ -0,0 +1,28 @@ +/* iwmmxt.h -- Intel(r) Wireless MMX(tm) technology co-processor interface. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by matthew green (mrg@redhat.com). + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +extern unsigned IwmmxtLDC (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned IwmmxtSTC (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned IwmmxtMCR (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned IwmmxtMRC (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned IwmmxtCDP (ARMul_State *, unsigned, ARMword); + +extern int ARMul_HandleIwmmxt (ARMul_State *, ARMword); + +extern int Fetch_Iwmmxt_Register (unsigned int, unsigned char *); +extern int Store_Iwmmxt_Register (unsigned int, unsigned char *); diff --git a/sim/arm/maverick.c b/sim/arm/maverick.c new file mode 100644 index 0000000..82871f9 --- /dev/null +++ b/sim/arm/maverick.c @@ -0,0 +1,1291 @@ +/* maverick.c -- Cirrus/DSP co-processor interface. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Aldy Hernandez (aldyh@redhat.com). + + 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "armdefs.h" +#include "ansidecl.h" +#include "armemu.h" + +/*#define CIRRUS_DEBUG 1 /**/ +#if CIRRUS_DEBUG +# define printfdbg printf +#else +# define printfdbg printf_nothing +#endif + +#define POS64(i) ( (~(i)) >> 63 ) +#define NEG64(i) ( (i) >> 63 ) + +/* Define Co-Processor instruction handlers here. */ + +/* Here's ARMulator's DSP definition. A few things to note: + 1) it has 16 64-bit registers and 4 72-bit accumulators + 2) you can only access its registers with MCR and MRC. */ + +/* We can't define these in here because this file might not be linked + unless the target is arm9e-*. They are defined in wrapper.c. + Eventually the simulator should be made to handle any coprocessor + at run time. */ +struct maverick_regs +{ + union + { + int i; + float f; + } upper; + + union + { + int i; + float f; + } lower; +}; + +union maverick_acc_regs +{ + long double ld; /* Acc registers are 72-bits. */ +}; + +struct maverick_regs DSPregs[16]; +union maverick_acc_regs DSPacc[4]; +ARMword DSPsc; + +#define DEST_REG (BITS (12, 15)) +#define SRC1_REG (BITS (16, 19)) +#define SRC2_REG (BITS (0, 3)) + +static int lsw_int_index, msw_int_index; +static int lsw_float_index, msw_float_index; + +static double mv_getRegDouble (int); +static long long mv_getReg64int (int); +static void mv_setRegDouble (int, double val); +static void mv_setReg64int (int, long long val); + +static union +{ + double d; + long long ll; + int ints[2]; +} reg_conv; + +static void +printf_nothing (void * foo, ...) +{ +} + +static void +cirrus_not_implemented (char * insn) +{ + fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); + fprintf (stderr, "aborting!\n"); + + exit (1); +} + +static unsigned +DSPInit (ARMul_State * state) +{ + ARMul_ConsolePrint (state, ", DSP present"); + return TRUE; +} + +unsigned +DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword * value) +{ + switch (BITS (5, 7)) + { + case 0: /* cfmvrdl */ + /* Move lower half of a DF stored in a DSP reg into an Arm reg. */ + printfdbg ("cfmvrdl\n"); + printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i); + printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); + + *value = (ARMword) DSPregs[SRC1_REG].lower.i; + break; + + case 1: /* cfmvrdh */ + /* Move upper half of a DF stored in a DSP reg into an Arm reg. */ + printfdbg ("cfmvrdh\n"); + printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i); + printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); + + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + break; + + case 2: /* cfmvrs */ + /* Move SF from upper half of a DSP register to an Arm register. */ + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + printfdbg ("cfmvrs = mvf%d <-- %f\n", + SRC1_REG, + DSPregs[SRC1_REG].upper.f); + break; + +#ifdef doesnt_work + case 4: /* cfcmps */ + { + float a, b; + int n, z, c, v; + + a = DSPregs[SRC1_REG].upper.f; + b = DSPregs[SRC2_REG].upper.f; + + printfdbg ("cfcmps\n"); + printfdbg ("\tcomparing %f and %f\n", a, b); + + z = a == b; /* zero */ + n = a != b; /* negative */ + v = a > b; /* overflow */ + c = 0; /* carry */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } + + case 5: /* cfcmpd */ + { + double a, b; + int n, z, c, v; + + a = mv_getRegDouble (SRC1_REG); + b = mv_getRegDouble (SRC2_REG); + + printfdbg ("cfcmpd\n"); + printfdbg ("\tcomparing %g and %g\n", a, b); + + z = a == b; /* zero */ + n = a != b; /* negative */ + v = a > b; /* overflow */ + c = 0; /* carry */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } +#else + case 4: /* cfcmps */ + { + float a, b; + int n, z, c, v; + + a = DSPregs[SRC1_REG].upper.f; + b = DSPregs[SRC2_REG].upper.f; + + printfdbg ("cfcmps\n"); + printfdbg ("\tcomparing %f and %f\n", a, b); + + z = a == b; /* zero */ + n = a < b; /* negative */ + c = a > b; /* carry */ + v = 0; /* fixme */ + printfdbg ("\tz = %d, n = %d\n", z, n); + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } + + case 5: /* cfcmpd */ + { + double a, b; + int n, z, c, v; + + a = mv_getRegDouble (SRC1_REG); + b = mv_getRegDouble (SRC2_REG); + + printfdbg ("cfcmpd\n"); + printfdbg ("\tcomparing %g and %g\n", a, b); + + z = a == b; /* zero */ + n = a < b; /* negative */ + c = a > b; /* carry */ + v = 0; /* fixme */ + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } +#endif + default: + fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword * value) +{ + switch (BITS (5, 7)) + { + case 0: /* cfmvr64l */ + /* Move lower half of 64bit int from Cirrus to Arm. */ + *value = (ARMword) DSPregs[SRC1_REG].lower.i; + printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n", + DEST_REG, + (int) *value); + break; + + case 1: /* cfmvr64h */ + /* Move upper half of 64bit int from Cirrus to Arm. */ + *value = (ARMword) DSPregs[SRC1_REG].upper.i; + printfdbg ("cfmvr64h <-- %d\n", (int) *value); + break; + + case 4: /* cfcmp32 */ + { + int res; + int n, z, c, v; + unsigned int a, b; + + printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", + SRC1_REG, + SRC2_REG); + + /* FIXME: see comment for cfcmps. */ + a = DSPregs[SRC1_REG].lower.i; + b = DSPregs[SRC2_REG].lower.i; + + res = DSPregs[SRC1_REG].lower.i - DSPregs[SRC2_REG].lower.i; + /* zero */ + z = res == 0; + /* negative */ + n = res < 0; + /* overflow */ + v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i, + res); + /* carry */ + c = (NEG (a) && POS (b) || + (NEG (a) && POS (res)) || (POS (b) && POS (res))); + + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } + + case 5: /* cfcmp64 */ + { + long long res; + int n, z, c, v; + unsigned long long a, b; + + printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", + SRC1_REG, + SRC2_REG); + + /* fixme: see comment for cfcmps. */ + + a = mv_getReg64int (SRC1_REG); + b = mv_getReg64int (SRC2_REG); + + res = mv_getReg64int (SRC1_REG) - mv_getReg64int (SRC2_REG); + /* zero */ + z = res == 0; + /* negative */ + n = res < 0; + /* overflow */ + v = ((NEG64 (a) && POS64 (b) && POS64 (res)) + || (POS64 (a) && NEG64 (b) && NEG64 (res))); + /* carry */ + c = (NEG64 (a) && POS64 (b) || + (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res))); + + *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); + break; + } + + default: + fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMRC6 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword * value) +{ + switch (BITS (5, 7)) + { + case 0: /* cfmval32 */ + cirrus_not_implemented ("cfmval32"); + break; + + case 1: /* cfmvam32 */ + cirrus_not_implemented ("cfmvam32"); + break; + + case 2: /* cfmvah32 */ + cirrus_not_implemented ("cfmvah32"); + break; + + case 3: /* cfmva32 */ + cirrus_not_implemented ("cfmva32"); + break; + + case 4: /* cfmva64 */ + cirrus_not_implemented ("cfmva64"); + break; + + case 5: /* cfmvsc32 */ + cirrus_not_implemented ("cfmvsc32"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR4 (ARMul_State * state, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword value) +{ + switch (BITS (5, 7)) + { + case 0: /* cfmvdlr */ + /* Move the lower half of a DF value from an Arm register into + the lower half of a Cirrus register. */ + printfdbg ("cfmvdlr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].lower.i = (int) value; + break; + + case 1: /* cfmvdhr */ + /* Move the upper half of a DF value from an Arm register into + the upper half of a Cirrus register. */ + printfdbg ("cfmvdhr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + case 2: /* cfmvsr */ + /* Move SF from Arm register into upper half of Cirrus register. */ + printfdbg ("cfmvsr <-- 0x%x\n", (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR5 (ARMul_State * state, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword value) +{ + union + { + int s; + unsigned int us; + } val; + + switch (BITS (5, 7)) + { + case 0: /* cfmv64lr */ + /* Move lower half of a 64bit int from an ARM register into the + lower half of a DSP register and sign extend it. */ + printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, (int) value); + DSPregs[SRC1_REG].lower.i = (int) value; + break; + + case 1: /* cfmv64hr */ + /* Move upper half of a 64bit int from an ARM register into the + upper half of a DSP register. */ + printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n", + SRC1_REG, + (int) value); + DSPregs[SRC1_REG].upper.i = (int) value; + break; + + case 2: /* cfrshl32 */ + printfdbg ("cfrshl32\n"); + val.us = value; + if (val.s > 0) + DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i << value; + else + DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -value; + break; + + case 3: /* cfrshl64 */ + printfdbg ("cfrshl64\n"); + val.us = value; + if (val.s > 0) + mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) << value); + else + mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) >> -value); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPMCR6 (ARMul_State * state, + unsigned type ATTRIBUTE_UNUSED, + ARMword instr, + ARMword value) +{ + switch (BITS (5, 7)) + { + case 0: /* cfmv32al */ + cirrus_not_implemented ("cfmv32al"); + break; + + case 1: /* cfmv32am */ + cirrus_not_implemented ("cfmv32am"); + break; + + case 2: /* cfmv32ah */ + cirrus_not_implemented ("cfmv32ah"); + break; + + case 3: /* cfmv32a */ + cirrus_not_implemented ("cfmv32a"); + break; + + case 4: /* cfmv64a */ + cirrus_not_implemented ("cfmv64a"); + break; + + case 5: /* cfmv32sc */ + cirrus_not_implemented ("cfmv32sc"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPLDC4 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type, + ARMword instr, + ARMword data) +{ + static unsigned words; + + if (type != ARMul_DATA) + { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) + { /* it's a long access, get two words */ + /* cfldrd */ + + printfdbg ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n", + data, words, state->bigendSig, DEST_REG); + + if (words == 0) + { + if (state->bigendSig) + DSPregs[DEST_REG].upper.i = (int) data; + else + DSPregs[DEST_REG].lower.i = (int) data; + } + else + { + if (state->bigendSig) + DSPregs[DEST_REG].lower.i = (int) data; + else + DSPregs[DEST_REG].upper.i = (int) data; + } + + ++ words; + + if (words == 2) + { + printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, + mv_getRegDouble (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else + { + /* Get just one word. */ + + /* cfldrs */ + printfdbg ("cfldrs\n"); + + DSPregs[DEST_REG].upper.i = (int) data; + + printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG, + DSPregs[DEST_REG].upper.f); + + return ARMul_DONE; + } +} + +unsigned +DSPLDC5 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type, + ARMword instr, + ARMword data) +{ + static unsigned words; + + if (type != ARMul_DATA) + { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) + { + /* It's a long access, get two words. */ + + /* cfldr64 */ + printfdbg ("cfldr64: %d\n", data); + + if (words == 0) + { + if (state->bigendSig) + DSPregs[DEST_REG].upper.i = (int) data; + else + DSPregs[DEST_REG].lower.i = (int) data; + } + else + { + if (state->bigendSig) + DSPregs[DEST_REG].lower.i = (int) data; + else + DSPregs[DEST_REG].upper.i = (int) data; + } + + ++ words; + + if (words == 2) + { + printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, + mv_getReg64int (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else + { + /* Get just one word. */ + + /* cfldr32 */ + printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); + + /* 32bit ints should be sign extended to 64bits when loaded. */ + mv_setReg64int (DEST_REG, (long long) data); + + return ARMul_DONE; + } +} + +unsigned +DSPSTC4 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type, + ARMword instr, + ARMword * data) +{ + static unsigned words; + + if (type != ARMul_DATA) + { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) + { + /* It's a long access, get two words. */ + /* cfstrd */ + printfdbg ("cfstrd\n"); + + if (words == 0) + { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].upper.i; + else + *data = (ARMword) DSPregs[DEST_REG].lower.i; + } + else + { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].lower.i; + else + *data = (ARMword) DSPregs[DEST_REG].upper.i; + } + + ++ words; + + if (words == 2) + { + printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, + mv_getRegDouble (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else + { + /* Get just one word. */ + /* cfstrs */ + printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG, + DSPregs[DEST_REG].upper.f); + + *data = (ARMword) DSPregs[DEST_REG].upper.i; + + return ARMul_DONE; + } +} + +unsigned +DSPSTC5 (ARMul_State * state ATTRIBUTE_UNUSED, + unsigned type, + ARMword instr, + ARMword * data) +{ + static unsigned words; + + if (type != ARMul_DATA) + { + words = 0; + return ARMul_DONE; + } + + if (BIT (22)) + { + /* It's a long access, store two words. */ + /* cfstr64 */ + printfdbg ("cfstr64\n"); + + if (words == 0) + { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].upper.i; + else + *data = (ARMword) DSPregs[DEST_REG].lower.i; + } + else + { + if (state->bigendSig) + *data = (ARMword) DSPregs[DEST_REG].lower.i; + else + *data = (ARMword) DSPregs[DEST_REG].upper.i; + } + + ++ words; + + if (words == 2) + { + printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, + mv_getReg64int (DEST_REG)); + + return ARMul_DONE; + } + else + return ARMul_INC; + } + else + { + /* Store just one word. */ + /* cfstr32 */ + *data = (ARMword) DSPregs[DEST_REG].lower.i; + + printfdbg ("cfstr32 MEM = %d\n", (int) *data); + + return ARMul_DONE; + } +} + +unsigned +DSPCDP4 (ARMul_State * state, + unsigned type, + ARMword instr) +{ + int opcode2; + + opcode2 = BITS (5,7); + + switch (BITS (20,21)) + { + case 0: + switch (opcode2) + { + case 0: /* cfcpys */ + printfdbg ("cfcpys mvf%d = mvf%d = %f\n", + DEST_REG, + SRC1_REG, + DSPregs[SRC1_REG].upper.f); + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f; + break; + + case 1: /* cfcpyd */ + printfdbg ("cfcpyd mvd%d = mvd%d = %g\n", + DEST_REG, + SRC1_REG, + mv_getRegDouble (SRC1_REG)); + mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)); + break; + + case 2: /* cfcvtds */ + printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n", + DEST_REG, + SRC1_REG, + (float) mv_getRegDouble (SRC1_REG)); + DSPregs[DEST_REG].upper.f = (float) mv_getRegDouble (SRC1_REG); + break; + + case 3: /* cfcvtsd */ + printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n", + DEST_REG, + SRC1_REG, + (double) DSPregs[SRC1_REG].upper.f); + mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].upper.f); + break; + + case 4: /* cfcvt32s */ + printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n", + DEST_REG, + SRC1_REG, + (float) DSPregs[SRC1_REG].lower.i); + DSPregs[DEST_REG].upper.f = (float) DSPregs[SRC1_REG].lower.i; + break; + + case 5: /* cfcvt32d */ + printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n", + DEST_REG, + SRC1_REG, + (double) DSPregs[SRC1_REG].lower.i); + mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].lower.i); + break; + + case 6: /* cfcvt64s */ + printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n", + DEST_REG, + SRC1_REG, + (float) mv_getReg64int (SRC1_REG)); + DSPregs[DEST_REG].upper.f = (float) mv_getReg64int (SRC1_REG); + break; + + case 7: /* cfcvt64d */ + printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n", + DEST_REG, + SRC1_REG, + (double) mv_getReg64int (SRC1_REG)); + mv_setRegDouble (DEST_REG, (double) mv_getReg64int (SRC1_REG)); + break; + } + break; + + case 1: + switch (opcode2) + { + case 0: /* cfmuls */ + printfdbg ("cfmuls mvf%d = mvf%d = %f\n", + DEST_REG, + SRC1_REG, + DSPregs[SRC1_REG].upper.f * DSPregs[SRC2_REG].upper.f); + + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + * DSPregs[SRC2_REG].upper.f; + break; + + case 1: /* cfmuld */ + printfdbg ("cfmuld mvd%d = mvd%d = %g\n", + DEST_REG, + SRC1_REG, + mv_getRegDouble (SRC1_REG) * mv_getRegDouble (SRC2_REG)); + + mv_setRegDouble (DEST_REG, + mv_getRegDouble (SRC1_REG) + * mv_getRegDouble (SRC2_REG)); + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + break; + + case 3: + switch (opcode2) + { + case 0: /* cfabss */ + DSPregs[DEST_REG].upper.f = (DSPregs[SRC1_REG].upper.f < 0.0F ? + -DSPregs[SRC1_REG].upper.f + : DSPregs[SRC1_REG].upper.f); + printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 1: /* cfabsd */ + mv_setRegDouble (DEST_REG, + (mv_getRegDouble (SRC1_REG) < 0.0 ? + -mv_getRegDouble (SRC1_REG) + : mv_getRegDouble (SRC1_REG))); + printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n", + DEST_REG, + SRC1_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 2: /* cfnegs */ + DSPregs[DEST_REG].upper.f = -DSPregs[SRC1_REG].upper.f; + printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 3: /* cfnegd */ + mv_setRegDouble (DEST_REG, + -mv_getRegDouble (SRC1_REG)); + printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", + DEST_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 4: /* cfadds */ + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + + DSPregs[SRC2_REG].upper.f; + printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 5: /* cfaddd */ + mv_setRegDouble (DEST_REG, + mv_getRegDouble (SRC1_REG) + + mv_getRegDouble (SRC2_REG)); + printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getRegDouble (DEST_REG)); + break; + + case 6: /* cfsubs */ + DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f + - DSPregs[SRC2_REG].upper.f; + printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].upper.f); + break; + + case 7: /* cfsubd */ + mv_setRegDouble (DEST_REG, + mv_getRegDouble (SRC1_REG) + - mv_getRegDouble (SRC2_REG)); + printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getRegDouble (DEST_REG)); + break; + } + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPCDP5 (ARMul_State * state, + unsigned type, + ARMword instr) +{ + int opcode2; + char shift; + + opcode2 = BITS (5,7); + + /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */ + shift = BITS (0, 3) | (BITS (5, 7)) << 4; + if (shift & 0x40) + shift |= 0xc0; + + switch (BITS (20,21)) + { + case 0: + /* cfsh32 */ + printfdbg ("cfsh32 %s amount=%d\n", shift < 0 ? "right" : "left", + shift); + if (shift < 0) + /* Negative shift is a right shift. */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -shift; + else + /* Positive shift is a left shift. */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i << shift; + break; + + case 1: + switch (opcode2) + { + case 0: /* cfmul32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + * DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 1: /* cfmul64 */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) + * mv_getReg64int (SRC2_REG)); + printfdbg ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 2: /* cfmac32 */ + DSPregs[DEST_REG].lower.i + += DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 3: /* cfmsc32 */ + DSPregs[DEST_REG].lower.i + -= DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i; + printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 4: /* cfcvts32 */ + /* fixme: this should round */ + DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f; + printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 5: /* cfcvtd32 */ + /* fixme: this should round */ + DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG); + printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 6: /* cftruncs32 */ + DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f; + printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 7: /* cftruncd32 */ + DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG); + printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n", + DEST_REG, + SRC1_REG, + DSPregs[DEST_REG].lower.i); + break; + } + break; + + case 2: + /* cfsh64 */ + printfdbg ("cfsh64\n"); + + if (shift < 0) + /* Negative shift is a right shift. */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) >> -shift); + else + /* Positive shift is a left shift. */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) << shift); + printfdbg ("\t%llx\n", mv_getReg64int(DEST_REG)); + break; + + case 3: + switch (opcode2) + { + case 0: /* cfabs32 */ + DSPregs[DEST_REG].lower.i = (DSPregs[SRC1_REG].lower.i < 0 + ? -DSPregs[SRC1_REG].lower.i : DSPregs[SRC1_REG].lower.i); + printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 1: /* cfabs64 */ + mv_setReg64int (DEST_REG, + (mv_getReg64int (SRC1_REG) < 0 + ? -mv_getReg64int (SRC1_REG) + : mv_getReg64int (SRC1_REG))); + printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 2: /* cfneg32 */ + DSPregs[DEST_REG].lower.i = -DSPregs[SRC1_REG].lower.i; + printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 3: /* cfneg64 */ + mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG)); + printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 4: /* cfadd32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + + DSPregs[SRC2_REG].lower.i; + printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 5: /* cfadd64 */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) + + mv_getReg64int (SRC2_REG)); + printfdbg ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + + case 6: /* cfsub32 */ + DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i + - DSPregs[SRC2_REG].lower.i; + printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + DSPregs[DEST_REG].lower.i); + break; + + case 7: /* cfsub64 */ + mv_setReg64int (DEST_REG, + mv_getReg64int (SRC1_REG) + - mv_getReg64int (SRC2_REG)); + printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n", + DEST_REG, + SRC1_REG, + SRC2_REG, + mv_getReg64int (DEST_REG)); + break; + } + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr); + cirrus_not_implemented ("unknown"); + break; + } + + return ARMul_DONE; +} + +unsigned +DSPCDP6 (ARMul_State * state, + unsigned type, + ARMword instr) +{ + int opcode2; + + opcode2 = BITS (5,7); + + switch (BITS (20,21)) + { + case 0: + /* cfmadd32 */ + cirrus_not_implemented ("cfmadd32"); + break; + + case 1: + /* cfmsub32 */ + cirrus_not_implemented ("cfmsub32"); + break; + + case 2: + /* cfmadda32 */ + cirrus_not_implemented ("cfmadda32"); + break; + + case 3: + /* cfmsuba32 */ + cirrus_not_implemented ("cfmsuba32"); + break; + + default: + fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr); + } + + return ARMul_DONE; +} + +/* Conversion functions. + + 32-bit integers are stored in the LOWER half of a 64-bit physical + register. + + Single precision floats are stored in the UPPER half of a 64-bit + physical register. */ + +static double +mv_getRegDouble (int regnum) +{ + reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i; + reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i; + return reg_conv.d; +} + +static void +mv_setRegDouble (int regnum, double val) +{ + reg_conv.d = val; + DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index]; + DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index]; +} + +static long long +mv_getReg64int (int regnum) +{ + reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i; + reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i; + return reg_conv.ll; +} + +static void +mv_setReg64int (int regnum, long long val) +{ + reg_conv.ll = val; + DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index]; + DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index]; +} + +/* Compute LSW in a double and a long long. */ + +void +mv_compute_host_endianness (ARMul_State * state) +{ + static union + { + long long ll; + long ints[2]; + long i; + double d; + float floats[2]; + float f; + } conv; + + /* Calculate where's the LSW in a 64bit int. */ + conv.ll = 45; + + if (conv.ints[0] == 0) + { + msw_int_index = 0; + lsw_int_index = 1; + } + else + { + assert (conv.ints[1] == 0); + msw_int_index = 1; + lsw_int_index = 0; + } + + /* Calculate where's the LSW in a double. */ + conv.d = 3.0; + + if (conv.ints[0] == 0) + { + msw_float_index = 0; + lsw_float_index = 1; + } + else + { + assert (conv.ints[1] == 0); + msw_float_index = 1; + lsw_float_index = 0; + } + + printfdbg ("lsw_int_index %d\n", lsw_int_index); + printfdbg ("lsw_float_index %d\n", lsw_float_index); +} -- cgit v1.1