+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * cpu-score.c: New file.
+ * elf32-score.c: New file.
+ * config.bfd: Add Score target.
+ * Makefile.am: Add Score files.
+ * Makefile.in: Regenerate.
+ * archures.c: Add Score architecture.
+ * reloc.c: Add Score relocs.
+ * targets.c: Add Score target vectors.
+ * bfd-in2.h: Regenerate.
+ * libbfd.h: Regenerate.
+ * configure.in: Add Score target.
+ * configure: Regenerate.
+
2006-09-16 Nick Clifton <nickc@redhat.com>
Pedro Alves <pedro_alves@portugalmail.pt>
cpu-powerpc.lo \
cpu-rs6000.lo \
cpu-s390.lo \
+ cpu-score.lo \
cpu-sh.lo \
cpu-sparc.lo \
cpu-tic30.lo \
cpu-powerpc.c \
cpu-rs6000.c \
cpu-s390.c \
+ cpu-score.c \
cpu-sh.c \
cpu-sparc.c \
cpu-tic30.c \
elf32-pj.lo \
elf32-ppc.lo \
elf32-s390.lo \
+ elf32-score.lo \
elf32-sh.lo \
elf32-sh-symbian.lo \
elf32-sh64.lo \
elf32-sh64.c \
elf32-sh64-com.c \
elf32-s390.c \
+ elf32-score.c \
elf32-sh.c \
elf32-sh-symbian.c \
elfxx-sparc.c \
cpu-powerpc.lo: cpu-powerpc.c $(INCDIR)/filenames.h \
$(INCDIR)/hashtab.h
cpu-rs6000.lo: cpu-rs6000.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+cpu-score.lo: cpu-score.c $(INCDIR)/filenames.h
cpu-s390.lo: cpu-s390.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
cpu-sh.lo: cpu-sh.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
$(srcdir)/../opcodes/sh-opc.h
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \
$(INCDIR)/elf/sh.h $(INCDIR)/elf/reloc-macros.h elf32-sh64.h \
$(srcdir)/../opcodes/sh64-opc.h
+elf32-score.lo: elf32-score.c $(INCDIR)/filenames.h \
+ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+ $(INCDIR)/elf/external.h $(INCDIR)/elf/score.h \
+ $(INCDIR)/elf/reloc-macros.h elf32-target.h
elf32-s390.lo: elf32-s390.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
$(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/elf/s390.h \
cpu-powerpc.lo \
cpu-rs6000.lo \
cpu-s390.lo \
+ cpu-score.lo \
cpu-sh.lo \
cpu-sparc.lo \
cpu-tic30.lo \
cpu-powerpc.c \
cpu-rs6000.c \
cpu-s390.c \
+ cpu-score.c \
cpu-sh.c \
cpu-sparc.c \
cpu-tic30.c \
elf32-pj.lo \
elf32-ppc.lo \
elf32-s390.lo \
+ elf32-score.lo \
elf32-sh.lo \
elf32-sh-symbian.lo \
elf32-sh64.lo \
elf32-sh64.c \
elf32-sh64-com.c \
elf32-s390.c \
+ elf32-score.c \
elf32-sh.c \
elf32-sh-symbian.c \
elfxx-sparc.c \
cpu-powerpc.lo: cpu-powerpc.c $(INCDIR)/filenames.h \
$(INCDIR)/hashtab.h
cpu-rs6000.lo: cpu-rs6000.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
+cpu-score.lo: cpu-score.c $(INCDIR)/filenames.h
cpu-s390.lo: cpu-s390.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
cpu-sh.lo: cpu-sh.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
$(srcdir)/../opcodes/sh-opc.h
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \
$(INCDIR)/elf/sh.h $(INCDIR)/elf/reloc-macros.h elf32-sh64.h \
$(srcdir)/../opcodes/sh64-opc.h
+elf32-score.lo: elf32-score.c $(INCDIR)/filenames.h \
+ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+ $(INCDIR)/elf/external.h $(INCDIR)/elf/score.h \
+ $(INCDIR)/elf/reloc-macros.h elf32-target.h
elf32-s390.lo: elf32-s390.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
$(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/elf/s390.h \
. bfd_arch_s390, {* IBM s390 *}
.#define bfd_mach_s390_31 31
.#define bfd_mach_s390_64 64
+. bfd_arch_score, {* Sunplus score *}
. bfd_arch_openrisc, {* OpenRISC *}
. bfd_arch_mmix, {* Donald Knuth's educational processor. *}
. bfd_arch_xstormy16,
#define bfd_powerpc_arch bfd_powerpc_archs[0]
extern const bfd_arch_info_type bfd_rs6000_arch;
extern const bfd_arch_info_type bfd_s390_arch;
+extern const bfd_arch_info_type bfd_score_arch;
extern const bfd_arch_info_type bfd_sh_arch;
extern const bfd_arch_info_type bfd_sparc_arch;
extern const bfd_arch_info_type bfd_tic30_arch;
&bfd_powerpc_arch,
&bfd_rs6000_arch,
&bfd_s390_arch,
+ &bfd_score_arch,
&bfd_sh_arch,
&bfd_sparc_arch,
&bfd_tic30_arch,
bfd_arch_s390, /* IBM s390 */
#define bfd_mach_s390_31 31
#define bfd_mach_s390_64 64
+ bfd_arch_score, /* Sunplus score */
bfd_arch_openrisc, /* OpenRISC */
bfd_arch_mmix, /* Donald Knuth's educational processor. */
bfd_arch_xstormy16,
BFD_RELOC_390_GOTPLT20,
BFD_RELOC_390_TLS_GOTIE20,
+/* Score relocations */
+ BFD_RELOC_SCORE_DUMMY1,
+
+/* Low 16 bit for load/store */
+ BFD_RELOC_SCORE_GPREL15,
+
+/* This is a 24-bit reloc with the right 1 bit assumed to be 0 */
+ BFD_RELOC_SCORE_DUMMY2,
+ BFD_RELOC_SCORE_JMP,
+
+/* This is a 19-bit reloc with the right 1 bit assumed to be 0 */
+ BFD_RELOC_SCORE_BRANCH,
+
+/* This is a 11-bit reloc with the right 1 bit assumed to be 0 */
+ BFD_RELOC_SCORE16_JMP,
+
+/* This is a 8-bit reloc with the right 1 bit assumed to be 0 */
+ BFD_RELOC_SCORE16_BRANCH,
+
+/* Undocumented Score relocs */
+ BFD_RELOC_SCORE_GOT15,
+ BFD_RELOC_SCORE_GOT_LO16,
+ BFD_RELOC_SCORE_CALL15,
+ BFD_RELOC_SCORE_DUMMY_HI16,
+
/* Scenix IP2K - 9-bit register number / data address */
BFD_RELOC_IP2K_FR9,
;;
#endif
+ score*-*-elf*)
+ targ_defvec=bfd_elf32_bigscore_vec
+ targ_selvecs=bfd_elf32_littlescore_vec
+ ;;
+
#ifdef BFD64
sh64l*-*-elf*)
targ_defvec=bfd_elf32_sh64l_vec
bfd_elf32_powerpcle_vec) tb="$tb elf32-ppc.lo elf-vxworks.lo elf32.lo $elf" ;;
bfd_elf32_powerpc_vxworks_vec) tb="$tb elf32-ppc.lo elf-vxworks.lo elf32.lo $elf" ;;
bfd_elf32_s390_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;;
+ bfd_elf32_bigscore_vec) tb="$tb elf32-score.lo elf32.lo $elf" ;;
+ bfd_elf32_littlescore_vec) tb="$tb elf32-score.lo elf32.lo $elf" ;;
# FIXME: We include cofflink.lo not because it's needed for
# bfd_elf32_sh64[l]_vec, but because we include bfd_elf32_sh[l]_vec
# which needs it but does not list it. Should be fixed in right place.
bfd_elf32_powerpcle_vec) tb="$tb elf32-ppc.lo elf-vxworks.lo elf32.lo $elf" ;;
bfd_elf32_powerpc_vxworks_vec) tb="$tb elf32-ppc.lo elf-vxworks.lo elf32.lo $elf" ;;
bfd_elf32_s390_vec) tb="$tb elf32-s390.lo elf32.lo $elf" ;;
+ bfd_elf32_bigscore_vec) tb="$tb elf32-score.lo elf32.lo $elf" ;;
+ bfd_elf32_littlescore_vec) tb="$tb elf32-score.lo elf32.lo $elf" ;;
# FIXME: We include cofflink.lo not because it's needed for
# bfd_elf32_sh64[l]_vec, but because we include bfd_elf32_sh[l]_vec
# which needs it but does not list it. Should be fixed in right place.
--- /dev/null
+/* BFD support for the score processor
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+const bfd_arch_info_type
+bfd_score_arch =
+{
+ 32, /* There's 32 bits_per_word. */
+ 32, /* There's 32 bits_per_address. */
+ 8, /* There's 8 bits_per_byte. */
+ bfd_arch_score, /* One of enum bfd_architecture, defined
+ in archures.c and provided in
+ generated header files. */
+ 0, /* Only 1 machine, but #255 for
+ historical reasons. */
+ "score", /* The arch_name. */
+ "score", /* The printable name is the same. */
+ 4, /* Section alignment power; each section
+ is aligned to (only) 2^4 bytes. */
+ TRUE, /* This is the default "machine", since
+ there's only one. */
+ bfd_default_compatible, /* A default function for testing
+ "machine" compatibility of two
+ bfd_arch_info_type. */
+ bfd_default_scan, /* Check if an bfd_arch_info_type is a
+ match. */
+ NULL /* Pointer to next bfd_arch_info_type in
+ the same family. */
+};
--- /dev/null
+/* 32-bit ELF support for S+core.
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "libiberty.h"
+#include "elf-bfd.h"
+#include "elf/score.h"
+#include "elf/common.h"
+#include "elf/internal.h"
+#include "hashtab.h"
+
+
+/* Score ELF linker hash table. */
+
+struct score_elf_link_hash_table
+{
+ /* The main hash table. */
+ struct elf_link_hash_table root;
+};
+
+/* The SCORE ELF linker needs additional information for each symbol in
+ the global hash table. */
+
+struct score_elf_link_hash_entry
+{
+ struct elf_link_hash_entry root;
+
+ /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol. */
+ unsigned int possibly_dynamic_relocs;
+
+ /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section. */
+ bfd_boolean readonly_reloc;
+
+ /* We must not create a stub for a symbol that has relocations related to
+ taking the function's address, i.e. any but R_SCORE_CALL15 ones. */
+ bfd_boolean no_fn_stub;
+
+ /* Are we forced local? This will only be set if we have converted
+ the initial global GOT entry to a local GOT entry. */
+ bfd_boolean forced_local;
+};
+
+/* Traverse a score ELF linker hash table. */
+#define score_elf_link_hash_traverse(table, func, info) \
+ (elf_link_hash_traverse \
+ (&(table)->root, \
+ (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
+ (info)))
+
+/* Get the SCORE elf linker hash table from a link_info structure. */
+#define score_elf_hash_table(info) \
+ ((struct score_elf_link_hash_table *) ((info)->hash))
+
+/* This structure is used to hold .got entries while estimating got sizes. */
+struct score_got_entry
+{
+ /* The input bfd in which the symbol is defined. */
+ bfd *abfd;
+ /* The index of the symbol, as stored in the relocation r_info, if
+ we have a local symbol; -1 otherwise. */
+ long symndx;
+ union
+ {
+ /* If abfd == NULL, an address that must be stored in the got. */
+ bfd_vma address;
+ /* If abfd != NULL && symndx != -1, the addend of the relocation
+ that should be added to the symbol value. */
+ bfd_vma addend;
+ /* If abfd != NULL && symndx == -1, the hash table entry
+ corresponding to a global symbol in the got (or, local, if
+ h->forced_local). */
+ struct score_elf_link_hash_entry *h;
+ } d;
+
+ /* The offset from the beginning of the .got section to the entry
+ corresponding to this symbol+addend. If it's a global symbol
+ whose offset is yet to be decided, it's going to be -1. */
+ long gotidx;
+};
+
+/* This structure is passed to score_elf_sort_hash_table_f when sorting
+ the dynamic symbols. */
+
+struct score_elf_hash_sort_data
+{
+ /* The symbol in the global GOT with the lowest dynamic symbol table index. */
+ struct elf_link_hash_entry *low;
+ /* The least dynamic symbol table index corresponding to a symbol with a GOT entry. */
+ long min_got_dynindx;
+ /* The greatest dynamic symbol table index corresponding to a symbol
+ with a GOT entry that is not referenced (e.g., a dynamic symbol
+ with dynamic relocations pointing to it from non-primary GOTs). */
+ long max_unref_got_dynindx;
+ /* The greatest dynamic symbol table index not corresponding to a
+ symbol without a GOT entry. */
+ long max_non_got_dynindx;
+};
+
+struct score_got_info
+{
+ /* The global symbol in the GOT with the lowest index in the dynamic
+ symbol table. */
+ struct elf_link_hash_entry *global_gotsym;
+ /* The number of global .got entries. */
+ unsigned int global_gotno;
+ /* The number of local .got entries. */
+ unsigned int local_gotno;
+ /* The number of local .got entries we have used. */
+ unsigned int assigned_gotno;
+ /* A hash table holding members of the got. */
+ struct htab *got_entries;
+ /* In multi-got links, a pointer to the next got (err, rather, most
+ of the time, it points to the previous got). */
+ struct score_got_info *next;
+};
+
+/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal. */
+struct _score_elf_section_data
+{
+ struct bfd_elf_section_data elf;
+ union
+ {
+ struct score_got_info *got_info;
+ bfd_byte *tdata;
+ }
+ u;
+};
+
+#define score_elf_section_data(sec) \
+ ((struct _score_elf_section_data *) elf_section_data (sec))
+
+/* The size of a symbol-table entry. */
+#define SCORE_ELF_SYM_SIZE(abfd) \
+ (get_elf_backend_data (abfd)->s->sizeof_sym)
+
+/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
+ from smaller values. Start with zero, widen, *then* decrement. */
+#define MINUS_ONE (((bfd_vma)0) - 1)
+#define MINUS_TWO (((bfd_vma)0) - 2)
+
+#define PDR_SIZE 32
+
+
+/* The number of local .got entries we reserve. */
+#define SCORE_RESERVED_GOTNO (2)
+#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
+
+/* The offset of $gp from the beginning of the .got section. */
+#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0)
+/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp. */
+#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff)
+
+#define SCORE_ELF_STUB_SECTION_NAME (".SCORE.stub")
+#define SCORE_FUNCTION_STUB_SIZE (16)
+
+#define STUB_LW 0xc3bcc010 /* lw r29, [r28, -0x3ff0] */
+#define STUB_MOVE 0x8363bc56 /* mv r27, r3 */
+#define STUB_LI16 0x87548000 /* ori r26, .dynsym_index */
+#define STUB_BRL 0x801dbc09 /* brl r29 */
+
+#define SCORE_ELF_GOT_SIZE(abfd) \
+ (get_elf_backend_data (abfd)->s->arch_size / 8)
+
+#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
+ (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val))
+
+/* The size of an external dynamic table entry. */
+#define SCORE_ELF_DYN_SIZE(abfd) \
+ (get_elf_backend_data (abfd)->s->sizeof_dyn)
+
+/* The size of an external REL relocation. */
+#define SCORE_ELF_REL_SIZE(abfd) \
+ (get_elf_backend_data (abfd)->s->sizeof_rel)
+
+/* The default alignment for sections, as a power of two. */
+#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\
+ (get_elf_backend_data (abfd)->s->log_file_align)
+
+#ifndef NUM_ELEM
+#define NUM_ELEM(a) (sizeof (a) / (sizeof (a)[0]))
+#endif
+
+static bfd_byte *hi16_rel_addr;
+
+/* This will be used when we sort the dynamic relocation records. */
+static bfd *reldyn_sorting_bfd;
+
+/* SCORE ELF uses two common sections. One is the usual one, and the
+ other is for small objects. All the small objects are kept
+ together, and then referenced via the gp pointer, which yields
+ faster assembler code. This is what we use for the small common
+ section. This approach is copied from ecoff.c. */
+static asection score_elf_scom_section;
+static asymbol score_elf_scom_symbol;
+static asymbol *score_elf_scom_symbol_ptr;
+
+static bfd_reloc_status_type
+score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void * data,
+ asection *input_section ATTRIBUTE_UNUSED,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ hi16_rel_addr = (bfd_byte *) data + reloc_entry->address;
+ return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+score_elf_lo16_reloc (bfd *abfd,
+ arelent *reloc_entry,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void * data,
+ asection *input_section,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ bfd_vma addend = 0, offset = 0;
+ unsigned long val;
+ unsigned long hi16_offset, hi16_value, uvalue;
+
+ hi16_value = bfd_get_32 (abfd, hi16_rel_addr);
+ hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
+ addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
+ val = reloc_entry->addend;
+ if (reloc_entry->address > input_section->size)
+ return bfd_reloc_outofrange;
+ uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
+ hi16_offset = (uvalue >> 16) << 1;
+ hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
+ bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
+ offset = (uvalue & 0xffff) << 1;
+ addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+ bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
+ return bfd_reloc_ok;
+}
+
+/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a
+ dangerous relocation. */
+
+static bfd_boolean
+score_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
+{
+ unsigned int count;
+ asymbol **sym;
+ unsigned int i;
+
+ /* If we've already figured out what GP will be, just return it. */
+ *pgp = _bfd_get_gp_value (output_bfd);
+ if (*pgp)
+ return TRUE;
+
+ count = bfd_get_symcount (output_bfd);
+ sym = bfd_get_outsymbols (output_bfd);
+
+ /* The linker script will have created a symbol named `_gp' with the
+ appropriate value. */
+ if (sym == NULL)
+ i = count;
+ else
+ {
+ for (i = 0; i < count; i++, sym++)
+ {
+ const char *name;
+
+ name = bfd_asymbol_name (*sym);
+ if (*name == '_' && strcmp (name, "_gp") == 0)
+ {
+ *pgp = bfd_asymbol_value (*sym);
+ _bfd_set_gp_value (output_bfd, *pgp);
+ break;
+ }
+ }
+ }
+
+ if (i >= count)
+ {
+ /* Only get the error once. */
+ *pgp = 4;
+ _bfd_set_gp_value (output_bfd, *pgp);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* We have to figure out the gp value, so that we can adjust the
+ symbol value correctly. We look up the symbol _gp in the output
+ BFD. If we can't find it, we're stuck. We cache it in the ELF
+ target data. We don't need to adjust the symbol value for an
+ external symbol if we are producing relocatable output. */
+
+static bfd_reloc_status_type
+score_elf_final_gp (bfd *output_bfd,
+ asymbol *symbol,
+ bfd_boolean relocatable,
+ char **error_message,
+ bfd_vma *pgp)
+{
+ if (bfd_is_und_section (symbol->section)
+ && ! relocatable)
+ {
+ *pgp = 0;
+ return bfd_reloc_undefined;
+ }
+
+ *pgp = _bfd_get_gp_value (output_bfd);
+ if (*pgp == 0
+ && (! relocatable
+ || (symbol->flags & BSF_SECTION_SYM) != 0))
+ {
+ if (relocatable)
+ {
+ /* Make up a value. */
+ *pgp = symbol->section->output_section->vma + 0x4000;
+ _bfd_set_gp_value (output_bfd, *pgp);
+ }
+ else if (!score_elf_assign_gp (output_bfd, pgp))
+ {
+ *error_message =
+ (char *) _("GP relative relocation when _gp not defined");
+ return bfd_reloc_dangerous;
+ }
+ }
+
+ return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+score_elf_gprel15_with_gp (bfd *abfd,
+ asymbol *symbol,
+ arelent *reloc_entry,
+ asection *input_section,
+ bfd_boolean relocateable,
+ void * data,
+ bfd_vma gp ATTRIBUTE_UNUSED)
+{
+ bfd_vma relocation;
+ unsigned long insn;
+
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+ if (reloc_entry->address > input_section->size)
+ return bfd_reloc_outofrange;
+
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ if (((reloc_entry->addend & 0xffffc000) != 0)
+ && ((reloc_entry->addend & 0xffffc000) != 0xffffc000))
+ return bfd_reloc_overflow;
+
+ insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
+ if (relocateable)
+ reloc_entry->address += input_section->output_offset;
+
+ return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
+ asection *input_section, bfd_boolean relocatable,
+ void *data, bfd_vma gp)
+{
+ bfd_vma relocation;
+ bfd_vma val;
+
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+
+ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ return bfd_reloc_outofrange;
+
+ /* Set val to the offset into the section or symbol. */
+ val = reloc_entry->addend;
+
+ if (reloc_entry->howto->partial_inplace)
+ val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+
+ /* Adjust val for the final section location and GP value. If we
+ are producing relocatable output, we don't want to do this for
+ an external symbol. */
+ if (! relocatable
+ || (symbol->flags & BSF_SECTION_SYM) != 0)
+ val += relocation - gp;
+
+ if (reloc_entry->howto->partial_inplace)
+ bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
+ else
+ reloc_entry->addend = val;
+
+ if (relocatable)
+ reloc_entry->address += input_section->output_offset;
+
+ return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+score_elf_gprel15_reloc (bfd *abfd,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ void * data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message)
+{
+ bfd_boolean relocateable;
+ bfd_reloc_status_type ret;
+ bfd_vma gp;
+
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+ if (output_bfd != (bfd *) NULL)
+ relocateable = TRUE;
+ else
+ {
+ relocateable = FALSE;
+ output_bfd = symbol->section->output_section->owner;
+ }
+
+ ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp);
+ if (ret != bfd_reloc_ok)
+ return ret;
+
+ return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry,
+ input_section, relocateable, data, gp);
+}
+
+/* Do a R_SCORE_GPREL32 relocation. This is a 32 bit value which must
+ become the offset from the gp register. */
+
+static bfd_reloc_status_type
+score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ void *data, asection *input_section, bfd *output_bfd,
+ char **error_message)
+{
+ bfd_boolean relocatable;
+ bfd_reloc_status_type ret;
+ bfd_vma gp;
+
+ /* R_SCORE_GPREL32 relocations are defined for local symbols only. */
+ if (output_bfd != NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && (symbol->flags & BSF_LOCAL) != 0)
+ {
+ *error_message = (char *)
+ _("32bits gp relative relocation occurs for an external symbol");
+ return bfd_reloc_outofrange;
+ }
+
+ if (output_bfd != NULL)
+ relocatable = TRUE;
+ else
+ {
+ relocatable = FALSE;
+ output_bfd = symbol->section->output_section->owner;
+ }
+
+ ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp);
+ if (ret != bfd_reloc_ok)
+ return ret;
+
+ gp = 0; /* FIXME. */
+ return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
+ relocatable, data, gp);
+}
+
+/* A howto special_function for R_SCORE_GOT15 relocations. This is just
+ like any other 16-bit relocation when applied to global symbols, but is
+ treated in the same as R_SCORE_HI16 when applied to local symbols. */
+
+static bfd_reloc_status_type
+score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ void *data, asection *input_section,
+ bfd *output_bfd, char **error_message)
+{
+ if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+ || bfd_is_und_section (bfd_get_section (symbol))
+ || bfd_is_com_section (bfd_get_section (symbol)))
+ /* The relocation is against a global symbol. */
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd,
+ error_message);
+
+ return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+}
+
+static bfd_reloc_status_type
+score_elf_got_lo16_reloc (bfd *abfd,
+ arelent *reloc_entry,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void * data,
+ asection *input_section,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ bfd_vma addend = 0, offset = 0;
+ unsigned long val;
+ unsigned long hi16_offset, hi16_value, uvalue;
+
+ hi16_value = bfd_get_32 (abfd, hi16_rel_addr);
+ hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
+ addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
+ val = reloc_entry->addend;
+ if (reloc_entry->address > input_section->size)
+ return bfd_reloc_outofrange;
+ uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
+ hi16_offset = (uvalue >> 16) & 0x7fff;
+ hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
+ bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
+ offset = (uvalue & 0xffff) << 1;
+ addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+ bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
+ return bfd_reloc_ok;
+}
+
+static reloc_howto_type elf32_score_howto_table[] =
+{
+ /* No relocation. */
+ HOWTO (R_SCORE_NONE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_NONE", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_HI16 */
+ HOWTO (R_SCORE_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_hi16_reloc, /* special_function */
+ "R_SCORE_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x37fff, /* src_mask */
+ 0x37fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_LO16 */
+ HOWTO (R_SCORE_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_lo16_reloc, /* special_function */
+ "R_SCORE_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x37fff, /* src_mask */
+ 0x37fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_DUMMY1 */
+ HOWTO (R_SCORE_DUMMY1, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_DUMMY1", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /*R_SCORE_24 */
+ HOWTO (R_SCORE_24, /* type */
+ 1, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 24, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_24", /* name */
+ FALSE, /* partial_inplace */
+ 0x3ff7fff, /* src_mask */
+ 0x3ff7fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /*R_SCORE_PC19 */
+ HOWTO (R_SCORE_PC19, /* type */
+ 1, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 19, /* bitsize */
+ TRUE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_PC19", /* name */
+ FALSE, /* partial_inplace */
+ 0x3ff03fe, /* src_mask */
+ 0x3ff03fe, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /*R_SCORE16_11 */
+ HOWTO (R_SCORE16_11, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 11, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE16_11", /* name */
+ FALSE, /* partial_inplace */
+ 0x000000ffe, /* src_mask */
+ 0x000000ffe, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE16_PC8 */
+ HOWTO (R_SCORE16_PC8, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE16_PC8", /* name */
+ FALSE, /* partial_inplace */
+ 0x000000ff, /* src_mask */
+ 0x000000ff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 32 bit absolute */
+ HOWTO (R_SCORE_ABS32, /* type 8 */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_ABS32", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 16 bit absolute */
+ HOWTO (R_SCORE_ABS16, /* type 11 */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_ABS16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_DUMMY2 */
+ HOWTO (R_SCORE_DUMMY2, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_DUMMY2", /* name */
+ TRUE, /* partial_inplace */
+ 0x00007fff, /* src_mask */
+ 0x00007fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_GP15 */
+ HOWTO (R_SCORE_GP15, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_gprel15_reloc,/* special_function */
+ "R_SCORE_GP15", /* name */
+ TRUE, /* partial_inplace */
+ 0x00007fff, /* src_mask */
+ 0x00007fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* GNU extension to record C++ vtable hierarchy. */
+ HOWTO (R_SCORE_GNU_VTINHERIT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ NULL, /* special_function */
+ "R_SCORE_GNU_VTINHERIT", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* GNU extension to record C++ vtable member usage */
+ HOWTO (R_SCORE_GNU_VTENTRY, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+ "R_SCORE_GNU_VTENTRY", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Reference to global offset table. */
+ HOWTO (R_SCORE_GOT15, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ score_elf_got15_reloc, /* special_function */
+ "R_SCORE_GOT15", /* name */
+ TRUE, /* partial_inplace */
+ 0x00007fff, /* src_mask */
+ 0x00007fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ HOWTO (R_SCORE_GOT_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_got_lo16_reloc, /* special_function */
+ "R_SCORE_GOT_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x37ffe, /* src_mask */
+ 0x37ffe, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 15 bit call through global offset table. */
+ HOWTO (R_SCORE_CALL15, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_CALL15", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 32 bit GP relative reference. */
+ HOWTO (R_SCORE_GPREL32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_gprel32_reloc, /* special_function */
+ "R_SCORE_GPREL32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* 32 bit symbol relative relocation. */
+ HOWTO (R_SCORE_REL32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SCORE_REL32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* R_SCORE_DUMMY_HI16 */
+ HOWTO (R_SCORE_DUMMY_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ score_elf_hi16_reloc, /* special_function */
+ "R_SCORE_DUMMY_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x37fff, /* src_mask */
+ 0x37fff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+};
+
+struct score_reloc_map
+{
+ bfd_reloc_code_real_type bfd_reloc_val;
+ unsigned char elf_reloc_val;
+};
+
+static const struct score_reloc_map elf32_score_reloc_map[] =
+{
+ {BFD_RELOC_NONE, R_SCORE_NONE},
+ {BFD_RELOC_HI16_S, R_SCORE_HI16},
+ {BFD_RELOC_LO16, R_SCORE_LO16},
+ {BFD_RELOC_SCORE_DUMMY1, R_SCORE_DUMMY1},
+ {BFD_RELOC_SCORE_JMP, R_SCORE_24},
+ {BFD_RELOC_SCORE_BRANCH, R_SCORE_PC19},
+ {BFD_RELOC_SCORE16_JMP, R_SCORE16_11},
+ {BFD_RELOC_SCORE16_BRANCH, R_SCORE16_PC8},
+ {BFD_RELOC_32, R_SCORE_ABS32},
+ {BFD_RELOC_16, R_SCORE_ABS16},
+ {BFD_RELOC_SCORE_DUMMY2, R_SCORE_DUMMY2},
+ {BFD_RELOC_SCORE_GPREL15, R_SCORE_GP15},
+ {BFD_RELOC_VTABLE_INHERIT, R_SCORE_GNU_VTINHERIT},
+ {BFD_RELOC_VTABLE_ENTRY, R_SCORE_GNU_VTENTRY},
+ {BFD_RELOC_SCORE_GOT15, R_SCORE_GOT15},
+ {BFD_RELOC_SCORE_GOT_LO16, R_SCORE_GOT_LO16},
+ {BFD_RELOC_SCORE_CALL15, R_SCORE_CALL15},
+ {BFD_RELOC_GPREL32, R_SCORE_GPREL32},
+ {BFD_RELOC_32_PCREL, R_SCORE_REL32},
+ {BFD_RELOC_SCORE_DUMMY_HI16, R_SCORE_DUMMY_HI16},
+};
+
+/* got_entries only match if they're identical, except for gotidx, so
+ use all fields to compute the hash, and compare the appropriate
+ union members. */
+
+static hashval_t
+score_elf_got_entry_hash (const void *entry_)
+{
+ const struct score_got_entry *entry = (struct score_got_entry *)entry_;
+
+ return entry->symndx
+ + (!entry->abfd ? entry->d.address : entry->abfd->id);
+}
+
+static int
+score_elf_got_entry_eq (const void *entry1, const void *entry2)
+{
+ const struct score_got_entry *e1 = (struct score_got_entry *)entry1;
+ const struct score_got_entry *e2 = (struct score_got_entry *)entry2;
+
+ return e1->abfd == e2->abfd && e1->symndx == e2->symndx
+ && (! e1->abfd ? e1->d.address == e2->d.address
+ : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
+ : e1->d.h == e2->d.h);
+}
+
+/* If H needs a GOT entry, assign it the highest available dynamic
+ index. Otherwise, assign it the lowest available dynamic
+ index. */
+
+static bfd_boolean
+score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data)
+{
+ struct score_elf_hash_sort_data *hsd = data;
+
+ if (h->root.root.type == bfd_link_hash_warning)
+ h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ /* Symbols without dynamic symbol table entries aren't interesting at all. */
+ if (h->root.dynindx == -1)
+ return TRUE;
+
+ /* Global symbols that need GOT entries that are not explicitly
+ referenced are marked with got offset 2. Those that are
+ referenced get a 1, and those that don't need GOT entries get
+ -1. */
+ if (h->root.got.offset == 2)
+ {
+ if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
+ hsd->low = (struct elf_link_hash_entry *) h;
+ h->root.dynindx = hsd->max_unref_got_dynindx++;
+ }
+ else if (h->root.got.offset != 1)
+ h->root.dynindx = hsd->max_non_got_dynindx++;
+ else
+ {
+ h->root.dynindx = --hsd->min_got_dynindx;
+ hsd->low = (struct elf_link_hash_entry *) h;
+ }
+
+ return TRUE;
+}
+
+static asection *
+score_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
+{
+ asection *sgot = bfd_get_section_by_name (abfd, ".got");
+
+ if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
+ return NULL;
+ return sgot;
+}
+
+/* Returns the GOT information associated with the link indicated by
+ INFO. If SGOTP is non-NULL, it is filled in with the GOT section. */
+
+static struct score_got_info *
+score_elf_got_info (bfd *abfd, asection **sgotp)
+{
+ asection *sgot;
+ struct score_got_info *g;
+
+ sgot = score_elf_got_section (abfd, TRUE);
+ BFD_ASSERT (sgot != NULL);
+ BFD_ASSERT (elf_section_data (sgot) != NULL);
+ g = score_elf_section_data (sgot)->u.got_info;
+ BFD_ASSERT (g != NULL);
+
+ if (sgotp)
+ *sgotp = sgot;
+ return g;
+}
+
+/* Sort the dynamic symbol table so that symbols that need GOT entries
+ appear towards the end. This reduces the amount of GOT space
+ required. MAX_LOCAL is used to set the number of local symbols
+ known to be in the dynamic symbol table. During
+ _bfd_score_elf_size_dynamic_sections, this value is 1. Afterward, the
+ section symbols are added and the count is higher. */
+
+static bfd_boolean
+score_elf_sort_hash_table (struct bfd_link_info *info,
+ unsigned long max_local)
+{
+ struct score_elf_hash_sort_data hsd;
+ struct score_got_info *g;
+ bfd *dynobj;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ g = score_elf_got_info (dynobj, NULL);
+
+ hsd.low = NULL;
+ hsd.max_unref_got_dynindx =
+ hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount
+ /* In the multi-got case, assigned_gotno of the master got_info
+ indicate the number of entries that aren't referenced in the
+ primary GOT, but that must have entries because there are
+ dynamic relocations that reference it. Since they aren't
+ referenced, we move them to the end of the GOT, so that they
+ don't prevent other entries that are referenced from getting
+ too large offsets. */
+ - (g->next ? g->assigned_gotno : 0);
+ hsd.max_non_got_dynindx = max_local;
+ score_elf_link_hash_traverse (((struct score_elf_link_hash_table *)
+ elf_hash_table (info)),
+ score_elf_sort_hash_table_f,
+ &hsd);
+
+ /* There should have been enough room in the symbol table to
+ accommodate both the GOT and non-GOT symbols. */
+ BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
+ BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
+ <= elf_hash_table (info)->dynsymcount);
+
+ /* Now we know which dynamic symbol has the lowest dynamic symbol
+ table index in the GOT. */
+ g->global_gotsym = hsd.low;
+
+ return TRUE;
+}
+
+/* Create an entry in an score ELF linker hash table. */
+
+static struct bfd_hash_entry *
+score_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *)entry;
+
+ /* Allocate the structure if it has not already been allocated by a subclass. */
+ if (ret == NULL)
+ ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry));
+ if (ret == NULL)
+ return (struct bfd_hash_entry *)ret;
+
+ /* Call the allocation method of the superclass. */
+ ret = ((struct score_elf_link_hash_entry *)
+ _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *)ret, table, string));
+
+ if (ret != NULL)
+ {
+ ret->possibly_dynamic_relocs = 0;
+ ret->readonly_reloc = FALSE;
+ ret->no_fn_stub = FALSE;
+ ret->forced_local = FALSE;
+ }
+
+ return (struct bfd_hash_entry *)ret;
+}
+
+/* Returns the first relocation of type r_type found, beginning with
+ RELOCATION. RELEND is one-past-the-end of the relocation table. */
+
+static const Elf_Internal_Rela *
+score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
+ const Elf_Internal_Rela *relocation,
+ const Elf_Internal_Rela *relend)
+{
+ while (relocation < relend)
+ {
+ if (ELF32_R_TYPE (relocation->r_info) == r_type)
+ return relocation;
+
+ ++relocation;
+ }
+
+ /* We didn't find it. */
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+}
+
+/* This function is called via qsort() to sort the dynamic relocation
+ entries by increasing r_symndx value. */
+
+static int
+score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2)
+{
+ Elf_Internal_Rela int_reloc1;
+ Elf_Internal_Rela int_reloc2;
+
+ bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
+ bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
+
+ return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info));
+}
+
+/* Return whether a relocation is against a local symbol. */
+
+static bfd_boolean
+score_elf_local_relocation_p (bfd *input_bfd,
+ const Elf_Internal_Rela *relocation,
+ asection **local_sections,
+ bfd_boolean check_forced)
+{
+ unsigned long r_symndx;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct score_elf_link_hash_entry *h;
+ size_t extsymoff;
+
+ r_symndx = ELF32_R_SYM (relocation->r_info);
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
+
+ if (r_symndx < extsymoff)
+ return TRUE;
+ if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
+ return TRUE;
+
+ if (check_forced)
+ {
+ /* Look up the hash table to check whether the symbol was forced local. */
+ h = (struct score_elf_link_hash_entry *)
+ elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
+ /* Find the real hash-table entry for this symbol. */
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
+ if (h->root.forced_local)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Returns the dynamic relocation section for DYNOBJ. */
+
+static asection *
+score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p)
+{
+ static const char dname[] = ".rel.dyn";
+ asection *sreloc;
+
+ sreloc = bfd_get_section_by_name (dynobj, dname);
+ if (sreloc == NULL && create_p)
+ {
+ sreloc = bfd_make_section (dynobj, dname);
+ if (sreloc == NULL
+ || ! bfd_set_section_flags (dynobj, sreloc,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || ! bfd_set_section_alignment (dynobj, sreloc, SCORE_ELF_LOG_FILE_ALIGN (dynobj)))
+ return NULL;
+ }
+
+ return sreloc;
+}
+
+static void
+score_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n)
+{
+ asection *s;
+
+ s = score_elf_rel_dyn_section (abfd, FALSE);
+ BFD_ASSERT (s != NULL);
+
+ if (s->size == 0)
+ {
+ /* Make room for a null element. */
+ s->size += SCORE_ELF_REL_SIZE (abfd);
+ ++s->reloc_count;
+ }
+ s->size += n * SCORE_ELF_REL_SIZE (abfd);
+}
+
+/* Create a rel.dyn relocation for the dynamic linker to resolve. REL
+ is the original relocation, which is now being transformed into a
+ dynamic relocation. The ADDENDP is adjusted if necessary; the
+ caller should store the result in place of the original addend. */
+
+static bfd_boolean
+score_elf_create_dynamic_relocation (bfd *output_bfd,
+ struct bfd_link_info *info,
+ const Elf_Internal_Rela *rel,
+ struct score_elf_link_hash_entry *h,
+ asection *sec, bfd_vma symbol,
+ bfd_vma *addendp, asection *input_section)
+{
+ Elf_Internal_Rela outrel[3];
+ asection *sreloc;
+ bfd *dynobj;
+ int r_type;
+ long indx;
+ bfd_boolean defined_p;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ dynobj = elf_hash_table (info)->dynobj;
+ sreloc = score_elf_rel_dyn_section (dynobj, FALSE);
+ BFD_ASSERT (sreloc != NULL);
+ BFD_ASSERT (sreloc->contents != NULL);
+ BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size);
+
+ outrel[0].r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset);
+ outrel[1].r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset);
+ outrel[2].r_offset =
+ _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset);
+
+ if (outrel[0].r_offset == MINUS_ONE)
+ /* The relocation field has been deleted. */
+ return TRUE;
+
+ if (outrel[0].r_offset == MINUS_TWO)
+ {
+ /* The relocation field has been converted into a relative value of
+ some sort. Functions like _bfd_elf_write_section_eh_frame expect
+ the field to be fully relocated, so add in the symbol's value. */
+ *addendp += symbol;
+ return TRUE;
+ }
+
+ /* We must now calculate the dynamic symbol table index to use
+ in the relocation. */
+ if (h != NULL
+ && (! info->symbolic || !h->root.def_regular)
+ /* h->root.dynindx may be -1 if this symbol was marked to
+ become local. */
+ && h->root.dynindx != -1)
+ {
+ indx = h->root.dynindx;
+ /* ??? glibc's ld.so just adds the final GOT entry to the
+ relocation field. It therefore treats relocs against
+ defined symbols in the same way as relocs against
+ undefined symbols. */
+ defined_p = FALSE;
+ }
+ else
+ {
+ if (sec != NULL && bfd_is_abs_section (sec))
+ indx = 0;
+ else if (sec == NULL || sec->owner == NULL)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ indx = elf_section_data (sec->output_section)->dynindx;
+ if (indx == 0)
+ abort ();
+ }
+
+ /* Instead of generating a relocation using the section
+ symbol, we may as well make it a fully relative
+ relocation. We want to avoid generating relocations to
+ local symbols because we used to generate them
+ incorrectly, without adding the original symbol value,
+ which is mandated by the ABI for section symbols. In
+ order to give dynamic loaders and applications time to
+ phase out the incorrect use, we refrain from emitting
+ section-relative relocations. It's not like they're
+ useful, after all. This should be a bit more efficient
+ as well. */
+ /* ??? Although this behavior is compatible with glibc's ld.so,
+ the ABI says that relocations against STN_UNDEF should have
+ a symbol value of 0. Irix rld honors this, so relocations
+ against STN_UNDEF have no effect. */
+ defined_p = TRUE;
+ }
+
+ /* If the relocation was previously an absolute relocation and
+ this symbol will not be referred to by the relocation, we must
+ adjust it by the value we give it in the dynamic symbol table.
+ Otherwise leave the job up to the dynamic linker. */
+ if (defined_p && r_type != R_SCORE_REL32)
+ *addendp += symbol;
+
+ /* The relocation is always an REL32 relocation because we don't
+ know where the shared library will wind up at load-time. */
+ outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32);
+
+ /* For strict adherence to the ABI specification, we should
+ generate a R_SCORE_64 relocation record by itself before the
+ _REL32/_64 record as well, such that the addend is read in as
+ a 64-bit value (REL32 is a 32-bit relocation, after all).
+ However, since none of the existing ELF64 SCORE dynamic
+ loaders seems to care, we don't waste space with these
+ artificial relocations. If this turns out to not be true,
+ score_elf_allocate_dynamic_relocations() should be tweaked so
+ as to make room for a pair of dynamic relocations per
+ invocation if ABI_64_P, and here we should generate an
+ additional relocation record with R_SCORE_64 by itself for a
+ NULL symbol before this relocation record. */
+ outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
+ outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
+
+ /* Adjust the output offset of the relocation to reference the
+ correct location in the output file. */
+ outrel[0].r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+ outrel[1].r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+ outrel[2].r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
+
+ /* Put the relocation back out. We have to use the special
+ relocation outputter in the 64-bit case since the 64-bit
+ relocation format is non-standard. */
+ bfd_elf32_swap_reloc_out
+ (output_bfd, &outrel[0],
+ (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+
+ /* We've now added another relocation. */
+ ++sreloc->reloc_count;
+
+ /* Make sure the output section is writable. The dynamic linker
+ will be writing to it. */
+ elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE;
+
+ return TRUE;
+}
+
+static bfd_boolean
+score_elf_create_got_section (bfd *abfd,
+ struct bfd_link_info *info,
+ bfd_boolean maybe_exclude)
+{
+ flagword flags;
+ asection *s;
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+ struct score_got_info *g;
+ bfd_size_type amt;
+
+ /* This function may be called more than once. */
+ s = score_elf_got_section (abfd, TRUE);
+ if (s)
+ {
+ if (! maybe_exclude)
+ s->flags &= ~SEC_EXCLUDE;
+ return TRUE;
+ }
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+
+ if (maybe_exclude)
+ flags |= SEC_EXCLUDE;
+
+ /* We have to use an alignment of 2**4 here because this is hardcoded
+ in the function stub generation and in the linker script. */
+ s = bfd_make_section (abfd, ".got");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags)
+ || ! bfd_set_section_alignment (abfd, s, 4))
+ return FALSE;
+
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the
+ linker script because we don't want to define the symbol if we
+ are not creating a global offset table. */
+ bh = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
+ 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->non_elf = 0;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+
+ if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+
+ amt = sizeof (struct score_got_info);
+ g = bfd_alloc (abfd, amt);
+ if (g == NULL)
+ return FALSE;
+
+ g->global_gotsym = NULL;
+ g->global_gotno = 0;
+
+ g->local_gotno = SCORE_RESERVED_GOTNO;
+ g->assigned_gotno = SCORE_RESERVED_GOTNO;
+ g->next = NULL;
+
+ g->got_entries = htab_try_create (1, score_elf_got_entry_hash,
+ score_elf_got_entry_eq, NULL);
+ if (g->got_entries == NULL)
+ return FALSE;
+ score_elf_section_data (s)->u.got_info = g;
+ score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
+
+ return TRUE;
+}
+
+/* Calculate the %high function. */
+
+static bfd_vma
+score_elf_high (bfd_vma value)
+{
+ return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff;
+}
+
+/* Create a local GOT entry for VALUE. Return the index of the entry,
+ or -1 if it could not be created. */
+
+static struct score_got_entry *
+score_elf_create_local_got_entry (bfd *abfd,
+ bfd *ibfd ATTRIBUTE_UNUSED,
+ struct score_got_info *gg,
+ asection *sgot, bfd_vma value,
+ unsigned long r_symndx ATTRIBUTE_UNUSED,
+ struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED,
+ int r_type ATTRIBUTE_UNUSED)
+{
+ struct score_got_entry entry, **loc;
+ struct score_got_info *g;
+
+ entry.abfd = NULL;
+ entry.symndx = -1;
+ entry.d.address = value;
+
+ g = gg;
+ loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT);
+ if (*loc)
+ return *loc;
+
+ entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+
+ *loc = bfd_alloc (abfd, sizeof entry);
+
+ if (! *loc)
+ return NULL;
+
+ memcpy (*loc, &entry, sizeof entry);
+
+ if (g->assigned_gotno >= g->local_gotno)
+ {
+ (*loc)->gotidx = -1;
+ /* We didn't allocate enough space in the GOT. */
+ (*_bfd_error_handler)
+ (_("not enough GOT space for local GOT entries"));
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+ }
+
+ bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx));
+
+ return *loc;
+}
+
+/* Find a GOT entry whose higher-order 16 bits are the same as those
+ for value. Return the index into the GOT for this entry. */
+
+static bfd_vma
+score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
+ bfd_vma value, bfd_boolean external)
+{
+ asection *sgot;
+ struct score_got_info *g;
+ struct score_got_entry *entry;
+
+ if (!external)
+ {
+ /* Although the ABI says that it is "the high-order 16 bits" that we
+ want, it is really the %high value. The complete value is
+ calculated with a `addiu' of a LO16 relocation, just as with a
+ HI16/LO16 pair. */
+ value = score_elf_high (value) << 16;
+ }
+
+ g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
+
+ entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL,
+ R_SCORE_GOT15);
+ if (entry)
+ return entry->gotidx;
+ else
+ return MINUS_ONE;
+}
+
+static void
+_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *entry,
+ bfd_boolean force_local)
+{
+ bfd *dynobj;
+ asection *got;
+ struct score_got_info *g;
+ struct score_elf_link_hash_entry *h;
+
+ h = (struct score_elf_link_hash_entry *) entry;
+ if (h->forced_local)
+ return;
+ h->forced_local = TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj != NULL && force_local)
+ {
+ got = score_elf_got_section (dynobj, FALSE);
+ if (got == NULL)
+ return;
+ g = score_elf_section_data (got)->u.got_info;
+
+ if (g->next)
+ {
+ struct score_got_entry e;
+ struct score_got_info *gg = g;
+
+ /* Since we're turning what used to be a global symbol into a
+ local one, bump up the number of local entries of each GOT
+ that had an entry for it. This will automatically decrease
+ the number of global entries, since global_gotno is actually
+ the upper limit of global entries. */
+ e.abfd = dynobj;
+ e.symndx = -1;
+ e.d.h = h;
+
+ for (g = g->next; g != gg; g = g->next)
+ if (htab_find (g->got_entries, &e))
+ {
+ BFD_ASSERT (g->global_gotno > 0);
+ g->local_gotno++;
+ g->global_gotno--;
+ }
+
+ /* If this was a global symbol forced into the primary GOT, we
+ no longer need an entry for it. We can't release the entry
+ at this point, but we must at least stop counting it as one
+ of the symbols that required a forced got entry. */
+ if (h->root.got.offset == 2)
+ {
+ BFD_ASSERT (gg->assigned_gotno > 0);
+ gg->assigned_gotno--;
+ }
+ }
+ else if (g->global_gotno == 0 && g->global_gotsym == NULL)
+ /* If we haven't got through GOT allocation yet, just bump up the
+ number of local entries, as this symbol won't be counted as
+ global. */
+ g->local_gotno++;
+ else if (h->root.got.offset == 1)
+ {
+ /* If we're past non-multi-GOT allocation and this symbol had
+ been marked for a global got entry, give it a local entry
+ instead. */
+ BFD_ASSERT (g->global_gotno > 0);
+ g->local_gotno++;
+ g->global_gotno--;
+ }
+ }
+
+ _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
+}
+
+/* If H is a symbol that needs a global GOT entry, but has a dynamic
+ symbol table index lower than any we've seen to date, record it for
+ posterity. */
+
+static bfd_boolean
+score_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
+ bfd *abfd,
+ struct bfd_link_info *info,
+ struct score_got_info *g)
+{
+ struct score_got_entry entry, **loc;
+
+ /* A global symbol in the GOT must also be in the dynamic symbol table. */
+ if (h->dynindx == -1)
+ {
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ _bfd_score_elf_hide_symbol (info, h, TRUE);
+ break;
+ }
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ entry.abfd = abfd;
+ entry.symndx = -1;
+ entry.d.h = (struct score_elf_link_hash_entry *)h;
+
+ loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
+
+ /* If we've already marked this entry as needing GOT space, we don't
+ need to do it again. */
+ if (*loc)
+ return TRUE;
+
+ *loc = bfd_alloc (abfd, sizeof entry);
+ if (! *loc)
+ return FALSE;
+
+ entry.gotidx = -1;
+
+ memcpy (*loc, &entry, sizeof (entry));
+
+ if (h->got.offset != MINUS_ONE)
+ return TRUE;
+
+ /* By setting this to a value other than -1, we are indicating that
+ there needs to be a GOT entry for H. Avoid using zero, as the
+ generic ELF copy_indirect_symbol tests for <= 0. */
+ h->got.offset = 1;
+
+ return TRUE;
+}
+
+/* Reserve space in G for a GOT entry containing the value of symbol
+ SYMNDX in input bfd ABDF, plus ADDEND. */
+
+static bfd_boolean
+score_elf_record_local_got_symbol (bfd *abfd,
+ long symndx,
+ bfd_vma addend,
+ struct score_got_info *g)
+{
+ struct score_got_entry entry, **loc;
+
+ entry.abfd = abfd;
+ entry.symndx = symndx;
+ entry.d.addend = addend;
+ loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
+
+ if (*loc)
+ return TRUE;
+
+ entry.gotidx = g->local_gotno++;
+
+ *loc = bfd_alloc (abfd, sizeof(entry));
+ if (! *loc)
+ return FALSE;
+
+ memcpy (*loc, &entry, sizeof (entry));
+
+ return TRUE;
+}
+
+/* Returns the GOT offset at which the indicated address can be found.
+ If there is not yet a GOT entry for this value, create one.
+ Returns -1 if no satisfactory GOT offset can be found. */
+
+static bfd_vma
+score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
+ bfd_vma value, unsigned long r_symndx,
+ struct score_elf_link_hash_entry *h, int r_type)
+{
+ asection *sgot;
+ struct score_got_info *g;
+ struct score_got_entry *entry;
+
+ g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
+
+ entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value,
+ r_symndx, h, r_type);
+ if (!entry)
+ return MINUS_ONE;
+
+ else
+ return entry->gotidx;
+}
+
+/* Returns the GOT index for the global symbol indicated by H. */
+
+static bfd_vma
+score_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h)
+{
+ bfd_vma index;
+ asection *sgot;
+ struct score_got_info *g;
+ long global_got_dynindx = 0;
+
+ g = score_elf_got_info (abfd, &sgot);
+ if (g->global_gotsym != NULL)
+ global_got_dynindx = g->global_gotsym->dynindx;
+
+ /* Once we determine the global GOT entry with the lowest dynamic
+ symbol table index, we must put all dynamic symbols with greater
+ indices into the GOT. That makes it easy to calculate the GOT
+ offset. */
+ BFD_ASSERT (h->dynindx >= global_got_dynindx);
+ index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd));
+ BFD_ASSERT (index < sgot->size);
+
+ return index;
+}
+
+/* Returns the offset for the entry at the INDEXth position in the GOT. */
+
+static bfd_vma
+score_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd,
+ bfd *input_bfd ATTRIBUTE_UNUSED, bfd_vma index)
+{
+ asection *sgot;
+ bfd_vma gp;
+ struct score_got_info *g;
+
+ g = score_elf_got_info (dynobj, &sgot);
+ gp = _bfd_get_gp_value (output_bfd);
+
+ return sgot->output_section->vma + sgot->output_offset + index - gp;
+}
+
+/* Follow indirect and warning hash entries so that each got entry
+ points to the final symbol definition. P must point to a pointer
+ to the hash table we're traversing. Since this traversal may
+ modify the hash table, we set this pointer to NULL to indicate
+ we've made a potentially-destructive change to the hash table, so
+ the traversal must be restarted. */
+static int
+score_elf_resolve_final_got_entry (void **entryp, void *p)
+{
+ struct score_got_entry *entry = (struct score_got_entry *)*entryp;
+ htab_t got_entries = *(htab_t *)p;
+
+ if (entry->abfd != NULL && entry->symndx == -1)
+ {
+ struct score_elf_link_hash_entry *h = entry->d.h;
+
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ if (entry->d.h == h)
+ return 1;
+
+ entry->d.h = h;
+
+ /* If we can't find this entry with the new bfd hash, re-insert
+ it, and get the traversal restarted. */
+ if (! htab_find (got_entries, entry))
+ {
+ htab_clear_slot (got_entries, entryp);
+ entryp = htab_find_slot (got_entries, entry, INSERT);
+ if (! *entryp)
+ *entryp = entry;
+ /* Abort the traversal, since the whole table may have
+ moved, and leave it up to the parent to restart the
+ process. */
+ *(htab_t *)p = NULL;
+ return 0;
+ }
+ /* We might want to decrement the global_gotno count, but it's
+ either too early or too late for that at this point. */
+ }
+
+ return 1;
+}
+
+/* Turn indirect got entries in a got_entries table into their final locations. */
+static void
+score_elf_resolve_final_got_entries (struct score_got_info *g)
+{
+ htab_t got_entries;
+
+ do
+ {
+ got_entries = g->got_entries;
+
+ htab_traverse (got_entries,
+ score_elf_resolve_final_got_entry,
+ &got_entries);
+ }
+ while (got_entries == NULL);
+}
+
+/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r */
+
+static void
+score_elf_add_to_rel (bfd *abfd,
+ bfd_byte *address,
+ reloc_howto_type *howto,
+ bfd_signed_vma increment)
+{
+ bfd_signed_vma addend;
+ bfd_vma contents;
+ unsigned long offset;
+ unsigned long r_type = howto->type;
+ unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
+
+ contents = bfd_get_32 (abfd, address);
+ /* Get the (signed) value from the instruction. */
+ addend = contents & howto->src_mask;
+ if (addend & ((howto->src_mask + 1) >> 1))
+ {
+ bfd_signed_vma mask;
+
+ mask = -1;
+ mask &= ~howto->src_mask;
+ addend |= mask;
+ }
+ /* Add in the increment, (which is a byte value). */
+ switch (r_type)
+ {
+ case R_SCORE_PC19:
+ offset =
+ (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff);
+ offset += increment;
+ contents =
+ (contents & ~howto->
+ src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff);
+ bfd_put_32 (abfd, contents, address);
+ break;
+ case R_SCORE_HI16:
+ break;
+ case R_SCORE_LO16:
+ hi16_addend = bfd_get_32 (abfd, address - 4);
+ hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
+ offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1;
+ offset = (hi16_offset << 16) | (offset & 0xffff);
+ uvalue = increment + offset;
+ hi16_offset = (uvalue >> 16) << 1;
+ hi16_value = (hi16_addend & (~(howto->dst_mask)))
+ | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
+ bfd_put_32 (abfd, hi16_value, address - 4);
+ offset = (uvalue & 0xffff) << 1;
+ contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+ bfd_put_32 (abfd, contents, address);
+ break;
+ case R_SCORE_24:
+ offset =
+ (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff);
+ offset += increment;
+ contents =
+ (contents & ~howto->
+ src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff);
+ bfd_put_32 (abfd, contents, address);
+ break;
+ case R_SCORE16_11:
+
+ contents = bfd_get_16 (abfd, address);
+ offset = contents & howto->src_mask;
+ offset += increment;
+ contents = (contents & ~howto->src_mask) | (offset & howto->src_mask);
+ bfd_put_16 (abfd, contents, address);
+
+ break;
+ case R_SCORE16_PC8:
+
+ contents = bfd_get_16 (abfd, address);
+ offset = (contents & howto->src_mask) + ((increment >> 1) & 0xff);
+ contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
+ bfd_put_16 (abfd, contents, address);
+
+ break;
+ default:
+ addend += increment;
+ contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask);
+ bfd_put_32 (abfd, contents, address);
+ break;
+ }
+}
+
+/* Perform a relocation as part of a final link. */
+
+static bfd_reloc_status_type
+score_elf_final_link_relocate (reloc_howto_type *howto,
+ bfd *input_bfd,
+ bfd *output_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ Elf_Internal_Rela *rel,
+ Elf_Internal_Rela *relocs,
+ bfd_vma symbol,
+ struct bfd_link_info *info,
+ asection *sym_sec,
+ const char *sym_name ATTRIBUTE_UNUSED,
+ int sym_flags ATTRIBUTE_UNUSED,
+ struct score_elf_link_hash_entry *h,
+ asection **local_sections,
+ bfd_boolean gp_disp_p)
+{
+ unsigned long r_type;
+ unsigned long r_symndx;
+ bfd_byte *hit_data = contents + rel->r_offset;
+ bfd_vma addend;
+ /* The final GP value to be used for the relocatable, executable, or
+ shared object file being produced. */
+ bfd_vma gp = MINUS_ONE;
+ /* The place (section offset or address) of the storage unit being relocated. */
+ bfd_vma rel_addr;
+ /* The value of GP used to create the relocatable object. */
+ bfd_vma gp0 = MINUS_ONE;
+ /* The offset into the global offset table at which the address of the relocation entry
+ symbol, adjusted by the addend, resides during execution. */
+ bfd_vma g = MINUS_ONE;
+ /* TRUE if the symbol referred to by this relocation is a local symbol. */
+ bfd_boolean local_p;
+ /* The eventual value we will relocate. */
+ bfd_vma value = symbol;
+ unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0;
+
+ if (elf_gp (output_bfd) == 0)
+ {
+ struct bfd_link_hash_entry *bh;
+ asection *o;
+
+ bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1);
+ if (bh != (struct bfd_link_hash_entry *)NULL && bh->type == bfd_link_hash_defined)
+ elf_gp (output_bfd) = (bh->u.def.value
+ + bh->u.def.section->output_section->vma
+ + bh->u.def.section->output_offset);
+ else if (info->relocatable)
+ {
+ bfd_vma lo = -1;
+
+ /* Find the GP-relative section with the lowest offset. */
+ for (o = output_bfd->sections; o != (asection *) NULL; o = o->next)
+ if (o->vma < lo)
+ lo = o->vma;
+ /* And calculate GP relative to that. */
+ elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd);
+ }
+ else
+ {
+ /* If the relocate_section function needs to do a reloc
+ involving the GP value, it should make a reloc_dangerous
+ callback to warn that GP is not defined. */
+ }
+ }
+
+ /* Parse the relocation. */
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+ rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
+
+ /* If the start address has been set, then set the EF_SCORE_HASENTRY
+ flag. Setting this more than once is redundant, but the cost is
+ not too high, and it keeps the code simple.
+ The test is done here, rather than somewhere else, because the
+ start address is only set just before the final link commences.
+ Note - if the user deliberately sets a start address of 0, the flag will not be set. */
+ if (bfd_get_start_address (output_bfd) != 0)
+ elf_elfheader (output_bfd)->e_flags |= EF_SCORE_HASENTRY;
+
+ if (r_type == R_SCORE_GOT15)
+ {
+ const Elf_Internal_Rela *relend;
+ const Elf_Internal_Rela *lo16_rel;
+ const struct elf_backend_data *bed;
+ bfd_vma lo_value = 0;
+
+ addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
+
+ bed = get_elf_backend_data (output_bfd);
+ relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
+ lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend);
+ if (lo16_rel != NULL)
+ {
+ lo_value = (bfd_get_32 (input_bfd, contents + lo16_rel->r_offset) >> howto->bitpos)
+ & howto->src_mask;
+ }
+ addend = (addend << 16) + lo_value;
+ }
+ else
+ {
+ addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
+ }
+
+ local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE);
+
+ /* If we haven't already determined the GOT offset, or the GP value,
+ and we're going to need it, get it now. */
+ switch (r_type)
+ {
+ case R_SCORE_CALL15:
+ case R_SCORE_GOT15:
+ if (!local_p)
+ {
+ g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
+ (struct elf_link_hash_entry *) h);
+ }
+ else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15)
+ {
+ /* There's no need to create a local GOT entry here; the
+ calculation for a local GOT15 entry does not involve G. */
+ ;
+ }
+ else
+ {
+ g = score_elf_local_got_index (output_bfd, input_bfd, info,
+ symbol + addend, r_symndx, h, r_type);
+ if (g == MINUS_ONE)
+ return bfd_reloc_outofrange;
+ }
+
+ /* Convert GOT indices to actual offsets. */
+ g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
+ output_bfd, input_bfd, g);
+ break;
+
+ case R_SCORE_HI16:
+ case R_SCORE_LO16:
+ case R_SCORE_GPREL32:
+ gp0 = _bfd_get_gp_value (input_bfd);
+ gp = _bfd_get_gp_value (output_bfd);
+ break;
+
+ case R_SCORE_GP15:
+ gp = _bfd_get_gp_value (output_bfd);
+
+ default:
+ break;
+ }
+
+ switch (r_type)
+ {
+ case R_SCORE_NONE:
+ return bfd_reloc_ok;
+
+ case R_SCORE_ABS32:
+ case R_SCORE_REL32:
+ if ((info->shared
+ || (elf_hash_table (info)->dynamic_sections_created
+ && h != NULL
+ && h->root.def_dynamic
+ && !h->root.def_regular))
+ && r_symndx != 0
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ /* If we're creating a shared library, or this relocation is against a symbol
+ in a shared library, then we can't know where the symbol will end up.
+ So, we create a relocation record in the output, and leave the job up
+ to the dynamic linker. */
+ value = addend;
+ if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h,
+ sym_sec, symbol, &value,
+ input_section))
+ return bfd_reloc_undefined;
+ }
+ else
+ {
+ if (r_type != R_SCORE_REL32)
+ value = symbol + addend;
+ else
+ value = addend;
+ }
+ value &= howto->dst_mask;
+ bfd_put_32 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_ABS16:
+ value += addend;
+ if ((long)value > 0x7fff || (long)value < -0x8000)
+ return bfd_reloc_overflow;
+ bfd_put_16 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_24:
+ addend = bfd_get_32 (input_bfd, hit_data);
+ offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff);
+ if ((offset & 0x1000000) != 0)
+ offset |= 0xfe000000;
+ value += offset;
+ addend = (addend & ~howto->src_mask)
+ | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff);
+ bfd_put_32 (input_bfd, addend, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_PC19:
+ addend = bfd_get_32 (input_bfd, hit_data);
+ offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff);
+ if ((offset & 0x80000) != 0)
+ offset |= 0xfff00000;
+ abs_value = value = value - rel_addr + offset;
+ /* exceed 20 bit : overflow. */
+ if ((abs_value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - value + 1;
+ if ((abs_value & 0xfff80000) != 0)
+ return bfd_reloc_overflow;
+ addend = (addend & ~howto->src_mask)
+ | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff);
+ bfd_put_32 (input_bfd, addend, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE16_11:
+ addend = bfd_get_16 (input_bfd, hit_data);
+ offset = addend & howto->src_mask;
+ if ((offset & 0x800) != 0) /* Offset is negative. */
+ offset |= 0xfffff000;
+ value += offset;
+ addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
+ bfd_put_16 (input_bfd, addend, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE16_PC8:
+ addend = bfd_get_16 (input_bfd, hit_data);
+ offset = (addend & howto->src_mask) << 1;
+ if ((offset & 0x100) != 0) /* Offset is negative. */
+ offset |= 0xfffffe00;
+ abs_value = value = value - rel_addr + offset;
+ /* Sign bit + exceed 9 bit. */
+ if (((value & 0xffffff00) != 0) && ((value & 0xffffff00) != 0xffffff00))
+ return bfd_reloc_overflow;
+ value >>= 1;
+ addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
+ bfd_put_16 (input_bfd, addend, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_HI16:
+ return bfd_reloc_ok;
+
+ case R_SCORE_LO16:
+ hi16_addend = bfd_get_32 (input_bfd, hit_data - 4);
+ hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
+ addend = bfd_get_32 (input_bfd, hit_data);
+ offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
+ offset = (hi16_offset << 16) | (offset & 0xffff);
+
+ if (!gp_disp_p)
+ uvalue = value + offset;
+ else
+ uvalue = offset + gp - rel_addr + 4;
+
+ hi16_offset = (uvalue >> 16) << 1;
+ hi16_value = (hi16_addend & (~(howto->dst_mask)))
+ | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
+ bfd_put_32 (input_bfd, hi16_value, hit_data - 4);
+ offset = (uvalue & 0xffff) << 1;
+ value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+ bfd_put_32 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_GP15:
+ addend = bfd_get_32 (input_bfd, hit_data);
+ offset = addend & 0x7fff;
+ if ((offset & 0x4000) == 0x4000)
+ offset |= 0xffffc000;
+ value = value + offset - gp;
+ if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000))
+ return bfd_reloc_overflow;
+ value = (addend & ~howto->src_mask) | (value & howto->src_mask);
+ bfd_put_32 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_GOT15:
+ case R_SCORE_CALL15:
+ if (local_p)
+ {
+ bfd_boolean forced;
+
+ /* The special case is when the symbol is forced to be local. We need the
+ full address in the GOT since no R_SCORE_GOT_LO16 relocation follows. */
+ forced = ! score_elf_local_relocation_p (input_bfd, rel,
+ local_sections, FALSE);
+ value = score_elf_got16_entry (output_bfd, input_bfd, info,
+ symbol + addend, forced);
+ if (value == MINUS_ONE)
+ return bfd_reloc_outofrange;
+ value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
+ output_bfd, input_bfd, value);
+ }
+ else
+ {
+ value = g;
+ }
+
+ if ((long) value > 0x3fff || (long) value < -0x4000)
+ return bfd_reloc_overflow;
+ bfd_put_16 (input_bfd, value, hit_data + 2);
+ return bfd_reloc_ok;
+
+ case R_SCORE_GPREL32:
+ value = (addend + symbol - gp);
+ value &= howto->dst_mask;
+ bfd_put_32 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_GOT_LO16:
+ addend = bfd_get_32 (input_bfd, hit_data);
+ value = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
+ value += symbol;
+ offset = (value & 0xffff) << 1;
+ value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+
+ bfd_put_32 (input_bfd, value, hit_data);
+ return bfd_reloc_ok;
+
+ case R_SCORE_DUMMY_HI16:
+ return bfd_reloc_ok;
+
+ case R_SCORE_GNU_VTINHERIT:
+ case R_SCORE_GNU_VTENTRY:
+ /* We don't do anything with these at present. */
+ return bfd_reloc_continue;
+
+ default:
+ return bfd_reloc_notsupported;
+ }
+}
+
+/* Score backend functions. */
+
+static void
+_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *bfd_reloc,
+ Elf_Internal_Rela *elf_reloc)
+{
+ unsigned int r_type;
+
+ r_type = ELF32_R_TYPE (elf_reloc->r_info);
+ if (r_type >= NUM_ELEM (elf32_score_howto_table))
+ bfd_reloc->howto = NULL;
+ else
+ bfd_reloc->howto = &elf32_score_howto_table[r_type];
+}
+
+/* Relocate an score ELF section. */
+
+static bfd_boolean
+_bfd_score_elf_relocate_section (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;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ const char *name;
+ unsigned long offset;
+ unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
+ size_t extsymoff;
+ bfd_boolean gp_disp_p = FALSE;
+
+#ifndef USE_REL
+ if (info->relocatable)
+ return TRUE;
+#endif
+
+ /* Sort dynsym. */
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ bfd_size_type dynsecsymcount = 0;
+ if (info->shared)
+ {
+ asection * p;
+ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+
+ for (p = output_bfd->sections; p ; p = p->next)
+ if ((p->flags & SEC_EXCLUDE) == 0
+ && (p->flags & SEC_ALLOC) != 0
+ && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
+ ++ dynsecsymcount;
+ }
+
+ if (!score_elf_sort_hash_table (info, dynsecsymcount + 1))
+ return FALSE;
+ }
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ int r_type;
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ struct score_elf_link_hash_entry *h;
+ bfd_vma relocation = 0;
+ bfd_reloc_status_type r;
+ arelent bfd_reloc;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ _bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel);
+ howto = bfd_reloc.howto;
+
+ if (info->relocatable)
+ {
+ /* This is a relocatable link. 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];
+ score_elf_add_to_rel (input_bfd, contents + rel->r_offset,
+ howto, (bfd_signed_vma) (sec->output_offset + sym->st_value));
+ }
+ }
+ continue;
+ }
+
+ /* This is a final link. */
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+
+ if (r_symndx < extsymoff)
+ {
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+ relocation = (sec->output_section->vma + sec->output_offset + sym->st_value);
+
+ if ((sec->flags & SEC_MERGE) && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ asection *msec;
+ bfd_vma addend, value;
+
+ switch (r_type)
+ {
+ case R_SCORE_HI16:
+ break;
+ case R_SCORE_LO16:
+ hi16_addend = bfd_get_32 (input_bfd, contents + rel->r_offset - 4);
+ hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1;
+ addend = (hi16_offset << 16) | (offset & 0xffff);
+ msec = sec;
+ addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
+ addend -= relocation;
+ addend += msec->output_section->vma + msec->output_offset;
+ uvalue = addend;
+ hi16_offset = (uvalue >> 16) << 1;
+ hi16_value = (hi16_addend & (~(howto->dst_mask)))
+ | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
+ bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4);
+ offset = (uvalue & 0xffff) << 1;
+ value = (value & (~(howto->dst_mask)))
+ | (offset & 0x7fff) | ((offset << 1) & 0x30000);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+ default:
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ /* Get the (signed) value from the instruction. */
+ addend = value & howto->src_mask;
+ if (addend & ((howto->src_mask + 1) >> 1))
+ {
+ bfd_signed_vma mask;
+
+ mask = -1;
+ mask &= ~howto->src_mask;
+ addend |= mask;
+ }
+ msec = sec;
+ addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
+ addend += msec->output_section->vma + msec->output_offset;
+ value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* For global symbols we look up the symbol in the hash-table. */
+ h = ((struct score_elf_link_hash_entry *)
+ elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
+ /* Find the real hash-table entry for this symbol. */
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ /* Record the name of this symbol, for our caller. */
+ name = h->root.root.root.string;
+
+ /* See if this is the special GP_DISP_LABEL symbol. Note that such a
+ symbol must always be a global symbol. */
+ if (strcmp (name, GP_DISP_LABEL) == 0)
+ {
+ /* Relocations against GP_DISP_LABEL are permitted only with
+ R_SCORE_HI16 and R_SCORE_LO16 relocations. */
+ if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16)
+ return bfd_reloc_notsupported;
+
+ gp_disp_p = TRUE;
+ }
+
+ /* If this symbol is defined, calculate its address. Note that
+ GP_DISP_LABEL is a magic symbol, always implicitly defined by the
+ linker, so it's inappropriate to check to see whether or not
+ its defined. */
+ else if ((h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ && h->root.root.u.def.section)
+ {
+ sec = h->root.root.u.def.section;
+ if (sec->output_section)
+ relocation = (h->root.root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
+ else
+ {
+ relocation = h->root.root.u.def.value;
+ }
+ }
+ else if (h->root.root.type == bfd_link_hash_undefweak)
+ /* We allow relocations against undefined weak symbols, giving
+ it the value zero, so that you can undefined weak functions
+ and check to see if they exist by looking at their addresses. */
+ relocation = 0;
+ else if (info->unresolved_syms_in_objects == RM_IGNORE
+ && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
+ relocation = 0;
+ else if (strcmp (name, "_DYNAMIC_LINK") == 0)
+ {
+ /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol
+ in _bfd_score_elf_create_dynamic_sections. Otherwise, we should define
+ the symbol with a value of 0. */
+ BFD_ASSERT (! info->shared);
+ BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL);
+ relocation = 0;
+ }
+ else
+ {
+ if (! ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.root.string, input_bfd,
+ input_section, rel->r_offset,
+ (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
+ || ELF_ST_VISIBILITY (h->root.other))))
+ return bfd_reloc_undefined;
+ relocation = 0;
+ }
+ }
+
+ if (h == NULL)
+ {
+ name = (bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, sym->st_name));
+ if (name == NULL || *name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
+
+ r = score_elf_final_link_relocate (howto, input_bfd, output_bfd,
+ input_section, contents, rel, relocs,
+ relocation, info, sec, name,
+ (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) :
+ ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections,
+ gp_disp_p);
+
+ if (r != bfd_reloc_ok)
+ {
+ const char *msg = (const char *)0;
+
+ switch (r)
+ {
+ case bfd_reloc_overflow:
+ /* If the overflowing reloc was to an undefined symbol,
+ we have already printed one error message and there
+ is no point complaining again. */
+ if (((!h) || (h->root.root.type != bfd_link_hash_undefined))
+ && (!((*info->callbacks->reloc_overflow)
+ (info, NULL, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset))))
+ return FALSE;
+ break;
+ case bfd_reloc_undefined:
+ if (!((*info->callbacks->undefined_symbol)
+ (info, name, input_bfd, input_section, rel->r_offset, TRUE)))
+ return FALSE;
+ break;
+
+ case bfd_reloc_outofrange:
+ msg = _("internal error: out of range error");
+ goto common_error;
+
+ case bfd_reloc_notsupported:
+ msg = _("internal error: unsupported relocation error");
+ goto common_error;
+
+ case bfd_reloc_dangerous:
+ msg = _("internal error: dangerous error");
+ goto common_error;
+
+ default:
+ msg = _("internal error: unknown error");
+ /* fall through */
+
+ common_error:
+ if (!((*info->callbacks->warning)
+ (info, msg, name, input_bfd, input_section, rel->r_offset)))
+ return FALSE;
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* Look through the relocs for a section during the first phase, and
+ allocate space in the global offset table. */
+
+static bfd_boolean
+_bfd_score_elf_check_relocs (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
+{
+ const char *name;
+ bfd *dynobj;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ struct score_got_info *g;
+ size_t extsymoff;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ asection *sgot;
+ asection *sreloc;
+ const struct elf_backend_data *bed;
+
+ if (info->relocatable)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
+
+ name = bfd_get_section_name (abfd, sec);
+
+ if (dynobj == NULL)
+ {
+ sgot = NULL;
+ g = NULL;
+ }
+ else
+ {
+ sgot = score_elf_got_section (dynobj, FALSE);
+ if (sgot == NULL)
+ g = NULL;
+ else
+ {
+ BFD_ASSERT (score_elf_section_data (sgot) != NULL);
+ g = score_elf_section_data (sgot)->u.got_info;
+ BFD_ASSERT (g != NULL);
+ }
+ }
+
+ sreloc = NULL;
+ bed = get_elf_backend_data (abfd);
+ rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+ for (rel = relocs; rel < rel_end; ++rel)
+ {
+ unsigned long r_symndx;
+ unsigned int r_type;
+ 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 < extsymoff)
+ {
+ h = NULL;
+ }
+ else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ (*_bfd_error_handler) (_("%s: Malformed reloc detected for section %s"), abfd, name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ h = sym_hashes[r_symndx - extsymoff];
+
+ /* This may be an indirect symbol created because of a version. */
+ if (h != NULL)
+ {
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *)h->root.u.i.link;
+ }
+ }
+
+ /* Some relocs require a global offset table. */
+ if (dynobj == NULL || sgot == NULL)
+ {
+ switch (r_type)
+ {
+ case R_SCORE_GOT15:
+ case R_SCORE_CALL15:
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (!score_elf_create_got_section (dynobj, info, FALSE))
+ return FALSE;
+ g = score_elf_got_info (dynobj, &sgot);
+ break;
+ case R_SCORE_ABS32:
+ case R_SCORE_REL32:
+ if (dynobj == NULL && (info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!h && (r_type == R_SCORE_GOT_LO16))
+ {
+ if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g))
+ return FALSE;
+ }
+
+ switch (r_type)
+ {
+ case R_SCORE_CALL15:
+ if (h == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%B: CALL15 reloc at 0x%lx not against global symbol"),
+ abfd, (unsigned long) rel->r_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ else
+ {
+ /* This symbol requires a global offset table entry. */
+ if (! score_elf_record_global_got_symbol (h, abfd, info, g))
+ return FALSE;
+
+ /* We need a stub, not a plt entry for the undefined function. But we record
+ it as if it needs plt. See _bfd_elf_adjust_dynamic_symbol. */
+ h->needs_plt = 1;
+ h->type = STT_FUNC;
+ }
+ break;
+ case R_SCORE_GOT15:
+ if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g))
+ return FALSE;
+ break;
+ case R_SCORE_ABS32:
+ case R_SCORE_REL32:
+ if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
+ {
+ if (sreloc == NULL)
+ {
+ sreloc = score_elf_rel_dyn_section (dynobj, TRUE);
+ if (sreloc == NULL)
+ return FALSE;
+ }
+#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
+ if (info->shared)
+ {
+ /* When creating a shared object, we must copy these reloc types into
+ the output file as R_SCORE_REL32 relocs. We make room for this reloc
+ in the .rel.dyn reloc section. */
+ score_elf_allocate_dynamic_relocations (dynobj, 1);
+ if ((sec->flags & SCORE_READONLY_SECTION)
+ == SCORE_READONLY_SECTION)
+ /* We tell the dynamic linker that there are
+ relocations against the text segment. */
+ info->flags |= DF_TEXTREL;
+ }
+ else
+ {
+ struct score_elf_link_hash_entry *hscore;
+
+ /* We only need to copy this reloc if the symbol is
+ defined in a dynamic object. */
+ hscore = (struct score_elf_link_hash_entry *)h;
+ ++hscore->possibly_dynamic_relocs;
+ if ((sec->flags & SCORE_READONLY_SECTION)
+ == SCORE_READONLY_SECTION)
+ /* We need it to tell the dynamic linker if there
+ are relocations against the text segment. */
+ hscore->readonly_reloc = TRUE;
+ }
+
+ /* Even though we don't directly need a GOT entry for this symbol,
+ a symbol must have a dynamic symbol table index greater that
+ DT_SCORE_GOTSYM if there are dynamic relocations against it. */
+ if (h != NULL)
+ {
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (! score_elf_create_got_section (dynobj, info, TRUE))
+ return FALSE;
+ g = score_elf_got_info (dynobj, &sgot);
+ if (! score_elf_record_global_got_symbol (h, abfd, info, g))
+ return FALSE;
+ }
+ }
+ break;
+
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_SCORE_GNU_VTINHERIT:
+ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return FALSE;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_SCORE_GNU_VTENTRY:
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address. */
+ switch (r_type)
+ {
+ default:
+ if (h != NULL)
+ {
+ struct score_elf_link_hash_entry *sh;
+
+ sh = (struct score_elf_link_hash_entry *) h;
+ sh->no_fn_stub = TRUE;
+ }
+ break;
+ case R_SCORE_CALL15:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_score_elf_add_symbol_hook (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *sym,
+ const char **namep ATTRIBUTE_UNUSED,
+ flagword *flagsp ATTRIBUTE_UNUSED,
+ asection **secp,
+ bfd_vma *valp)
+{
+ switch (sym->st_shndx)
+ {
+ case SHN_COMMON:
+ if (sym->st_size > elf_gp_size (abfd))
+ break;
+ /* Fall through. */
+ case SHN_SCORE_SCOMMON:
+ *secp = bfd_make_section_old_way (abfd, ".scommon");
+ (*secp)->flags |= SEC_IS_COMMON;
+ *valp = sym->st_size;
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
+{
+ elf_symbol_type *elfsym;
+
+ elfsym = (elf_symbol_type *) asym;
+ switch (elfsym->internal_elf_sym.st_shndx)
+ {
+ case SHN_COMMON:
+ if (asym->value > elf_gp_size (abfd))
+ break;
+ /* Fall through. */
+ case SHN_SCORE_SCOMMON:
+ if (score_elf_scom_section.name == NULL)
+ {
+ /* Initialize the small common section. */
+ score_elf_scom_section.name = ".scommon";
+ score_elf_scom_section.flags = SEC_IS_COMMON;
+ score_elf_scom_section.output_section = &score_elf_scom_section;
+ score_elf_scom_section.symbol = &score_elf_scom_symbol;
+ score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr;
+ score_elf_scom_symbol.name = ".scommon";
+ score_elf_scom_symbol.flags = BSF_SECTION_SYM;
+ score_elf_scom_symbol.section = &score_elf_scom_section;
+ score_elf_scom_symbol_ptr = &score_elf_scom_symbol;
+ }
+ asym->section = &score_elf_scom_section;
+ asym->value = elfsym->internal_elf_sym.st_size;
+ break;
+ }
+}
+
+static bfd_boolean
+_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *sym,
+ asection *input_sec,
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
+{
+ /* If we see a common symbol, which implies a relocatable link, then
+ if a symbol was small common in an input file, mark it as small
+ common in the output file. */
+ if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
+ sym->st_shndx = SHN_SCORE_SCOMMON;
+
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec,
+ int *retval)
+{
+ if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+ {
+ *retval = SHN_SCORE_SCOMMON;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* 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
+_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ bfd *dynobj;
+ struct score_elf_link_hash_entry *hscore;
+ asection *s;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ /* Make sure we know what is going on here. */
+ BFD_ASSERT (dynobj != NULL
+ && (h->needs_plt
+ || h->u.weakdef != NULL
+ || (h->def_dynamic && h->ref_regular && !h->def_regular)));
+
+ /* If this symbol is defined in a dynamic object, we need to copy
+ any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output
+ file. */
+ hscore = (struct score_elf_link_hash_entry *)h;
+ if (!info->relocatable
+ && hscore->possibly_dynamic_relocs != 0
+ && (h->root.type == bfd_link_hash_defweak || !h->def_regular))
+ {
+ score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs);
+ if (hscore->readonly_reloc)
+ /* We tell the dynamic linker that there are relocations
+ against the text segment. */
+ info->flags |= DF_TEXTREL;
+ }
+
+ /* For a function, create a stub, if allowed. */
+ if (!hscore->no_fn_stub && h->needs_plt)
+ {
+ if (!elf_hash_table (info)->dynamic_sections_created)
+ return TRUE;
+
+ /* If this symbol is not defined in a regular file, then set
+ the symbol to the stub location. This is required to make
+ function pointers compare as equal between the normal
+ executable and the shared library. */
+ if (!h->def_regular)
+ {
+ /* We need .stub section. */
+ s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+
+ h->root.u.def.section = s;
+ h->root.u.def.value = s->size;
+
+ /* XXX Write this stub address somewhere. */
+ h->plt.offset = s->size;
+
+ /* Make room for this stub code. */
+ s->size += SCORE_FUNCTION_STUB_SIZE;
+
+ /* The last half word of the stub will be filled with the index
+ of this symbol in .dynsym section. */
+ return TRUE;
+ }
+ }
+ else if ((h->type == STT_FUNC) && !h->needs_plt)
+ {
+ /* This will set the entry for this symbol in the GOT to 0, and
+ the dynamic linker will take care of this. */
+ h->root.u.def.value = 0;
+ return TRUE;
+ }
+
+ /* 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->u.weakdef != NULL)
+ {
+ BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
+ || h->u.weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->u.weakdef->root.u.def.section;
+ h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ return TRUE;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object which
+ is not a function. */
+ return TRUE;
+}
+
+/* This function is called after all the input files have been read,
+ and the input sections have been assigned to output sections. */
+
+static bfd_boolean
+_bfd_score_elf_always_size_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *s;
+ struct score_got_info *g;
+ int i;
+ bfd_size_type loadable_size = 0;
+ bfd_size_type local_gotno;
+ bfd *sub;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj == NULL)
+ /* Relocatable links don't have it. */
+ return TRUE;
+
+ g = score_elf_got_info (dynobj, &s);
+ if (s == NULL)
+ return TRUE;
+
+ /* Calculate the total loadable size of the output. That will give us the
+ maximum number of GOT_PAGE entries required. */
+ for (sub = info->input_bfds; sub; sub = sub->link_next)
+ {
+ asection *subsection;
+
+ for (subsection = sub->sections;
+ subsection;
+ subsection = subsection->next)
+ {
+ if ((subsection->flags & SEC_ALLOC) == 0)
+ continue;
+ loadable_size += ((subsection->size + 0xf)
+ &~ (bfd_size_type) 0xf);
+ }
+ }
+
+ /* There has to be a global GOT entry for every symbol with
+ a dynamic symbol table index of DT_SCORE_GOTSYM or
+ higher. Therefore, it make sense to put those symbols
+ that need GOT entries at the end of the symbol table. We
+ do that here. */
+ if (! score_elf_sort_hash_table (info, 1))
+ return FALSE;
+
+ if (g->global_gotsym != NULL)
+ i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
+ else
+ /* If there are no global symbols, or none requiring
+ relocations, then GLOBAL_GOTSYM will be NULL. */
+ i = 0;
+
+ /* In the worst case, we'll get one stub per dynamic symbol. */
+ loadable_size += SCORE_FUNCTION_STUB_SIZE * i;
+
+ /* Assume there are two loadable segments consisting of
+ contiguous sections. Is 5 enough? */
+ local_gotno = (loadable_size >> 16) + 5;
+
+ g->local_gotno += local_gotno;
+ s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd);
+
+ g->global_gotno = i;
+ s->size += i * SCORE_ELF_GOT_SIZE (output_bfd);
+
+ score_elf_resolve_final_got_entries (g);
+
+ if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd))
+ {
+ /* Fixme. Error message or Warning message should be issued here. */
+ }
+
+ return TRUE;
+}
+
+/* Set the sizes of the dynamic sections. */
+
+static bfd_boolean
+_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *s;
+ bfd_boolean reltext;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ 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");
+ BFD_ASSERT (s != NULL);
+ s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
+ s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
+ }
+ }
+
+ /* The check_relocs and adjust_dynamic_symbol entry points have
+ determined the sizes of the various dynamic sections. Allocate
+ memory for them. */
+ reltext = FALSE;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+
+ 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);
+
+ if (CONST_STRNEQ (name, ".rel"))
+ {
+ if (s->size == 0)
+ {
+ /* We only strip the section if the output section name
+ has the same name. Otherwise, there might be several
+ input sections for this output section. FIXME: This
+ code is probably not needed these days anyhow, since
+ the linker now does not create empty output sections. */
+ if (s->output_section != NULL
+ && strcmp (name,
+ bfd_get_section_name (s->output_section->owner,
+ s->output_section)) == 0)
+ s->flags |= SEC_EXCLUDE;
+ }
+ else
+ {
+ const char *outname;
+ asection *target;
+
+ /* If this relocation section applies to a read only
+ section, then we probably need a DT_TEXTREL entry.
+ If the relocation section is .rel.dyn, we always
+ assert a DT_TEXTREL entry rather than testing whether
+ there exists a relocation to a read only section or
+ not. */
+ outname = bfd_get_section_name (output_bfd, s->output_section);
+ target = bfd_get_section_by_name (output_bfd, outname + 4);
+ if ((target != NULL
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0)
+ reltext = TRUE;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ if (strcmp (name, ".rel.dyn") != 0)
+ s->reloc_count = 0;
+ }
+ }
+ else if (CONST_STRNEQ (name, ".got"))
+ {
+ /* _bfd_score_elf_always_size_sections() has already done
+ most of the work, but some symbols may have been mapped
+ to versions that we must now resolve in the got_entries
+ hash tables. */
+ }
+ else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0)
+ {
+ /* IRIX rld assumes that the function stub isn't at the end
+ of .text section. So put a dummy. XXX */
+ s->size += SCORE_FUNCTION_STUB_SIZE;
+ }
+ else if (! CONST_STRNEQ (name, ".init"))
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ /* Allocate memory for the section contents. */
+ s->contents = bfd_zalloc (dynobj, s->size);
+ if (s->contents == NULL && s->size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return FALSE;
+ }
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in _bfd_score_elf_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. */
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
+ return FALSE;
+
+ if (reltext)
+ info->flags |= DF_TEXTREL;
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
+ return FALSE;
+ }
+
+ if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
+ return FALSE;
+
+ if (score_elf_rel_dyn_section (dynobj, FALSE))
+ {
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
+ return FALSE;
+ }
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0))
+ return FALSE;
+
+ if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+{
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+ flagword flags;
+ asection *s;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+
+ /* ABI requests the .dynamic section to be read only. */
+ s = bfd_get_section_by_name (abfd, ".dynamic");
+ if (s != NULL)
+ {
+ if (!bfd_set_section_flags (abfd, s, flags))
+ return FALSE;
+ }
+
+ /* We need to create .got section. */
+ if (!score_elf_create_got_section (abfd, info, FALSE))
+ return FALSE;
+
+ if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE))
+ return FALSE;
+
+ /* Create .stub section. */
+ if (bfd_get_section_by_name (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL)
+ {
+ s = bfd_make_section (abfd, SCORE_ELF_STUB_SECTION_NAME);
+ if (s == NULL
+ || !bfd_set_section_flags (abfd, s, flags | SEC_CODE)
+ || !bfd_set_section_alignment (abfd, s, 2))
+
+ return FALSE;
+ }
+
+ if (!info->shared)
+ {
+ const char *name;
+
+ name = "_DYNAMIC_LINK";
+ bh = NULL;
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr,
+ (bfd_vma) 0, (const char *)NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *)bh;
+ h->non_elf = 0;
+ h->def_regular = 1;
+ h->type = STT_SECTION;
+
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bfd_boolean
+_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ bfd *dynobj;
+ asection *sgot;
+ struct score_got_info *g;
+ const char *name;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ if (h->plt.offset != MINUS_ONE)
+ {
+ asection *s;
+ bfd_byte stub[SCORE_FUNCTION_STUB_SIZE];
+
+ /* This symbol has a stub. Set it up. */
+ BFD_ASSERT (h->dynindx != -1);
+
+ s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
+ BFD_ASSERT (s != NULL);
+
+ /* FIXME: Can h->dynindex be more than 64K? */
+ if (h->dynindx & 0xffff0000)
+ return FALSE;
+
+ /* Fill the stub. */
+ bfd_put_32 (output_bfd, STUB_LW, stub);
+ bfd_put_32 (output_bfd, STUB_MOVE, stub + 4);
+ bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8);
+ bfd_put_32 (output_bfd, STUB_BRL, stub + 12);
+
+ BFD_ASSERT (h->plt.offset <= s->size);
+ memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE);
+
+ /* Mark the symbol as undefined. plt.offset != -1 occurs
+ only for the referenced symbol. */
+ sym->st_shndx = SHN_UNDEF;
+
+ /* The run-time linker uses the st_value field of the symbol
+ to reset the global offset table entry for this external
+ to its stub address when unlinking a shared object. */
+ sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset);
+ }
+
+ BFD_ASSERT (h->dynindx != -1 || h->forced_local);
+
+ sgot = score_elf_got_section (dynobj, FALSE);
+ BFD_ASSERT (sgot != NULL);
+ BFD_ASSERT (score_elf_section_data (sgot) != NULL);
+ g = score_elf_section_data (sgot)->u.got_info;
+ BFD_ASSERT (g != NULL);
+
+ /* Run through the global symbol table, creating GOT entries for all
+ the symbols that need them. */
+ if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx)
+ {
+ bfd_vma offset;
+ bfd_vma value;
+
+ value = sym->st_value;
+ offset = score_elf_global_got_index (dynobj, h);
+ bfd_put_32 (output_bfd, value, sgot->contents + offset);
+ }
+
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
+ name = h->root.root.string;
+ if (strcmp (name, "_DYNAMIC") == 0 || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
+ sym->st_shndx = SHN_ABS;
+ else if (strcmp (name, "_DYNAMIC_LINK") == 0)
+ {
+ sym->st_shndx = SHN_ABS;
+ sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ sym->st_value = 1;
+ }
+ else if (strcmp (name, GP_DISP_LABEL) == 0)
+ {
+ sym->st_shndx = SHN_ABS;
+ sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
+ sym->st_value = elf_gp (output_bfd);
+ }
+
+ return TRUE;
+}
+
+/* Finish up the dynamic sections. */
+
+static bfd_boolean
+_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
+ struct bfd_link_info *info)
+{
+ bfd *dynobj;
+ asection *sdyn;
+ asection *sgot;
+ asection *s;
+ struct score_got_info *g;
+
+ dynobj = elf_hash_table (info)->dynobj;
+
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+ sgot = score_elf_got_section (dynobj, FALSE);
+ if (sgot == NULL)
+ g = NULL;
+ else
+ {
+ BFD_ASSERT (score_elf_section_data (sgot) != NULL);
+ g = score_elf_section_data (sgot)->u.got_info;
+ BFD_ASSERT (g != NULL);
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ bfd_byte *b;
+
+ BFD_ASSERT (sdyn != NULL);
+ BFD_ASSERT (g != NULL);
+
+ for (b = sdyn->contents;
+ b < sdyn->contents + sdyn->size;
+ b += SCORE_ELF_DYN_SIZE (dynobj))
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ size_t elemsize;
+ bfd_boolean swap_out_p;
+
+ /* Read in the current dynamic entry. */
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
+
+ /* Assume that we're going to modify it and write it out. */
+ swap_out_p = TRUE;
+
+ switch (dyn.d_tag)
+ {
+ case DT_RELENT:
+ s = score_elf_rel_dyn_section (dynobj, FALSE);
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj);
+ break;
+
+ case DT_STRSZ:
+ /* Rewrite DT_STRSZ. */
+ dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
+ break;
+
+ case DT_PLTGOT:
+ name = ".got";
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->vma;
+ break;
+
+ case DT_SCORE_BASE_ADDRESS:
+ s = output_bfd->sections;
+ BFD_ASSERT (s != NULL);
+ dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff;
+ break;
+
+ case DT_SCORE_LOCAL_GOTNO:
+ dyn.d_un.d_val = g->local_gotno;
+ break;
+
+ case DT_SCORE_UNREFEXTNO:
+ /* The index into the dynamic symbol table which is the
+ entry of the first external symbol that is not
+ referenced within the same object. */
+ dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
+ break;
+
+ case DT_SCORE_GOTSYM:
+ if (g->global_gotsym)
+ {
+ dyn.d_un.d_val = g->global_gotsym->dynindx;
+ break;
+ }
+ /* In case if we don't have global got symbols we default
+ to setting DT_SCORE_GOTSYM to the same value as
+ DT_SCORE_SYMTABNO, so we just fall through. */
+
+ case DT_SCORE_SYMTABNO:
+ name = ".dynsym";
+ elemsize = SCORE_ELF_SYM_SIZE (output_bfd);
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s != NULL);
+
+ dyn.d_un.d_val = s->size / elemsize;
+ break;
+
+ case DT_SCORE_HIPAGENO:
+ dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO;
+ break;
+
+ default:
+ swap_out_p = FALSE;
+ break;
+ }
+
+ if (swap_out_p)
+ (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b);
+ }
+ }
+
+ /* The first entry of the global offset table will be filled at
+ runtime. The second entry will be used by some runtime loaders.
+ This isn't the case of IRIX rld. */
+ if (sgot != NULL && sgot->size > 0)
+ {
+ bfd_put_32 (output_bfd, 0, sgot->contents);
+ bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd));
+ }
+
+ if (sgot != NULL)
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize
+ = SCORE_ELF_GOT_SIZE (output_bfd);
+
+
+ /* We need to sort the entries of the dynamic relocation section. */
+ s = score_elf_rel_dyn_section (dynobj, FALSE);
+
+ if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd))
+ {
+ reldyn_sorting_bfd = output_bfd;
+ qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1,
+ sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs);
+ }
+
+ return TRUE;
+}
+
+/* This function set up the ELF section header for a BFD section in preparation for writing
+ it out. This is where the flags and type fields are set for unusual sections. */
+
+static bfd_boolean
+_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
+ Elf_Internal_Shdr *hdr,
+ asection *sec)
+{
+ const char *name;
+
+ name = bfd_get_section_name (abfd, sec);
+
+ if (strcmp (name, ".got") == 0
+ || strcmp (name, ".srdata") == 0
+ || strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0)
+ hdr->sh_flags |= SHF_SCORE_GPREL;
+
+ return TRUE;
+}
+
+/* This function do additional processing on the ELF section header before writing
+ it out. This is used to set the flags and type fields for some sections. */
+
+/* assign_file_positions_except_relocs() check section flag and if it is allocatable,
+ warning message will be issued. backend_fake_section is called before
+ assign_file_positions_except_relocs(); backend_section_processing after it. so, we
+ modify section flag there, but not backend_fake_section. */
+
+static bfd_boolean
+_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
+{
+ if (hdr->bfd_section != NULL)
+ {
+ const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+
+ if (strcmp (name, ".sdata") == 0)
+ {
+ hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
+ hdr->sh_type = SHT_PROGBITS;
+ }
+ else if (strcmp (name, ".sbss") == 0)
+ {
+ hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
+ hdr->sh_type = SHT_NOBITS;
+ }
+ else if (strcmp (name, ".srdata") == 0)
+ {
+ hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL;
+ hdr->sh_type = SHT_PROGBITS;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents)
+{
+ bfd_byte *to, *from, *end;
+ int i;
+
+ if (strcmp (sec->name, ".pdr") != 0)
+ return FALSE;
+
+ if (score_elf_section_data (sec)->u.tdata == NULL)
+ return FALSE;
+
+ to = contents;
+ end = contents + sec->size;
+ for (from = contents, i = 0; from < end; from += PDR_SIZE, i++)
+ {
+ if ((score_elf_section_data (sec)->u.tdata)[i] == 1)
+ continue;
+
+ if (to != from)
+ memcpy (to, from, PDR_SIZE);
+
+ to += PDR_SIZE;
+ }
+ bfd_set_section_contents (output_bfd, sec->output_section, contents,
+ (file_ptr) sec->output_offset, sec->size);
+
+ return TRUE;
+}
+
+/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old
+ indirect symbol. Process additional relocation information. */
+
+static void
+_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct score_elf_link_hash_entry *dirscore, *indscore;
+
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+
+ if (ind->root.type != bfd_link_hash_indirect)
+ return;
+
+ dirscore = (struct score_elf_link_hash_entry *) dir;
+ indscore = (struct score_elf_link_hash_entry *) ind;
+ dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs;
+
+ if (indscore->readonly_reloc)
+ dirscore->readonly_reloc = TRUE;
+
+ if (indscore->no_fn_stub)
+ dirscore->no_fn_stub = TRUE;
+}
+
+/* Remove information about discarded functions from other sections which mention them. */
+
+static bfd_boolean
+_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
+ struct bfd_link_info *info)
+{
+ asection *o;
+ bfd_boolean ret = FALSE;
+ unsigned char *tdata;
+ size_t i, skip;
+
+ o = bfd_get_section_by_name (abfd, ".pdr");
+ if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0)
+ || (o->output_section != NULL && bfd_is_abs_section (o->output_section)))
+ return FALSE;
+
+ tdata = bfd_zmalloc (o->size / PDR_SIZE);
+ if (!tdata)
+ return FALSE;
+
+ cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory);
+ if (!cookie->rels)
+ {
+ free (tdata);
+ return FALSE;
+ }
+
+ cookie->rel = cookie->rels;
+ cookie->relend = cookie->rels + o->reloc_count;
+
+ for (i = 0, skip = 0; i < o->size; i++)
+ {
+ if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
+ {
+ tdata[i] = 1;
+ skip++;
+ }
+ }
+
+ if (skip != 0)
+ {
+ score_elf_section_data (o)->u.tdata = tdata;
+ o->size -= skip * PDR_SIZE;
+ ret = TRUE;
+ }
+ else
+ free (tdata);
+
+ if (!info->keep_memory)
+ free (cookie->rels);
+
+ return ret;
+}
+
+/* Signal that discard_info() has removed the discarded relocations for this section. */
+
+static bfd_boolean
+_bfd_score_elf_ignore_discarded_relocs (asection *sec)
+{
+ if (strcmp (sec->name, ".pdr") == 0)
+ return TRUE;
+ return FALSE;
+}
+
+/* This function discover the section a particular relocation refers to.
+ Return the section that should be marked against GC for a given relocation. */
+
+static asection *
+_bfd_score_elf_gc_mark_hook (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_SCORE_GNU_VTINHERIT:
+ case R_SCORE_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;
+}
+
+/* Support for core dump NOTE sections. */
+
+static bfd_boolean
+_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ int offset;
+ unsigned int raw_size;
+
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 148: /* Linux/Score 32-bit. */
+ /* 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 = 72;
+
+ break;
+ }
+
+ /* Make a ".reg/999" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, note->descpos + offset);
+}
+
+static bfd_boolean
+_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 124: /* Linux/Score elf_prpsinfo. */
+ elf_tdata (abfd)->core_program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+ elf_tdata (abfd)->core_command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 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;
+}
+
+
+/* Score BFD functions. */
+
+static reloc_howto_type *
+elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_ELEM (elf32_score_reloc_map); i++)
+ if (elf32_score_reloc_map[i].bfd_reloc_val == code)
+ return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val];
+
+ return NULL;
+}
+
+/* Create a score elf linker hash table. */
+
+static struct bfd_link_hash_table *
+elf32_score_link_hash_table_create (bfd *abfd)
+{
+ struct score_elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct score_elf_link_hash_table);
+
+ ret = bfd_malloc (amt);
+ if (ret == NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, score_elf_link_hash_newfunc,
+ sizeof (struct score_elf_link_hash_entry)))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ return &ret->root.root;
+}
+
+static bfd_boolean
+elf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
+{
+ FILE *file = (FILE *) ptr;
+
+ BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+ /* Print normal ELF private data. */
+ _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+ /* xgettext:c-format */
+ fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+ if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC)
+ {
+ fprintf (file, _(" [pic]"));
+ }
+ if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP)
+ {
+ fprintf (file, _(" [fix dep]"));
+ }
+ fputc ('\n', file);
+
+ return TRUE;
+}
+
+static bfd_boolean
+elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ flagword in_flags;
+ flagword out_flags;
+
+ if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+ return FALSE;
+
+ in_flags = elf_elfheader (ibfd)->e_flags;
+ out_flags = elf_elfheader (obfd)->e_flags;
+
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return TRUE;
+
+ in_flags = elf_elfheader (ibfd)->e_flags;
+ out_flags = elf_elfheader (obfd)->e_flags;
+
+ if (! elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = in_flags;
+
+ 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 (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0))
+ {
+ (*_bfd_error_handler) (_("%B: warning: linking PIC files with non-PIC files"), ibfd);
+ }
+
+ /* FIXME: Maybe dependency fix compatibility should be checked here. */
+
+ return TRUE;
+}
+
+static bfd_boolean
+elf32_score_new_section_hook (bfd *abfd, asection *sec)
+{
+ struct _score_elf_section_data *sdata;
+ bfd_size_type amt = sizeof (*sdata);
+
+ sdata = bfd_zalloc (abfd, amt);
+ if (sdata == NULL)
+ return FALSE;
+ sec->used_by_bfd = sdata;
+
+ return _bfd_elf_new_section_hook (abfd, sec);
+}
+
+
+#define USE_REL 1
+#define TARGET_LITTLE_SYM bfd_elf32_littlescore_vec
+#define TARGET_LITTLE_NAME "elf32-littlescore"
+#define TARGET_BIG_SYM bfd_elf32_bigscore_vec
+#define TARGET_BIG_NAME "elf32-bigscore"
+#define ELF_ARCH bfd_arch_score
+#define ELF_MACHINE_CODE EM_SCORE
+#define ELF_MAXPAGESIZE 0x8000
+
+#define elf_info_to_howto 0
+#define elf_info_to_howto_rel _bfd_score_info_to_howto
+#define elf_backend_relocate_section _bfd_score_elf_relocate_section
+#define elf_backend_check_relocs _bfd_score_elf_check_relocs
+#define elf_backend_add_symbol_hook _bfd_score_elf_add_symbol_hook
+#define elf_backend_symbol_processing _bfd_score_elf_symbol_processing
+#define elf_backend_link_output_symbol_hook _bfd_score_elf_link_output_symbol_hook
+#define elf_backend_section_from_bfd_section _bfd_score_elf_section_from_bfd_section
+#define elf_backend_adjust_dynamic_symbol _bfd_score_elf_adjust_dynamic_symbol
+#define elf_backend_always_size_sections _bfd_score_elf_always_size_sections
+#define elf_backend_size_dynamic_sections _bfd_score_elf_size_dynamic_sections
+#define elf_backend_create_dynamic_sections _bfd_score_elf_create_dynamic_sections
+#define elf_backend_finish_dynamic_symbol _bfd_score_elf_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections _bfd_score_elf_finish_dynamic_sections
+#define elf_backend_fake_sections _bfd_score_elf_fake_sections
+#define elf_backend_section_processing _bfd_score_elf_section_processing
+#define elf_backend_write_section _bfd_score_elf_write_section
+#define elf_backend_copy_indirect_symbol _bfd_score_elf_copy_indirect_symbol
+#define elf_backend_hide_symbol _bfd_score_elf_hide_symbol
+#define elf_backend_discard_info _bfd_score_elf_discard_info
+#define elf_backend_ignore_discarded_relocs _bfd_score_elf_ignore_discarded_relocs
+#define elf_backend_gc_mark_hook _bfd_score_elf_gc_mark_hook
+#define elf_backend_grok_prstatus _bfd_score_elf_grok_prstatus
+#define elf_backend_grok_psinfo _bfd_score_elf_grok_psinfo
+#define elf_backend_can_gc_sections 1
+#define elf_backend_want_plt_sym 0
+#define elf_backend_got_header_size (4 * SCORE_RESERVED_GOTNO)
+#define elf_backend_plt_header_size 0
+#define elf_backend_collect TRUE
+#define elf_backend_type_change_ok TRUE
+
+#define bfd_elf32_bfd_reloc_type_lookup elf32_score_reloc_type_lookup
+#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create
+#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data
+#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data
+#define bfd_elf32_new_section_hook elf32_score_new_section_hook
+
+#include "elf32-target.h"
"BFD_RELOC_390_GOT20",
"BFD_RELOC_390_GOTPLT20",
"BFD_RELOC_390_TLS_GOTIE20",
+ "BFD_RELOC_SCORE_DUMMY1",
+ "BFD_RELOC_SCORE_GPREL15",
+ "BFD_RELOC_SCORE_DUMMY2",
+ "BFD_RELOC_SCORE_JMP",
+ "BFD_RELOC_SCORE_BRANCH",
+ "BFD_RELOC_SCORE16_JMP",
+ "BFD_RELOC_SCORE16_BRANCH",
+ "BFD_RELOC_SCORE_GOT15",
+ "BFD_RELOC_SCORE_GOT_LO16",
+ "BFD_RELOC_SCORE_CALL15",
+ "BFD_RELOC_SCORE_DUMMY_HI16",
"BFD_RELOC_IP2K_FR9",
"BFD_RELOC_IP2K_BANK",
"BFD_RELOC_IP2K_ADDR16CJP",
ENUMDOC
Long displacement extension.
+ENUM
+ BFD_RELOC_SCORE_DUMMY1
+ENUMDOC
+ Score relocations
+ENUM
+ BFD_RELOC_SCORE_GPREL15
+ENUMDOC
+ Low 16 bit for load/store
+ENUM
+ BFD_RELOC_SCORE_DUMMY2
+ENUMX
+ BFD_RELOC_SCORE_JMP
+ENUMDOC
+ This is a 24-bit reloc with the right 1 bit assumed to be 0
+ENUM
+ BFD_RELOC_SCORE_BRANCH
+ENUMDOC
+ This is a 19-bit reloc with the right 1 bit assumed to be 0
+ENUM
+ BFD_RELOC_SCORE16_JMP
+ENUMDOC
+ This is a 11-bit reloc with the right 1 bit assumed to be 0
+ENUM
+ BFD_RELOC_SCORE16_BRANCH
+ENUMDOC
+ This is a 8-bit reloc with the right 1 bit assumed to be 0
+ENUM
+ BFD_RELOC_SCORE_GOT15
+ENUMX
+ BFD_RELOC_SCORE_GOT_LO16
+ENUMX
+ BFD_RELOC_SCORE_CALL15
+ENUMX
+ BFD_RELOC_SCORE_DUMMY_HI16
+ENUMDOC
+ Undocumented Score relocs
+
ENUM
BFD_RELOC_IP2K_FR9
ENUMDOC
extern const bfd_target bfd_elf32_powerpcle_vec;
extern const bfd_target bfd_elf32_powerpc_vxworks_vec;
extern const bfd_target bfd_elf32_s390_vec;
+extern const bfd_target bfd_elf32_bigscore_vec;
+extern const bfd_target bfd_elf32_littlescore_vec;
extern const bfd_target bfd_elf32_sh64_vec;
extern const bfd_target bfd_elf32_sh64l_vec;
extern const bfd_target bfd_elf32_sh64lin_vec;
&bfd_elf32_powerpc_vxworks_vec,
&bfd_elf32_powerpcle_vec,
&bfd_elf32_s390_vec,
+ &bfd_elf32_bigscore_vec,
+ &bfd_elf32_littlescore_vec,
&bfd_elf32_sh_vec,
&bfd_elf32_shblin_vec,
&bfd_elf32_shl_vec,
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * readelf.c: Add support for Score binaries.
+ * Makefile.am: Update readelf's dependencies.
+ * Makefile.in: Regenerate.
+
2006-09-16 Nick Clifton <nickc@redhat.com>
Pedro Alves <pedro_alves@portugalmail.pt>
$(INCDIR)/elf/mips.h $(INCDIR)/elf/mmix.h $(INCDIR)/elf/mn10200.h \
$(INCDIR)/elf/mn10300.h $(INCDIR)/elf/mt.h $(INCDIR)/elf/msp430.h \
$(INCDIR)/elf/or32.h $(INCDIR)/elf/pj.h $(INCDIR)/elf/ppc.h \
- $(INCDIR)/elf/ppc64.h $(INCDIR)/elf/s390.h $(INCDIR)/elf/sh.h \
+ $(INCDIR)/elf/ppc64.h $(INCDIR)/elf/s390.h $(INCDIR)/elf/score.h $(INCDIR)/elf/sh.h \
$(INCDIR)/elf/sparc.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \
$(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/crx.h \
$(INCDIR)/elf/iq2000.h $(INCDIR)/elf/xtensa.h $(INCDIR)/aout/ar.h \
EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
GENCAT = @GENCAT@
GMSGFMT = @GMSGFMT@
-GREP = @GREP@
HDEFINES = @HDEFINES@
INCINTL = @INCINTL@
INSTALL_DATA = @INSTALL_DATA@
WARN_CFLAGS = @WARN_CFLAGS@
XGETTEXT = @XGETTEXT@
YACC = `if [ -f ../bison/bison ]; then echo ../bison/bison -y -L$(srcdir)/../bison/; else echo @YACC@; fi`
-YFLAGS = -d
ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__include = @am__include@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
-dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
-localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
-psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
AUTOMAKE_OPTIONS = cygnus dejagnu
SUBDIRS = doc po
tooldir = $(exec_prefix)/$(target_alias)
+YFLAGS = -d
AM_CFLAGS = $(WARN_CFLAGS)
# these two are almost the same program
$(INCDIR)/elf/mips.h $(INCDIR)/elf/mmix.h $(INCDIR)/elf/mn10200.h \
$(INCDIR)/elf/mn10300.h $(INCDIR)/elf/mt.h $(INCDIR)/elf/msp430.h \
$(INCDIR)/elf/or32.h $(INCDIR)/elf/pj.h $(INCDIR)/elf/ppc.h \
- $(INCDIR)/elf/ppc64.h $(INCDIR)/elf/s390.h $(INCDIR)/elf/sh.h \
+ $(INCDIR)/elf/ppc64.h $(INCDIR)/elf/s390.h $(INCDIR)/elf/score.h $(INCDIR)/elf/sh.h \
$(INCDIR)/elf/sparc.h $(INCDIR)/elf/v850.h $(INCDIR)/elf/vax.h \
$(INCDIR)/elf/x86-64.h $(INCDIR)/elf/xstormy16.h $(INCDIR)/elf/crx.h \
$(INCDIR)/elf/iq2000.h $(INCDIR)/elf/xtensa.h $(INCDIR)/aout/ar.h \
#include "elf/avr.h"
#include "elf/bfin.h"
#include "elf/cris.h"
+#include "elf/crx.h"
#include "elf/d10v.h"
#include "elf/d30v.h"
#include "elf/dlx.h"
#include "elf/i960.h"
#include "elf/ia64.h"
#include "elf/ip2k.h"
+#include "elf/iq2000.h"
#include "elf/m32c.h"
#include "elf/m32r.h"
#include "elf/m68k.h"
#include "elf/ppc.h"
#include "elf/ppc64.h"
#include "elf/s390.h"
+#include "elf/score.h"
#include "elf/sh.h"
#include "elf/sparc.h"
#include "elf/v850.h"
#include "elf/vax.h"
#include "elf/x86-64.h"
#include "elf/xstormy16.h"
-#include "elf/crx.h"
-#include "elf/iq2000.h"
#include "elf/xtensa.h"
#include "aout/ar.h"
case EM_CYGNUS_D10V:
case EM_MIPS:
case EM_MIPS_RS3_LE:
+ case EM_SCORE:
return FALSE;
/* Targets that use RELA relocations. */
rtype = elf_s390_reloc_type (type);
break;
+ case EM_SCORE:
+ rtype = elf_score_reloc_type (type);
+ break;
+
case EM_XSTORMY16:
rtype = elf_xstormy16_reloc_type (type);
break;
}
}
+static const char *
+get_score_dynamic_type (unsigned long type)
+{
+ switch (type)
+ {
+ case DT_SCORE_BASE_ADDRESS: return "SCORE_BASE_ADDRESS";
+ case DT_SCORE_LOCAL_GOTNO: return "SCORE_LOCAL_GOTNO";
+ case DT_SCORE_SYMTABNO: return "SCORE_SYMTABNO";
+ case DT_SCORE_GOTSYM: return "SCORE_GOTSYM";
+ case DT_SCORE_UNREFEXTNO: return "SCORE_UNREFEXTNO";
+ case DT_SCORE_HIPAGENO: return "SCORE_HIPAGENO";
+ default:
+ return NULL;
+ }
+}
+
+
static const char *
get_dynamic_type (unsigned long type)
{
case EM_ALPHA:
result = get_alpha_dynamic_type (type);
break;
+ case EM_SCORE:
+ result = get_score_dynamic_type (type);
+ break;
default:
result = NULL;
break;
case EM_X86_64: return "Advanced Micro Devices X86-64";
case EM_S390_OLD:
case EM_S390: return "IBM S/390";
+ case EM_SCORE: return "SUNPLUS S+Core";
case EM_XSTORMY16: return "Sanyo Xstormy16 CPU core";
case EM_OPENRISC:
case EM_OR32: return "OpenRISC";
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * config/tc-score.c: New file.
+ * config/tc-score.h: Newf file.
+ * configure.tgt: Add Score target.
+ * Makefile.am: Add Score files.
+ * Makefile.in: Regenerate.
+ * NEWS: Mention new target support.
+
2006-09-16 Paul Brook <paul@codesourcery.com>
* config/tc-arm.c (s_arm_unwind_movsp): Add offset argument.
pj \
ppc \
s390 \
+ score \
sh \
sh64 \
sparc \
config/tc-pj.c \
config/tc-ppc.c \
config/tc-s390.c \
+ config/tc-score.c \
config/tc-sh.c \
config/tc-sh64.c \
config/tc-sparc.c \
config/tc-pj.h \
config/tc-ppc.h \
config/tc-s390.h \
+ config/tc-score.h \
config/tc-sh.h \
config/tc-sh64.h \
config/tc-sparc.h \
$(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
struc-symbol.h dw2gencfi.h $(INCDIR)/elf/dwarf2.h $(INCDIR)/opcode/s390.h \
$(INCDIR)/elf/s390.h $(INCDIR)/elf/reloc-macros.h
+DEPTC_score_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-score.h \
+ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+ $(INCDIR)/elf/score.h $(INCDIR)/elf/reloc-macros.h \
+ dwarf2dbg.h dw2gencfi.h $(INCDIR)/elf/dwarf2.h \
+ $(INCDIR)/opcode/score-inst.h $(INCDIR)/opcode/score-datadep.h
DEPTC_sh_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sh.h \
$(INCDIR)/coff/internal.h $(INCDIR)/coff/sh.h $(INCDIR)/coff/external.h \
$(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h \
pj \
ppc \
s390 \
+ score \
sh \
sh64 \
sparc \
config/tc-pj.c \
config/tc-ppc.c \
config/tc-s390.c \
+ config/tc-score.c \
config/tc-sh.c \
config/tc-sh64.c \
config/tc-sparc.c \
config/tc-pj.h \
config/tc-ppc.h \
config/tc-s390.h \
+ config/tc-score.h \
config/tc-sh.h \
config/tc-sh64.h \
config/tc-sparc.h \
struc-symbol.h dw2gencfi.h $(INCDIR)/elf/dwarf2.h $(INCDIR)/opcode/s390.h \
$(INCDIR)/elf/s390.h $(INCDIR)/elf/reloc-macros.h
+DEPTC_score_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \
+ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \
+ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-score.h \
+ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \
+ $(INCDIR)/elf/score.h $(INCDIR)/elf/reloc-macros.h \
+ dwarf2dbg.h dw2gencfi.h $(INCDIR)/elf/dwarf2.h \
+ $(INCDIR)/opcode/score-inst.h $(INCDIR)/opcode/score-datadep.h
+
DEPTC_sh_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-sh.h \
$(INCDIR)/coff/internal.h $(INCDIR)/coff/sh.h $(INCDIR)/coff/external.h \
$(BFDDIR)/libcoff.h $(INCDIR)/bfdlink.h subsegs.h $(INCDIR)/obstack.h \
-*- text -*-
+* Add support for Score target.
* Support for the Infineon XC16X has been added by KPIT Cummins Infosystems.
--- /dev/null
+/* tc-score.c -- Assembler for Score
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by:
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS 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.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "as.h"
+#include "config.h"
+#include "subsegs.h"
+#include "safe-ctype.h"
+#include "opcode/score-inst.h"
+#include "opcode/score-datadep.h"
+#include "struc-symbol.h"
+
+#ifdef OBJ_ELF
+#include "elf/score.h"
+#include "dwarf2dbg.h"
+#endif
+
+#define GP 28
+#define PIC_CALL_REG 29
+#define MAX_LITERAL_POOL_SIZE 1024
+#define FAIL 0x80000000
+#define SUCCESS 0
+#define INSN_SIZE 4
+#define INSN16_SIZE 2
+#define RELAX_INST_NUM 3
+#define Insn_PIC 123
+
+/* For score5u : div/mul will pop warning message, mmu/alw/asw will pop error message. */
+#define BAD_ARGS _("bad arguments to instruction")
+#define BAD_PC _("r15 not allowed here")
+#define BAD_COND _("instruction is not conditional")
+#define ERR_NO_ACCUM _("acc0 expected")
+#define ERR_FOR_SCORE5U_MUL_DIV _("div / mul are reserved instructions")
+#define ERR_FOR_SCORE5U_MMU _("This architecture doesn't support mmu")
+#define ERR_FOR_SCORE5U_ATOMIC _("This architecture doesn't support atomic instruction")
+#define LONG_LABEL_LEN _("the label length is longer than 1024");
+#define BAD_SKIP_COMMA BAD_ARGS
+#define BAD_GARBAGE _("garbage following instruction");
+
+#define skip_whitespace(str) while (*(str) == ' ') ++(str)
+
+/* The name of the readonly data section. */
+#define RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
+ ? ".data" \
+ : OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
+ ? ".rdata" \
+ : OUTPUT_FLAVOR == bfd_target_coff_flavour \
+ ? ".rdata" \
+ : OUTPUT_FLAVOR == bfd_target_elf_flavour \
+ ? ".rodata" \
+ : (abort (), ""))
+
+#define RELAX_ENCODE(old, new, type, reloc1, reloc2, opt) \
+ ((relax_substateT) \
+ (((old) << 23) \
+ | ((new) << 16) \
+ | ((type) << 9) \
+ | ((reloc1) << 5) \
+ | ((reloc2) << 1) \
+ | ((opt) ? 1 : 0)))
+
+#define RELAX_OLD(i) (((i) >> 23) & 0x7f)
+#define RELAX_NEW(i) (((i) >> 16) & 0x7f)
+#define RELAX_TYPE(i) (((i) >> 9) & 0x7f)
+#define RELAX_RELOC1(i) ((valueT) ((i) >> 5) & 0xf)
+#define RELAX_RELOC2(i) ((valueT) ((i) >> 1) & 0xf)
+#define RELAX_OPT(i) ((i) & 1)
+#define RELAX_OPT_CLEAR(i) ((i) & ~1)
+
+#define SET_INSN_ERROR(s) (inst.error = (s))
+#define INSN_IS_PCE_P(s) (strstr (str, "||") != NULL)
+
+#define GET_INSN_CLASS(type) (get_insn_class_from_type (type))
+
+#define GET_INSN_SIZE(type) ((GET_INSN_CLASS (type) == INSN_CLASS_16) \
+ ? INSN16_SIZE : INSN_SIZE)
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. */
+const char comment_chars[] = "#";
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = ";";
+
+/* Chars that can be used to separate mant from exp in floating point numbers. */
+const char EXP_CHARS[] = "eE";
+const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
+
+fragS *score_fragp = 0;
+static int fix_data_dependency = 0;
+static int warn_fix_data_dependency = 1;
+static int score7 = 1;
+static int university_version = 0;
+
+static int in_my_get_expression = 0;
+
+#define USE_GLOBAL_POINTER_OPT 1
+#define SCORE_BI_ENDIAN
+
+/* Default, pop warning message when using r1. */
+static int nor1 = 1;
+
+/* Default will do instruction relax, -O0 will set g_opt = 0. */
+static unsigned int g_opt = 1;
+
+/* The size of the small data section. */
+static unsigned int g_switch_value = 8;
+
+#ifdef OBJ_ELF
+/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+symbolS *GOT_symbol;
+#endif
+static segT pdr_seg;
+
+enum score_pic_level score_pic = NO_PIC;
+
+#define INSN_NAME_LEN 16
+struct score_it
+{
+ char name[INSN_NAME_LEN];
+ unsigned long instruction;
+ unsigned long relax_inst;
+ int size;
+ int relax_size;
+ enum score_insn_type type;
+ char str[MAX_LITERAL_POOL_SIZE];
+ const char *error;
+ int bwarn;
+ char reg[INSN_NAME_LEN];
+ struct
+ {
+ bfd_reloc_code_real_type type;
+ expressionS exp;
+ int pc_rel;
+ }reloc;
+};
+struct score_it inst;
+
+typedef struct proc
+{
+ symbolS *isym;
+ unsigned long reg_mask;
+ unsigned long reg_offset;
+ unsigned long fpreg_mask;
+ unsigned long leaf;
+ unsigned long frame_offset;
+ unsigned long frame_reg;
+ unsigned long pc_reg;
+}
+procS;
+
+static procS cur_proc;
+static procS *cur_proc_ptr;
+static int numprocs;
+
+#define SCORE7_PIPELINE 7
+#define SCORE5_PIPELINE 5
+static int vector_size = SCORE7_PIPELINE;
+struct score_it dependency_vector[SCORE7_PIPELINE];
+
+/* Relax will need some padding for alignment. */
+#define RELAX_PAD_BYTE 3
+
+/* Number of littlenums required to hold an extended precision number. For md_atof. */
+#define NUM_FLOAT_VALS 8
+#define MAX_LITTLENUMS 6
+LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
+
+/* Structure for a hash table entry for a register. */
+struct reg_entry
+{
+ const char *name;
+ int number;
+};
+
+static const struct reg_entry score_rn_table[] =
+{
+ {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
+ {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
+ {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
+ {"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", 15},
+ {"r16", 16}, {"r17", 17}, {"r18", 18}, {"r19", 19},
+ {"r20", 20}, {"r21", 21}, {"r22", 22}, {"r23", 23},
+ {"r24", 24}, {"r25", 25}, {"r26", 26}, {"r27", 27},
+ {"r28", 28}, {"r29", 29}, {"r30", 30}, {"r31", 31},
+ {NULL, 0}
+};
+
+static const struct reg_entry score_srn_table[] =
+{
+ {"sr0", 0}, {"sr1", 1}, {"sr2", 2},
+ {NULL, 0}
+};
+
+static const struct reg_entry score_crn_table[] =
+{
+ {"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3},
+ {"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7},
+ {"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11},
+ {"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
+ {"cr16", 16}, {"cr17", 17}, {"cr18", 18}, {"cr19", 19},
+ {"cr20", 20}, {"cr21", 21}, {"cr22", 22}, {"cr23", 23},
+ {"cr24", 24}, {"cr25", 25}, {"cr26", 26}, {"cr27", 27},
+ {"cr28", 28}, {"cr29", 29}, {"cr30", 30}, {"cr31", 31},
+ {NULL, 0}
+};
+
+struct reg_map
+{
+ const struct reg_entry *names;
+ int max_regno;
+ struct hash_control *htab;
+ const char *expected;
+};
+
+struct reg_map all_reg_maps[] =
+{
+ {score_rn_table, 31, NULL, N_("S+core register expected")},
+ {score_srn_table, 2, NULL, N_("S+core special-register expected")},
+ {score_crn_table, 31, NULL, N_("S+core co-processor register expected")},
+};
+
+static struct hash_control *score_ops_hsh = NULL;
+
+static struct hash_control *dependency_insn_hsh = NULL;
+
+/* Enumeration matching entries in table above. */
+enum score_reg_type
+{
+ REG_TYPE_SCORE = 0,
+#define REG_TYPE_FIRST REG_TYPE_SCORE
+ REG_TYPE_SCORE_SR = 1,
+ REG_TYPE_SCORE_CR = 2,
+ REG_TYPE_MAX = 3
+};
+
+typedef struct literalS
+{
+ struct expressionS exp;
+ struct score_it *inst;
+}
+literalT;
+
+literalT literals[MAX_LITERAL_POOL_SIZE];
+
+static void do_ldst_insn (char *);
+static void do_crdcrscrsimm5 (char *);
+static void do_ldst_unalign (char *);
+static void do_ldst_atomic (char *);
+static void do_ldst_cop (char *);
+static void do_macro_li_rdi32 (char *);
+static void do_macro_la_rdi32 (char *);
+static void do_macro_rdi32hi (char *);
+static void do_macro_rdi32lo (char *);
+static void do_macro_mul_rdrsrs (char *);
+static void do_macro_ldst_label (char *);
+static void do_branch (char *);
+static void do_jump (char *);
+static void do_empty (char *);
+static void do_rdrsrs (char *);
+static void do_rdsi16 (char *);
+static void do_rdrssi14 (char *);
+static void do_sub_rdsi16 (char *);
+static void do_sub_rdi16 (char *);
+static void do_sub_rdrssi14 (char *);
+static void do_rdrsi5 (char *);
+static void do_rdrsi14 (char *);
+static void do_rdi16 (char *);
+static void do_xrsi5 (char *);
+static void do_rdrs (char *);
+static void do_rdxrs (char *);
+static void do_rsrs (char *);
+static void do_rdcrs (char *);
+static void do_rdsrs (char *);
+static void do_rd (char *);
+static void do_rs (char *);
+static void do_i15 (char *);
+static void do_xi5x (char *);
+static void do_ceinst (char *);
+static void do_cache (char *);
+static void do16_rdrs (char *);
+static void do16_rs (char *);
+static void do16_xrs (char *);
+static void do16_mv_rdrs (char *);
+static void do16_hrdrs (char *);
+static void do16_rdhrs (char *);
+static void do16_rdi4 (char *);
+static void do16_rdi5 (char *);
+static void do16_xi5 (char *);
+static void do16_ldst_insn (char *);
+static void do16_ldst_imm_insn (char *);
+static void do16_push_pop (char *);
+static void do16_branch (char *);
+static void do16_jump (char *);
+static void do_rdi16_pic (char *);
+static void do_addi_s_pic (char *);
+static void do_addi_u_pic (char *);
+static void do_lw_pic (char *);
+
+static const struct asm_opcode score_ldst_insns[] =
+{
+ {"lw", 0x20000000, 0x3e000000, 0x2008, Rd_rvalueRs_SI15, do_ldst_insn},
+ {"lw", 0x06000000, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, do_ldst_insn},
+ {"lw", 0x0e000000, 0x3e000007, 0x200a, Rd_rvalueRs_postSI12, do_ldst_insn},
+ {"lh", 0x22000000, 0x3e000000, 0x2009, Rd_rvalueRs_SI15, do_ldst_insn},
+ {"lh", 0x06000001, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, do_ldst_insn},
+ {"lh", 0x0e000001, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, do_ldst_insn},
+ {"lhu", 0x24000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, do_ldst_insn},
+ {"lhu", 0x06000002, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, do_ldst_insn},
+ {"lhu", 0x0e000002, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, do_ldst_insn},
+ {"lb", 0x26000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, do_ldst_insn},
+ {"lb", 0x06000003, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, do_ldst_insn},
+ {"lb", 0x0e000003, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, do_ldst_insn},
+ {"sw", 0x28000000, 0x3e000000, 0x200c, Rd_lvalueRs_SI15, do_ldst_insn},
+ {"sw", 0x06000004, 0x3e000007, 0x200e, Rd_lvalueRs_preSI12, do_ldst_insn},
+ {"sw", 0x0e000004, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, do_ldst_insn},
+ {"sh", 0x2a000000, 0x3e000000, 0x200d, Rd_lvalueRs_SI15, do_ldst_insn},
+ {"sh", 0x06000005, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, do_ldst_insn},
+ {"sh", 0x0e000005, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, do_ldst_insn},
+ {"lbu", 0x2c000000, 0x3e000000, 0x200b, Rd_rvalueRs_SI15, do_ldst_insn},
+ {"lbu", 0x06000006, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, do_ldst_insn},
+ {"lbu", 0x0e000006, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, do_ldst_insn},
+ {"sb", 0x2e000000, 0x3e000000, 0x200f, Rd_lvalueRs_SI15, do_ldst_insn},
+ {"sb", 0x06000007, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, do_ldst_insn},
+ {"sb", 0x0e000007, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, do_ldst_insn},
+};
+
+static const struct asm_opcode score_insns[] =
+{
+ {"abs", 0x3800000a, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"abs.s", 0x3800004b, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"add", 0x00000010, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"add.c", 0x00000011, 0x3e0003ff, 0x2000, Rd_Rs_Rs, do_rdrsrs},
+ {"add.s", 0x38000048, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"addc", 0x00000012, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"addc.c", 0x00000013, 0x3e0003ff, 0x0009, Rd_Rs_Rs, do_rdrsrs},
+ {"addi", 0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, do_rdsi16},
+ {"addi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, do_rdsi16},
+ {"addis", 0x0a000000, 0x3e0e0001, 0x8000, Rd_SI16, do_rdi16},
+ {"addis.c", 0x0a000001, 0x3e0e0001, 0x8000, Rd_SI16, do_rdi16},
+ {"addri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, do_rdrssi14},
+ {"addri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, do_rdrssi14},
+ {"addc!", 0x0009, 0x700f, 0x00000013, Rd_Rs, do16_rdrs},
+ {"add!", 0x2000, 0x700f, 0x00000011, Rd_Rs, do16_rdrs},
+ {"addei!", 0x6000 , 0x7087, 0x02000001, Rd_I4, do16_rdi4},
+ {"subi", 0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, do_sub_rdsi16},
+ {"subi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, do_sub_rdsi16},
+ {"subis", 0x0a000000, 0x3e0e0001, 0x8000, Rd_SI16, do_sub_rdi16},
+ {"subis.c", 0x0a000001, 0x3e0e0001, 0x8000, Rd_SI16, do_sub_rdi16},
+ {"subri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, do_sub_rdrssi14},
+ {"subri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, do_sub_rdrssi14},
+ {"and", 0x00000020, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"and.c", 0x00000021, 0x3e0003ff, 0x2004, Rd_Rs_Rs, do_rdrsrs},
+ {"andi", 0x02080000, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"andi.c", 0x02080001, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"andis", 0x0a080000, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"andis.c", 0x0a080001, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"andri", 0x18000000, 0x3e000001, 0x8000, Rd_Rs_I14, do_rdrsi14},
+ {"andri.c", 0x18000001, 0x3e000001, 0x8000, Rd_Rs_I14, do_rdrsi14},
+ {"and!", 0x2004, 0x700f, 0x00000021, Rd_Rs, do16_rdrs},
+ {"bcs", 0x08000000, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bcc", 0x08000400, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bcnz", 0x08003800, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bcsl", 0x08000001, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bccl", 0x08000401, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bcnzl", 0x08003801, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bcs!", 0x4000, 0x7f00, 0x08000000, PC_DISP8div2, do16_branch},
+ {"bcc!", 0x4100, 0x7f00, 0x08000400, PC_DISP8div2, do16_branch},
+ {"bcnz!", 0x4e00, 0x7f00, 0x08003800, PC_DISP8div2, do16_branch},
+ {"beq", 0x08001000, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"beql", 0x08001001, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"beq!", 0x4400, 0x7f00, 0x08001000, PC_DISP8div2, do16_branch},
+ {"bgtu", 0x08000800, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bgt", 0x08001800, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bge", 0x08002000, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bgtul", 0x08000801, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bgtl", 0x08001801, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bgel", 0x08002001, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bgtu!", 0x4200, 0x7f00, 0x08000800, PC_DISP8div2, do16_branch},
+ {"bgt!", 0x4600, 0x7f00, 0x08001800, PC_DISP8div2, do16_branch},
+ {"bge!", 0x4800, 0x7f00, 0x08002000, PC_DISP8div2, do16_branch},
+ {"bitclr.c", 0x00000029, 0x3e0003ff, 0x6004, Rd_Rs_I5, do_rdrsi5},
+ {"bitrev", 0x3800000c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"bitset.c", 0x0000002b, 0x3e0003ff, 0x6005, Rd_Rs_I5, do_rdrsi5},
+ {"bittst.c", 0x0000002d, 0x3e0003ff, 0x6006, x_Rs_I5, do_xrsi5},
+ {"bittgl.c", 0x0000002f, 0x3e0003ff, 0x6007, Rd_Rs_I5, do_rdrsi5},
+ {"bitclr!", 0x6004, 0x7007, 0x00000029, Rd_I5, do16_rdi5},
+ {"bitset!", 0x6005, 0x7007, 0x0000002b, Rd_I5, do16_rdi5},
+ {"bittst!", 0x6006, 0x7007, 0x0000002d, Rd_I5, do16_rdi5},
+ {"bittgl!", 0x6007, 0x7007, 0x0000002f, Rd_I5, do16_rdi5},
+ {"bleu", 0x08000c00, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"ble", 0x08001c00, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"blt", 0x08002400, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bleul", 0x08000c01, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"blel", 0x08001c01, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bltl", 0x08002401, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bl", 0x08003c01, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bleu!", 0x4300, 0x7f00, 0x08000c00, PC_DISP8div2, do16_branch},
+ {"ble!", 0x4700, 0x7f00, 0x08001c00, PC_DISP8div2, do16_branch},
+ {"blt!", 0x4900, 0x7f00, 0x08002400, PC_DISP8div2, do16_branch},
+ {"bmi", 0x08002800, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bmil", 0x08002801, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bmi!", 0x00004a00, 0x00007f00, 0x08002800, PC_DISP8div2, do16_branch},
+ {"bne", 0x08001400, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bnel", 0x08001401, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bne!", 0x4500, 0x7f00, 0x08001400, PC_DISP8div2, do16_branch},
+ {"bpl", 0x08002c00, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bpll", 0x08002c01, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bpl!", 0x4b00, 0x7f00, 0x08002c00, PC_DISP8div2, do16_branch},
+ {"brcs", 0x00000008, 0x3e007fff, 0x0004, x_Rs_x, do_rs},
+ {"brcc", 0x00000408, 0x3e007fff, 0x0104, x_Rs_x, do_rs},
+ {"brgtu", 0x00000808, 0x3e007fff, 0x0204, x_Rs_x, do_rs},
+ {"brleu", 0x00000c08, 0x3e007fff, 0x0304, x_Rs_x, do_rs},
+ {"breq", 0x00001008, 0x3e007fff, 0x0404, x_Rs_x, do_rs},
+ {"brne", 0x00001408, 0x3e007fff, 0x0504, x_Rs_x, do_rs},
+ {"brgt", 0x00001808, 0x3e007fff, 0x0604, x_Rs_x, do_rs},
+ {"brle", 0x00001c08, 0x3e007fff, 0x0704, x_Rs_x, do_rs},
+ {"brge", 0x00002008, 0x3e007fff, 0x0804, x_Rs_x, do_rs},
+ {"brlt", 0x00002408, 0x3e007fff, 0x0904, x_Rs_x, do_rs},
+ {"brmi", 0x00002808, 0x3e007fff, 0x0a04, x_Rs_x, do_rs},
+ {"brpl", 0x00002c08, 0x3e007fff, 0x0b04, x_Rs_x, do_rs},
+ {"brvs", 0x00003008, 0x3e007fff, 0x0c04, x_Rs_x, do_rs},
+ {"brvc", 0x00003408, 0x3e007fff, 0x0d04, x_Rs_x, do_rs},
+ {"brcnz", 0x00003808, 0x3e007fff, 0x0e04, x_Rs_x, do_rs},
+ {"br", 0x00003c08, 0x3e007fff, 0x0f04, x_Rs_x, do_rs},
+ {"brcsl", 0x00000009, 0x3e007fff, 0x000c, x_Rs_x, do_rs},
+ {"brccl", 0x00000409, 0x3e007fff, 0x010c, x_Rs_x, do_rs},
+ {"brgtul", 0x00000809, 0x3e007fff, 0x020c, x_Rs_x, do_rs},
+ {"brleul", 0x00000c09, 0x3e007fff, 0x030c, x_Rs_x, do_rs},
+ {"breql", 0x00001009, 0x3e007fff, 0x040c, x_Rs_x, do_rs},
+ {"brnel", 0x00001409, 0x3e007fff, 0x050c, x_Rs_x, do_rs},
+ {"brgtl", 0x00001809, 0x3e007fff, 0x060c, x_Rs_x, do_rs},
+ {"brlel", 0x00001c09, 0x3e007fff, 0x070c, x_Rs_x, do_rs},
+ {"brgel", 0x00002009, 0x3e007fff, 0x080c, x_Rs_x, do_rs},
+ {"brltl", 0x00002409, 0x3e007fff, 0x090c, x_Rs_x, do_rs},
+ {"brmil", 0x00002809, 0x3e007fff, 0x0a0c, x_Rs_x, do_rs},
+ {"brpll", 0x00002c09, 0x3e007fff, 0x0b0c, x_Rs_x, do_rs},
+ {"brvsl", 0x00003009, 0x3e007fff, 0x0c0c, x_Rs_x, do_rs},
+ {"brvcl", 0x00003409, 0x3e007fff, 0x0d0c, x_Rs_x, do_rs},
+ {"brcnzl", 0x00003809, 0x3e007fff, 0x0e0c, x_Rs_x, do_rs},
+ {"brl", 0x00003c09, 0x3e007fff, 0x0f0c, x_Rs_x, do_rs},
+ {"brcs!", 0x0004, 0x7f0f, 0x00000008, x_Rs, do16_xrs},
+ {"brcc!", 0x0104, 0x7f0f, 0x00000408, x_Rs, do16_xrs},
+ {"brgtu!", 0x0204, 0x7f0f, 0x00000808, x_Rs, do16_xrs},
+ {"brleu!", 0x0304, 0x7f0f, 0x00000c08, x_Rs, do16_xrs},
+ {"breq!", 0x0404, 0x7f0f, 0x00001008, x_Rs, do16_xrs},
+ {"brne!", 0x0504, 0x7f0f, 0x00001408, x_Rs, do16_xrs},
+ {"brgt!", 0x0604, 0x7f0f, 0x00001808, x_Rs, do16_xrs},
+ {"brle!", 0x0704, 0x7f0f, 0x00001c08, x_Rs, do16_xrs},
+ {"brge!", 0x0804, 0x7f0f, 0x00002008, x_Rs, do16_xrs},
+ {"brlt!", 0x0904, 0x7f0f, 0x00002408, x_Rs, do16_xrs},
+ {"brmi!", 0x0a04, 0x7f0f, 0x00002808, x_Rs, do16_xrs},
+ {"brpl!", 0x0b04, 0x7f0f, 0x00002c08, x_Rs, do16_xrs},
+ {"brvs!", 0x0c04, 0x7f0f, 0x00003008, x_Rs, do16_xrs},
+ {"brvc!", 0x0d04, 0x7f0f, 0x00003408, x_Rs, do16_xrs},
+ {"brcnz!", 0x0e04, 0x7f0f, 0x00003808, x_Rs, do16_xrs},
+ {"br!", 0x0f04, 0x7f0f, 0x00003c08, x_Rs, do16_xrs},
+ {"brcsl!", 0x000c, 0x7f0f, 0x00000009, x_Rs, do16_xrs},
+ {"brccl!", 0x010c, 0x7f0f, 0x00000409, x_Rs, do16_xrs},
+ {"brgtul!", 0x020c, 0x7f0f, 0x00000809, x_Rs, do16_xrs},
+ {"brleul!", 0x030c, 0x7f0f, 0x00000c09, x_Rs, do16_xrs},
+ {"breql!", 0x040c, 0x7f0f, 0x00001009, x_Rs, do16_xrs},
+ {"brnel!", 0x050c, 0x7f0f, 0x00001409, x_Rs, do16_xrs},
+ {"brgtl!", 0x060c, 0x7f0f, 0x00001809, x_Rs, do16_xrs},
+ {"brlel!", 0x070c, 0x7f0f, 0x00001c09, x_Rs, do16_xrs},
+ {"brgel!", 0x080c, 0x7f0f, 0x00002009, x_Rs, do16_xrs},
+ {"brltl!", 0x090c, 0x7f0f, 0x00002409, x_Rs, do16_xrs},
+ {"brmil!", 0x0a0c, 0x7f0f, 0x00002809, x_Rs, do16_xrs},
+ {"brpll!", 0x0b0c, 0x7f0f, 0x00002c09, x_Rs, do16_xrs},
+ {"brvsl!", 0x0c0c, 0x7f0f, 0x00003009, x_Rs, do16_xrs},
+ {"brvcl!", 0x0d0c, 0x7f0f, 0x00003409, x_Rs, do16_xrs},
+ {"brcnzl!", 0x0e0c, 0x7f0f, 0x00003809, x_Rs, do16_xrs},
+ {"brl!", 0x0f0c, 0x7f0f, 0x00003c09, x_Rs, do16_xrs},
+ {"bvs", 0x08003000, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bvc", 0x08003400, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bvsl", 0x08003001, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bvcl", 0x08003401, 0x3e007c01, 0x8000, PC_DISP19div2, do_branch},
+ {"bvs!", 0x4c00, 0x7f00, 0x08003000, PC_DISP8div2, do16_branch},
+ {"bvc!", 0x4d00, 0x7f00, 0x08003400, PC_DISP8div2, do16_branch},
+ {"b!", 0x4f00, 0x7f00, 0x08003c00, PC_DISP8div2, do16_branch},
+ {"b", 0x08003c00, 0x3e007c01, 0x08003c00, PC_DISP19div2, do_branch},
+ {"cache", 0x30000000, 0x3ff00000, 0x8000, OP5_rvalueRs_SI15, do_cache},
+ {"ceinst", 0x38000000, 0x3e000000, 0x8000, I5_Rs_Rs_I5_OP5, do_ceinst},
+ {"clz", 0x3800000d, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"cmpteq.c", 0x00000019, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"cmptmi.c", 0x00100019, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"cmp.c", 0x00300019, 0x3ff003ff, 0x2003, x_Rs_Rs, do_rsrs},
+ {"cmpzteq.c", 0x0000001b, 0x3ff07fff, 0x8000, x_Rs_x, do_rs},
+ {"cmpztmi.c", 0x0010001b, 0x3ff07fff, 0x8000, x_Rs_x, do_rs},
+ {"cmpz.c", 0x0030001b, 0x3ff07fff, 0x8000, x_Rs_x, do_rs},
+ {"cmpi.c", 0x02040001, 0x3e0e0001, 0x8000, Rd_SI16, do_rdsi16},
+ {"cmp!", 0x2003, 0x700f, 0x00300019, Rd_Rs, do16_rdrs},
+ {"cop1", 0x0c00000c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, do_crdcrscrsimm5},
+ {"cop2", 0x0c000014, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, do_crdcrscrsimm5},
+ {"cop3", 0x0c00001c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, do_crdcrscrsimm5},
+ {"drte", 0x0c0000a4, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"extsb", 0x00000058, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extsb.c", 0x00000059, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extsh", 0x0000005a, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extsh.c", 0x0000005b, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extzb", 0x0000005c, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extzb.c", 0x0000005d, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extzh", 0x0000005e, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"extzh.c", 0x0000005f, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"jl", 0x04000001, 0x3e000001, 0x8000, PC_DISP24div2, do_jump},
+ {"jl!", 0x3001, 0x7001, 0x04000001, PC_DISP11div2, do16_jump},
+ {"j!", 0x3000, 0x7001, 0x04000000, PC_DISP11div2, do16_jump},
+ {"j", 0x04000000, 0x3e000001, 0x8000, PC_DISP24div2, do_jump},
+ {"lbu!", 0x200b, 0x0000700f, 0x2c000000, Rd_rvalueRs, do16_ldst_insn},
+ {"lbup!", 0x7003, 0x7007, 0x2c000000, Rd_rvalueBP_I5, do16_ldst_imm_insn},
+ {"alw", 0x0000000c, 0x3e0003ff, 0x8000, Rd_rvalue32Rs, do_ldst_atomic},
+ {"lcb", 0x00000060, 0x3e0003ff, 0x8000, x_rvalueRs_post4, do_ldst_unalign},
+ {"lcw", 0x00000062, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, do_ldst_unalign},
+ {"lce", 0x00000066, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, do_ldst_unalign},
+ {"ldc1", 0x0c00000a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, do_ldst_cop},
+ {"ldc2", 0x0c000012, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, do_ldst_cop},
+ {"ldc3", 0x0c00001a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, do_ldst_cop},
+ {"lh!", 0x2009, 0x700f, 0x22000000, Rd_rvalueRs, do16_ldst_insn},
+ {"lhp!", 0x7001, 0x7007, 0x22000000, Rd_rvalueBP_I5, do16_ldst_imm_insn},
+ {"ldi", 0x020c0000, 0x3e0e0000, 0x5000, Rd_SI16, do_rdsi16},
+ {"ldis", 0x0a0c0000, 0x3e0e0000, 0x5000, Rd_I16, do_rdi16},
+ {"ldiu!", 0x5000, 0x7000, 0x020c0000, Rd_I8, do16_ldst_imm_insn},
+ {"lw!", 0x2008, 0x700f, 0x20000000, Rd_rvalueRs, do16_ldst_insn},
+ {"lwp!", 0x7000, 0x7007, 0x20000000, Rd_rvalueBP_I5, do16_ldst_imm_insn},
+ {"mfcel", 0x00000448, 0x3e007fff, 0x8000, Rd_x_x, do_rd},
+ {"mfcel!", 0x1001, 0x7f0f, 0x00000448, x_Rs, do16_rs},
+ {"mad", 0x38000000, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mad.f!", 0x1004, 0x700f, 0x38000080, Rd_Rs, do16_rdrs},
+ {"madh", 0x38000203, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"madh.fs", 0x380002c3, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"madh.fs!", 0x100b, 0x700f, 0x380002c3, Rd_Rs, do16_rdrs},
+ {"madl", 0x38000002, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"madl.fs", 0x380000c2, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"madl.fs!", 0x100a, 0x700f, 0x380000c2, Rd_Rs, do16_rdrs},
+ {"madu", 0x38000020, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"madu!", 0x1005, 0x700f, 0x38000020, Rd_Rs, do16_rdrs},
+ {"mad.f", 0x38000080, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"max", 0x38000007, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"mazh", 0x38000303, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mazh.f", 0x38000383, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mazh.f!", 0x1009, 0x700f, 0x3800038c, Rd_Rs, do16_rdrs},
+ {"mazl", 0x38000102, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mazl.f", 0x38000182, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mazl.f!", 0x1008, 0x700f, 0x38000182, Rd_Rs, do16_rdrs},
+ {"mfceh", 0x00000848, 0x3e007fff, 0x8000, Rd_x_x, do_rd},
+ {"mfceh!", 0x1101, 0x7f0f, 0x00000848, x_Rs, do16_rs},
+ {"mfcehl", 0x00000c48, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mfsr", 0x00000050, 0x3e0003ff, 0x8000, Rd_x_I5, do_rdsrs},
+ {"mfcr", 0x0c000001, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfc1", 0x0c000009, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfc2", 0x0c000011, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfc3", 0x0c000019, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfcc1", 0x0c00000f, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfcc2", 0x0c000017, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mfcc3", 0x0c00001f, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mhfl!", 0x0002, 0x700f, 0x00003c56, Rd_LowRs, do16_hrdrs},
+ {"min", 0x38000006, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"mlfh!", 0x0001, 0x700f, 0x00003c56, Rd_HighRs, do16_rdhrs},
+ {"msb", 0x38000001, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msb.f!", 0x1006, 0x700f, 0x38000081, Rd_Rs, do16_rdrs},
+ {"msbh", 0x38000205, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msbh.fs", 0x380002c5, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msbh.fs!", 0x100f, 0x700f, 0x380002c5, Rd_Rs, do16_rdrs},
+ {"msbl", 0x38000004, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msbl.fs", 0x380000c4, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msbl.fs!", 0x100e, 0x700f, 0x380000c4, Rd_Rs, do16_rdrs},
+ {"msbu", 0x38000021, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"msbu!", 0x1007, 0x700f, 0x38000021, Rd_Rs, do16_rdrs},
+ {"msb.f", 0x38000081, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mszh", 0x38000305, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mszh.f", 0x38000385, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mszh.f!", 0x100d, 0x700f, 0x38000385, Rd_Rs, do16_rdrs},
+ {"mszl", 0x38000104, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mszl.f", 0x38000184, 0x3ff003ff, 0x8000, x_Rs_Rs, do_rsrs},
+ {"mszl.f!", 0x100c, 0x700f, 0x38000184, Rd_Rs, do16_rdrs},
+ {"mtcel!", 0x1000, 0x7f0f, 0x0000044a, x_Rs, do16_rs},
+ {"mtcel", 0x0000044a, 0x3e007fff, 0x8000, Rd_x_x, do_rd},
+ {"mtceh", 0x0000084a, 0x3e007fff, 0x8000, Rd_x_x, do_rd},
+ {"mtceh!", 0x1100, 0x7f0f, 0x0000084a, x_Rs, do16_rs},
+ {"mtcehl", 0x00000c4a, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mtsr", 0x00000052, 0x3e0003ff, 0x8000, x_Rs_I5, do_rdsrs},
+ {"mtcr", 0x0c000000, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtc1", 0x0c000008, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtc2", 0x0c000010, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtc3", 0x0c000018, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtcc1", 0x0c00000e, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtcc2", 0x0c000016, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mtcc3", 0x0c00001e, 0x3e00001f, 0x8000, Rd_Rs_x, do_rdcrs},
+ {"mul.f!", 0x1002, 0x700f, 0x00000041, Rd_Rs, do16_rdrs},
+ {"mulu!", 0x1003, 0x700f, 0x00000042, Rd_Rs, do16_rdrs},
+ {"mvcs", 0x00000056, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvcc", 0x00000456, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvgtu", 0x00000856, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvleu", 0x00000c56, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mveq", 0x00001056, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvne", 0x00001456, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvgt", 0x00001856, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvle", 0x00001c56, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvge", 0x00002056, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvlt", 0x00002456, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvmi", 0x00002856, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvpl", 0x00002c56, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvvs", 0x00003056, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mvvc", 0x00003456, 0x3e007fff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"mv", 0x00003c56, 0x3e007fff, 0x0003, Rd_Rs_x, do_rdrs},
+ {"mv!", 0x0003, 0x700f, 0x00003c56, Rd_Rs, do16_mv_rdrs},
+ {"neg", 0x0000001e, 0x3e0003ff, 0x8000, Rd_x_Rs, do_rdxrs},
+ {"neg.c", 0x0000001f, 0x3e0003ff, 0x2002, Rd_x_Rs, do_rdxrs},
+ {"neg!", 0x2002, 0x700f, 0x0000001f, Rd_Rs, do16_rdrs},
+ {"nop", 0x00000000, 0x3e0003ff, 0x0000, NO_OPD, do_empty},
+ {"not", 0x00000024, 0x3e0003ff, 0x8000, Rd_Rs_x, do_rdrs},
+ {"not.c", 0x00000025, 0x3e0003ff, 0x2006, Rd_Rs_x, do_rdrs},
+ {"nop!", 0x0000, 0x700f, 0x00000000, NO16_OPD, do_empty},
+ {"not!", 0x2006, 0x700f, 0x00000025, Rd_Rs, do16_rdrs},
+ {"or", 0x00000022, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"or.c", 0x00000023, 0x3e0003ff, 0x2005, Rd_Rs_Rs, do_rdrsrs},
+ {"ori", 0x020a0000, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"ori.c", 0x020a0001, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"oris", 0x0a0a0000, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"oris.c", 0x0a0a0001, 0x3e0e0001, 0x8000, Rd_I16, do_rdi16},
+ {"orri", 0x1a000000, 0x3e000001, 0x8000, Rd_Rs_I14, do_rdrsi14},
+ {"orri.c", 0x1a000001, 0x3e000001, 0x8000, Rd_Rs_I14, do_rdrsi14},
+ {"or!", 0x2005, 0x700f, 0x00000023, Rd_Rs, do16_rdrs},
+ {"pflush", 0x0000000a, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"pop!", 0x200a, 0x700f, 0x0e000000, Rd_rvalueRs, do16_push_pop},
+ {"push!", 0x200e, 0x700f, 0x06000004, Rd_lvalueRs, do16_push_pop},
+ {"ror", 0x00000038, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"ror.c", 0x00000039, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"rorc.c", 0x0000003b, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"rol", 0x0000003c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"rol.c", 0x0000003d, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"rolc.c", 0x0000003f, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"rori", 0x00000078, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"rori.c", 0x00000079, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"roric.c", 0x0000007b, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"roli", 0x0000007c, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"roli.c", 0x0000007d, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"rolic.c", 0x0000007f, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"rte", 0x0c000084, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"sb!", 0x200f, 0x700f, 0x2e000000, Rd_lvalueRs, do16_ldst_insn},
+ {"sbp!", 0x7007, 0x7007, 0x2e000000, Rd_lvalueBP_I5, do16_ldst_imm_insn},
+ {"asw", 0x0000000e, 0x3e0003ff, 0x8000, Rd_lvalue32Rs, do_ldst_atomic},
+ {"scb", 0x00000068, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, do_ldst_unalign},
+ {"scw", 0x0000006a, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, do_ldst_unalign},
+ {"sce", 0x0000006e, 0x3e0003ff, 0x8000, x_lvalueRs_post4, do_ldst_unalign},
+ {"sdbbp", 0x00000006, 0x3e0003ff, 0x6002, x_I5_x, do_xi5x},
+ {"sdbbp!", 0x6002, 0x7007, 0x00000006, Rd_I5, do16_xi5},
+ {"sh!", 0x200d, 0x700f, 0x2a000000, Rd_lvalueRs, do16_ldst_insn},
+ {"shp!", 0x7005, 0x7007, 0x2a000000, Rd_lvalueBP_I5, do16_ldst_imm_insn},
+ {"sleep", 0x0c0000c4, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"sll", 0x00000030, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"sll.c", 0x00000031, 0x3e0003ff, 0x0008, Rd_Rs_Rs, do_rdrsrs},
+ {"sll.s", 0x3800004e, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"slli", 0x00000070, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"slli.c", 0x00000071, 0x3e0003ff, 0x6001, Rd_Rs_I5, do_rdrsi5},
+ {"sll!", 0x0008, 0x700f, 0x00000031, Rd_Rs, do16_rdrs},
+ {"slli!", 0x6001, 0x7007, 0x00000071, Rd_I5, do16_rdi5},
+ {"srl", 0x00000034, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"srl.c", 0x00000035, 0x3e0003ff, 0x000a, Rd_Rs_Rs, do_rdrsrs},
+ {"sra", 0x00000036, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"sra.c", 0x00000037, 0x3e0003ff, 0x000b, Rd_Rs_Rs, do_rdrsrs},
+ {"srli", 0x00000074, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"srli.c", 0x00000075, 0x3e0003ff, 0x6003, Rd_Rs_I5, do_rdrsi5},
+ {"srai", 0x00000076, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"srai.c", 0x00000077, 0x3e0003ff, 0x8000, Rd_Rs_I5, do_rdrsi5},
+ {"srl!", 0x000a, 0x700f, 0x00000035, Rd_Rs, do16_rdrs},
+ {"sra!", 0x000b, 0x700f, 0x00000037, Rd_Rs, do16_rdrs},
+ {"srli!", 0x6003, 0x7007, 0x00000075, Rd_Rs, do16_rdi5},
+ {"stc1", 0x0c00000b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, do_ldst_cop},
+ {"stc2", 0x0c000013, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, do_ldst_cop},
+ {"stc3", 0x0c00001b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, do_ldst_cop},
+ {"sub", 0x00000014, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"sub.c", 0x00000015, 0x3e0003ff, 0x2001, Rd_Rs_Rs, do_rdrsrs},
+ {"sub.s", 0x38000049, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"subc", 0x00000016, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"subc.c", 0x00000017, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"sub!", 0x2001, 0x700f, 0x00000015, Rd_Rs, do16_rdrs},
+ {"subei!", 0x6080, 0x7087, 0x02000001, Rd_I4, do16_rdi4},
+ {"sw!", 0x200c, 0x700f, 0x28000000, Rd_lvalueRs, do16_ldst_insn},
+ {"swp!", 0x7004, 0x7007, 0x28000000, Rd_lvalueBP_I5, do16_ldst_imm_insn},
+ {"syscall", 0x00000002, 0x3e0003ff, 0x8000, I15, do_i15},
+ {"tcs", 0x00000054, 0x3e007fff, 0x0005, NO_OPD, do_empty},
+ {"tcc", 0x00000454, 0x3e007fff, 0x0105, NO_OPD, do_empty},
+ {"tcnz", 0x00003854, 0x3e007fff, 0x0e05, NO_OPD, do_empty},
+ {"tcs!", 0x0005, 0x7f0f, 0x00000054, NO16_OPD, do_empty},
+ {"tcc!", 0x0105, 0x7f0f, 0x00000454, NO16_OPD, do_empty},
+ {"tcnz!", 0x0e05, 0x7f0f, 0x00003854, NO16_OPD, do_empty},
+ {"teq", 0x00001054, 0x3e007fff, 0x0405, NO_OPD, do_empty},
+ {"teq!", 0x0405, 0x7f0f, 0x00001054, NO16_OPD, do_empty},
+ {"tgtu", 0x00000854, 0x3e007fff, 0x0205, NO_OPD, do_empty},
+ {"tgt", 0x00001854, 0x3e007fff, 0x0605, NO_OPD, do_empty},
+ {"tge", 0x00002054, 0x3e007fff, 0x0805, NO_OPD, do_empty},
+ {"tgtu!", 0x0205, 0x7f0f, 0x00000854, NO16_OPD, do_empty},
+ {"tgt!", 0x0605, 0x7f0f, 0x00001854, NO16_OPD, do_empty},
+ {"tge!", 0x0805, 0x7f0f, 0x00002054, NO16_OPD, do_empty},
+ {"tleu", 0x00000c54, 0x3e007fff, 0x0305, NO_OPD, do_empty},
+ {"tle", 0x00001c54, 0x3e007fff, 0x0705, NO_OPD, do_empty},
+ {"tlt", 0x00002454, 0x3e007fff, 0x0905, NO_OPD, do_empty},
+ {"stlb", 0x0c000004, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"mftlb", 0x0c000024, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"mtptlb", 0x0c000044, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"mtrtlb", 0x0c000064, 0x3e0003ff, 0x8000, NO_OPD, do_empty},
+ {"tleu!", 0x0305, 0x7f0f, 0x00000c54, NO16_OPD, do_empty},
+ {"tle!", 0x0705, 0x7f0f, 0x00001c54, NO16_OPD, do_empty},
+ {"tlt!", 0x0905, 0x7f0f, 0x00002454, NO16_OPD, do_empty},
+ {"tmi", 0x00002854, 0x3e007fff, 0x0a05, NO_OPD, do_empty},
+ {"tmi!", 0x0a05, 0x7f0f, 0x00002854, NO16_OPD, do_empty},
+ {"tne", 0x00001454, 0x3e007fff, 0x0505, NO_OPD, do_empty},
+ {"tne!", 0x0505, 0x7f0f, 0x00001454, NO16_OPD, do_empty},
+ {"tpl", 0x00002c54, 0x3e007fff, 0x0b05, NO_OPD, do_empty},
+ {"tpl!", 0x0b05, 0x7f0f, 0x00002c54, NO16_OPD, do_empty},
+ {"trapcs", 0x00000004, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapcc", 0x00000404, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapgtu", 0x00000804, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapleu", 0x00000c04, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapeq", 0x00001004, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapne", 0x00001404, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapgt", 0x00001804, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"traple", 0x00001c04, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapge", 0x00002004, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"traplt", 0x00002404, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapmi", 0x00002804, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trappl", 0x00002c04, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapvs", 0x00003004, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trapvc", 0x00003404, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"trap", 0x00003c04, 0x3e007fff, 0x8000, x_I5_x, do_xi5x},
+ {"tset", 0x00003c54, 0x3e007fff, 0x0f05, NO_OPD, do_empty},
+ {"tset!", 0x0f05, 0x00007f0f, 0x00003c54, NO16_OPD, do_empty},
+ {"tvs", 0x00003054, 0x3e007fff, 0x0c05, NO_OPD, do_empty},
+ {"tvc", 0x00003454, 0x3e007fff, 0x0d05, NO_OPD, do_empty},
+ {"tvs!", 0x0c05, 0x7f0f, 0x00003054, NO16_OPD, do_empty},
+ {"tvc!", 0x0d05, 0x7f0f, 0x00003454, NO16_OPD, do_empty},
+ {"xor", 0x00000026, 0x3e0003ff, 0x8000, Rd_Rs_Rs, do_rdrsrs},
+ {"xor.c", 0x00000027, 0x3e0003ff, 0x2007, Rd_Rs_Rs, do_rdrsrs},
+ {"xor!", 0x2007, 0x700f, 0x00000027, Rd_Rs, do16_rdrs},
+ /* Macro instruction. */
+ {"li", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, do_macro_li_rdi32},
+ /* la reg, imm32 -->(1) ldi reg, simm16
+ (2) ldis reg, %HI(imm32)
+ ori reg, %LO(imm32)
+
+ la reg, symbol -->(1) lis reg, %HI(imm32)
+ ori reg, %LO(imm32) */
+ {"la", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, do_macro_la_rdi32},
+ {"div", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"divu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"rem", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"remu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"mul", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"mulu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"maz", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"mazu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"mul.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"maz.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, do_macro_mul_rdrsrs},
+ {"lb", INSN_LB, 0x00000000, 0x8000, Insn_Type_SYN, do_macro_ldst_label},
+ {"lbu", INSN_LBU, 0x00000000, 0x200b, Insn_Type_SYN, do_macro_ldst_label},
+ {"lh", INSN_LH, 0x00000000, 0x2009, Insn_Type_SYN, do_macro_ldst_label},
+ {"lhu", INSN_LHU, 0x00000000, 0x8000, Insn_Type_SYN, do_macro_ldst_label},
+ {"lw", INSN_LW, 0x00000000, 0x2008, Insn_Type_SYN, do_macro_ldst_label},
+ {"sb", INSN_SB, 0x00000000, 0x200f, Insn_Type_SYN, do_macro_ldst_label},
+ {"sh", INSN_SH, 0x00000000, 0x200d, Insn_Type_SYN, do_macro_ldst_label},
+ {"sw", INSN_SW, 0x00000000, 0x200c, Insn_Type_SYN, do_macro_ldst_label},
+ /* Assembler use internal. */
+ {"ld_i32hi", 0x0a0c0000, 0x3e0e0000, 0x8000, Rd_I16, do_macro_rdi32hi},
+ {"ld_i32lo", 0x020a0000, 0x3e0e0001, 0x8000, Rd_I16, do_macro_rdi32lo},
+ {"ldis_pic", 0x0a0c0000, 0x3e0e0000, 0x5000, Rd_I16, do_rdi16_pic},
+ {"addi_s_pic",0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, do_addi_s_pic},
+ {"addi_u_pic",0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, do_addi_u_pic},
+ {"lw_pic", 0x20000000, 0x3e000000, 0x2008, Rd_rvalueRs_SI15, do_lw_pic},
+};
+
+/* Next free entry in the pool. */
+int next_literal_pool_place = 0;
+
+/* Next literal pool number. */
+int lit_pool_num = 1;
+symbolS *current_poolP = NULL;
+
+static int
+end_of_line (char *str)
+{
+ int retval = SUCCESS;
+
+ skip_whitespace (str);
+ if (*str != '\0')
+ {
+ retval = (int) FAIL;
+
+ if (!inst.error)
+ {
+ inst.error = BAD_GARBAGE}
+ }
+
+ return retval;
+}
+
+static int
+score_reg_parse (char **ccp, struct hash_control *htab)
+{
+ char *start = *ccp;
+ char c;
+ char *p;
+ struct reg_entry *reg;
+
+ p = start;
+ if (!ISALPHA (*p) || !is_name_beginner (*p))
+ return (int) FAIL;
+
+ c = *p++;
+
+ while (ISALPHA (c) || ISDIGIT (c) || c == '_')
+ c = *p++;
+
+ *--p = 0;
+ reg = (struct reg_entry *) hash_find (htab, start);
+ *p = c;
+
+ if (reg)
+ {
+ *ccp = p;
+ return reg->number;
+ }
+ return (int) FAIL;
+}
+
+/* If shift <= 0, only return reg. */
+
+static int
+reg_required_here (char **str, int shift, enum score_reg_type reg_type)
+{
+ static char buff[MAX_LITERAL_POOL_SIZE];
+ int reg = (int) FAIL;
+ char *start = *str;
+
+ if ((reg = score_reg_parse (str, all_reg_maps[reg_type].htab)) != (int) FAIL)
+ {
+ if (reg_type == REG_TYPE_SCORE)
+ {
+ if ((reg == 1) && (nor1 == 1) && (inst.bwarn == 0))
+ {
+ as_warn ("Using temp register(r1)");
+ inst.bwarn = 1;
+ }
+ }
+ if (shift >= 0)
+ {
+ if (reg_type == REG_TYPE_SCORE_CR)
+ strcpy (inst.reg, score_crn_table[reg].name);
+ else if (reg_type == REG_TYPE_SCORE_SR)
+ strcpy (inst.reg, score_srn_table[reg].name);
+ else
+ strcpy (inst.reg, "");
+
+ inst.instruction |= reg << shift;
+ }
+ }
+ else
+ {
+ *str = start;
+ sprintf (buff, _("register expected, not '%.100s'"), start);
+ inst.error = buff;
+ }
+
+ return reg;
+}
+
+static int
+skip_past_comma (char **str)
+{
+ char *p = *str;
+ char c;
+ int comma = 0;
+
+ while ((c = *p) == ' ' || c == ',')
+ {
+ p++;
+ if (c == ',' && comma++)
+ {
+ inst.error = BAD_SKIP_COMMA;
+ return (int) FAIL;
+ }
+ }
+
+ if ((c == '\0') || (comma == 0))
+ {
+ inst.error = BAD_SKIP_COMMA;
+ return (int) FAIL;
+ }
+
+ *str = p;
+ return comma ? SUCCESS : (int) FAIL;
+}
+
+static void
+do_rdrsrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 10, REG_TYPE_SCORE) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ if ((((inst.instruction >> 15) & 0x10) == 0)
+ && (((inst.instruction >> 10) & 0x10) == 0)
+ && (((inst.instruction >> 20) & 0x10) == 0)
+ && (inst.relax_inst != 0x8000)
+ && (((inst.instruction >> 20) & 0xf) == ((inst.instruction >> 15) & 0xf)))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0xf) << 4)
+ | (((inst.instruction >> 15) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+}
+
+static int
+walk_no_bignums (symbolS * sp)
+{
+ if (symbol_get_value_expression (sp)->X_op == O_big)
+ return 1;
+
+ if (symbol_get_value_expression (sp)->X_add_symbol)
+ return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
+ || (symbol_get_value_expression (sp)->X_op_symbol
+ && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
+
+ return 0;
+}
+
+static int
+my_get_expression (expressionS * ep, char **str)
+{
+ char *save_in;
+ segT seg;
+
+ save_in = input_line_pointer;
+ input_line_pointer = *str;
+ in_my_get_expression = 1;
+ seg = expression (ep);
+ in_my_get_expression = 0;
+
+ if (ep->X_op == O_illegal)
+ {
+ *str = input_line_pointer;
+ input_line_pointer = save_in;
+ inst.error = _("illegal expression");
+ return (int) FAIL;
+ }
+ /* Get rid of any bignums now, so that we don't generate an error for which
+ we can't establish a line number later on. Big numbers are never valid
+ in instructions, which is where this routine is always called. */
+ if (ep->X_op == O_big
+ || (ep->X_add_symbol
+ && (walk_no_bignums (ep->X_add_symbol)
+ || (ep->X_op_symbol && walk_no_bignums (ep->X_op_symbol)))))
+ {
+ inst.error = _("invalid constant");
+ *str = input_line_pointer;
+ input_line_pointer = save_in;
+ return (int) FAIL;
+ }
+
+ *str = input_line_pointer;
+ input_line_pointer = save_in;
+ return SUCCESS;
+}
+
+/* Check if an immediate is valid. If so, convert it to the right format. */
+
+static int
+validate_immediate (int val, unsigned int data_type)
+{
+ switch (data_type)
+ {
+ case _VALUE_HI16:
+ {
+ int val_hi = ((val & 0xffff0000) >> 16);
+
+ if (score_df_range[data_type].range[0] <= val_hi
+ && val_hi <= score_df_range[data_type].range[1])
+ return val_hi;
+ }
+ break;
+
+ case _VALUE_LO16:
+ {
+ int val_lo = (val & 0xffff);
+
+ if (score_df_range[data_type].range[0] <= val_lo
+ && val_lo <= score_df_range[data_type].range[1])
+ return val_lo;
+ }
+ break;
+
+ case _VALUE:
+ return val;
+ break;
+
+ default:
+ if (data_type == _SIMM14_NEG || data_type == _SIMM16_NEG || data_type == _IMM16_NEG)
+ val = -val;
+
+ if (score_df_range[data_type].range[0] <= val
+ && val <= score_df_range[data_type].range[1])
+ return val;
+
+ break;
+ }
+
+ return (int) FAIL;
+}
+
+static int
+data_op2 (char **str, int shift, enum score_data_type data_type)
+{
+ int value;
+ char data_exp[MAX_LITERAL_POOL_SIZE];
+ char *dataptr;
+ int cnt = 0;
+ char *pp = NULL;
+
+ skip_whitespace (*str);
+ inst.error = NULL;
+ dataptr = * str;
+
+ while ((*dataptr != '\0') && (*dataptr != '|') && (cnt <= MAX_LITERAL_POOL_SIZE)) /* 0x7c = ='|' */
+ {
+ data_exp[cnt] = *dataptr;
+ dataptr++;
+ cnt++;
+ }
+
+ data_exp[cnt] = '\0';
+ pp = (char *)&data_exp;
+
+ if (*dataptr == '|') /* process PCE */
+ {
+ if (my_get_expression (&inst.reloc.exp, &pp) == (int) FAIL)
+ return (int) FAIL;
+ end_of_line (pp);
+ if (inst.error != 0)
+ return (int) FAIL; /* to ouptut_inst to printf out the error */
+ *str = dataptr;
+ }
+ else /* process 16 bit */
+ {
+ if (my_get_expression (&inst.reloc.exp, str) == (int) FAIL)
+ {
+ return (int) FAIL;
+ }
+
+ dataptr = (char *)data_exp;
+ for (; *dataptr != '\0'; dataptr++)
+ {
+ *dataptr = TOLOWER (*dataptr);
+ if (*dataptr == '!' || *dataptr == ' ')
+ break;
+ }
+ dataptr = (char *)data_exp;
+
+ if ((*dataptr == '0') && (*(dataptr + 1) == 'x')
+ && (data_type != _SIMM16_LA)
+ && (data_type != _VALUE_HI16)
+ && (data_type != _VALUE_LO16)
+ && (data_type != _IMM16)
+ && (data_type != _IMM15)
+ && (data_type != _IMM14)
+ && (data_type != _IMM4)
+ && (data_type != _IMM5)
+ && (data_type != _IMM8)
+ && (data_type != _IMM5_RSHIFT_1)
+ && (data_type != _IMM5_RSHIFT_2)
+ && (data_type != _SIMM14_NEG)
+ && (data_type != _IMM10_RSHIFT_2)
+ && (data_type != _GP_IMM15))
+ {
+ data_type += 24;
+ }
+ }
+
+ if ((inst.reloc.exp.X_add_symbol)
+ && ((data_type == _SIMM16)
+ || (data_type == _SIMM16_NEG)
+ || (data_type == _IMM16_NEG)
+ || (data_type == _SIMM14)
+ || (data_type == _SIMM14_NEG)
+ || (data_type == _IMM5)
+ || (data_type == _IMM14)
+ || (data_type == _IMM20)
+ || (data_type == _IMM16)
+ || (data_type == _IMM15)
+ || (data_type == _IMM4)))
+ {
+ inst.error = BAD_ARGS;
+ return (int) FAIL;
+ }
+
+ if (inst.reloc.exp.X_add_symbol)
+ {
+ switch (data_type)
+ {
+ case _SIMM16_LA:
+ return (int) FAIL;
+ case _VALUE_HI16:
+ inst.reloc.type = BFD_RELOC_HI16_S;
+ inst.reloc.pc_rel = 0;
+ break;
+ case _VALUE_LO16:
+ inst.reloc.type = BFD_RELOC_LO16;
+ inst.reloc.pc_rel = 0;
+ break;
+ case _GP_IMM15:
+ inst.reloc.type = BFD_RELOC_SCORE_GPREL15;
+ inst.reloc.pc_rel = 0;
+ break;
+ case _SIMM16_pic:
+ case _IMM16_LO16_pic:
+ inst.reloc.type = BFD_RELOC_SCORE_GOT_LO16;
+ inst.reloc.pc_rel = 0;
+ break;
+ default:
+ inst.reloc.type = BFD_RELOC_32;
+ inst.reloc.pc_rel = 0;
+ break;
+ }
+ }
+ else
+ {
+ if (data_type == _IMM16_pic)
+ {
+ inst.reloc.type = BFD_RELOC_SCORE_DUMMY_HI16;
+ inst.reloc.pc_rel = 0;
+ }
+
+ if (data_type == _SIMM16_LA && inst.reloc.exp.X_unsigned == 1)
+ {
+ value = validate_immediate (inst.reloc.exp.X_add_number, _SIMM16_LA_POS);
+ if (value == (int) FAIL) /* for advance to check if this is ldis */
+ if ((inst.reloc.exp.X_add_number & 0xffff) == 0)
+ {
+ inst.instruction |= 0x8000000;
+ inst.instruction |= ((inst.reloc.exp.X_add_number >> 16) << 1) & 0x1fffe;
+ return SUCCESS;
+ }
+ }
+ else
+ {
+ value = validate_immediate (inst.reloc.exp.X_add_number, data_type);
+ }
+
+ if (value == (int) FAIL)
+ {
+ char err_msg[100];
+
+ if ((data_type != _SIMM14_NEG) && (data_type != _SIMM16_NEG) && (data_type != _IMM16_NEG))
+ {
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type].bits,
+ score_df_range[data_type].range[0], score_df_range[data_type].range[1]);
+ }
+ else
+ {
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type].bits,
+ -score_df_range[data_type].range[1], -score_df_range[data_type].range[0]);
+ }
+
+ inst.error = _(err_msg);
+ return (int) FAIL;
+ }
+
+ if ((score_df_range[data_type].range[0] != 0) || (data_type == _IMM5_RANGE_8_31))
+ {
+ value &= (1 << score_df_range[data_type].bits) - 1;
+ }
+
+ inst.instruction |= value << shift;
+ }
+
+ if ((inst.instruction & 0xf0000000) == 0x30000000)
+ {
+ if ((((inst.instruction >> 20) & 0x1F) != 0)
+ && (((inst.instruction >> 20) & 0x1F) != 1)
+ && (((inst.instruction >> 20) & 0x1F) != 2)
+ && (((inst.instruction >> 20) & 0x1F) != 3)
+ && (((inst.instruction >> 20) & 0x1F) != 4)
+ && (((inst.instruction >> 20) & 0x1F) != 8)
+ && (((inst.instruction >> 20) & 0x1F) != 9)
+ && (((inst.instruction >> 20) & 0x1F) != 0xa)
+ && (((inst.instruction >> 20) & 0x1F) != 0xb)
+ && (((inst.instruction >> 20) & 0x1F) != 0xc)
+ && (((inst.instruction >> 20) & 0x1F) != 0xd)
+ && (((inst.instruction >> 20) & 0x1F) != 0xe)
+ && (((inst.instruction >> 20) & 0x1F) != 0x10)
+ && (((inst.instruction >> 20) & 0x1F) != 0x11)
+ && (((inst.instruction >> 20) & 0x1F) != 0x18)
+ && (((inst.instruction >> 20) & 0x1F) != 0x1A)
+ && (((inst.instruction >> 20) & 0x1F) != 0x1B)
+ && (((inst.instruction >> 20) & 0x1F) != 0x1d)
+ && (((inst.instruction >> 20) & 0x1F) != 0x1e)
+ && (((inst.instruction >> 20) & 0x1F) != 0x1f))
+ {
+ char err_msg[100];
+
+ sprintf (err_msg, "invalid constant: bit expression not defined");
+ inst.error = _(err_msg);
+ return (int) FAIL;
+ }
+ }
+
+ return SUCCESS;
+}
+
+/* Handle addi/addi.c/addis.c/cmpi.c/addis.c/ldi. */
+
+static void
+do_rdsi16 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 1, _SIMM16) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ /* ldi. */
+ if ((inst.instruction & 0x20c0000) == 0x20c0000)
+ {
+ if ((((inst.instruction >> 20) & 0x10) == 0x10) || ((inst.instruction & 0x1fe00) != 0))
+ {
+ inst.relax_inst = 0x8000;
+ }
+ else
+ {
+ inst.relax_inst |= (inst.instruction >> 1) & 0xff;
+ inst.relax_inst |= (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ }
+ else if (((inst.instruction >> 20) & 0x10) == 0x10)
+ {
+ inst.relax_inst = 0x8000;
+ }
+}
+
+/* Handle subi/subi.c. */
+
+static void
+do_sub_rdsi16 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _SIMM16_NEG) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle subis/subis.c. */
+
+static void
+do_sub_rdi16 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _IMM16_NEG) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle addri/addri.c. */
+
+static void
+do_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reg_required_here (&str, 15, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL)
+ data_op2 (&str, 1, _SIMM14);
+}
+
+/* Handle subri.c/subri. */
+static void
+do_sub_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reg_required_here (&str, 15, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _SIMM14_NEG) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle bitclr.c/bitset.c/bittgl.c/slli.c/srai.c/srli.c/roli.c/rori.c/rolic.c. */
+static void
+do_rdrsi5 (char *str) /* 0~((2^14)-1) */
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 10, _IMM5) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if ((((inst.instruction >> 20) & 0x1f) == ((inst.instruction >> 15) & 0x1f))
+ && (inst.relax_inst != 0x8000) && (((inst.instruction >> 15) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0x1f) << 3) | (((inst.instruction >> 15) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ inst.relax_inst = 0x8000;
+}
+
+/* Handle andri/orri/andri.c/orri.c. */
+
+static void
+do_rdrsi14 (char *str) /* 0 ~ ((2^14)-1) */
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reg_required_here (&str, 15, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _IMM14) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle bittst.c. */
+static void
+do_xrsi5 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 10, _IMM5) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if ((inst.relax_inst != 0x8000) && (((inst.instruction >> 15) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0x1f) << 3) | (((inst.instruction >> 15) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ inst.relax_inst = 0x8000;
+}
+
+/* Handle andi/ori/andis/oris/ldis. */
+static void
+do_rdi16 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 1, _IMM16) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if (((inst.instruction & 0xa0dfffe) != 0xa0c0000) || ((((inst.instruction >> 20) & 0x1f) & 0x10) == 0x10))
+ inst.relax_inst = 0x8000;
+ else
+ inst.relax_size = 2;
+}
+
+static void
+do_macro_rdi32hi (char *str)
+{
+ skip_whitespace (str);
+
+ /* Do not handle end_of_line(). */
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL)
+ data_op2 (&str, 1, _VALUE_HI16);
+}
+
+static void
+do_macro_rdi32lo (char *str)
+{
+ skip_whitespace (str);
+
+ /* Do not handle end_of_line(). */
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL)
+ data_op2 (&str, 1, _VALUE_LO16);
+}
+
+/* Handle ldis_pic. */
+
+static void
+do_rdi16_pic (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _IMM16_pic) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle addi_s_pic to generate R_SCORE_GOT_LO16 . */
+
+static void
+do_addi_s_pic (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _SIMM16_pic) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle addi_u_pic to generate R_SCORE_GOT_LO16 . */
+
+static void
+do_addi_u_pic (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && data_op2 (&str, 1, _IMM16_LO16_pic) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle mfceh/mfcel/mtceh/mtchl. */
+
+static void
+do_rd (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL)
+ end_of_line (str);
+}
+
+static void
+do_rs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if ((inst.relax_inst != 0x8000) && (((inst.instruction >> 15) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0xf) << 8) | (((inst.instruction >> 15) & 0xf) << 4);
+ inst.relax_size = 2;
+ }
+ else
+ inst.relax_inst = 0x8000;
+}
+
+static void
+do_i15 (char *str)
+{
+ skip_whitespace (str);
+
+ if (data_op2 (&str, 10, _IMM15) != (int) FAIL)
+ end_of_line (str);
+}
+
+static void
+do_xi5x (char *str)
+{
+ skip_whitespace (str);
+
+ if (data_op2 (&str, 15, _IMM5) == (int) FAIL || end_of_line (str) == (int) FAIL)
+ return;
+
+ if (inst.relax_inst != 0x8000)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0x1f) << 3);
+ inst.relax_size = 2;
+ }
+}
+
+static void
+do_rdrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if (inst.relax_inst != 0x8000)
+ {
+ if (((inst.instruction & 0x7f) == 0x56)) /* adjust mv -> mv! / mlfh! / mhfl! */
+ {
+ /* mlfh */
+ if ((((inst.instruction >> 15) & 0x10) != 0x0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ inst.relax_inst = 0x00000001 | (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* mhfl */
+ else if ((((inst.instruction >> 15) & 0x10) == 0x0) && ((inst.instruction >> 20) & 0x10) != 0)
+ {
+ inst.relax_inst = 0x00000002 | (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else if ((((inst.instruction >> 15) & 0x10) == 0x0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else if ((((inst.instruction >> 15) & 0x10) == 0x0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+}
+
+/* Handle mfcr/mtcr. */
+static void
+do_rdcrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reg_required_here (&str, 15, REG_TYPE_SCORE_CR) != (int) FAIL)
+ end_of_line (str);
+}
+
+/* Handle mfsr/mtsr. */
+
+static void
+do_rdsrs (char *str)
+{
+ skip_whitespace (str);
+
+ /* mfsr */
+ if ((inst.instruction & 0xff) == 0x50)
+ {
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reg_required_here (&str, 10, REG_TYPE_SCORE_SR) != (int) FAIL)
+ end_of_line (str);
+ }
+ else
+ {
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL)
+ reg_required_here (&str, 10, REG_TYPE_SCORE_SR);
+ }
+}
+
+/* Handle neg. */
+
+static void
+do_rdxrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 10, REG_TYPE_SCORE) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if ((inst.relax_inst != 0x8000) && (((inst.instruction >> 10) & 0x10) == 0)
+ && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0xf) << 4) | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ inst.relax_inst = 0x8000;
+}
+
+/* Handle cmp.c/cmp<cond>. */
+static void
+do_rsrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 10, REG_TYPE_SCORE) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if ((inst.relax_inst != 0x8000) && (((inst.instruction >> 20) & 0x1f) == 3)
+ && (((inst.instruction >> 10) & 0x10) == 0) && (((inst.instruction >> 15) & 0x10) == 0))
+ {
+ inst.relax_inst |= (((inst.instruction >> 10) & 0xf) << 4) | (((inst.instruction >> 15) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ else
+ inst.relax_inst = 0x8000;
+}
+
+static void
+do_ceinst (char *str)
+{
+ char *strbak;
+
+ strbak = str;
+ skip_whitespace (str);
+
+ if (data_op2 (&str, 20, _IMM5) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 10, REG_TYPE_SCORE) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 5, _IMM5) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 0, _IMM5) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ str = strbak;
+ if (data_op2 (&str, 0, _IMM25) == (int) FAIL)
+ return;
+ }
+}
+
+static int
+reglow_required_here (char **str, int shift)
+{
+ static char buff[MAX_LITERAL_POOL_SIZE];
+ int reg;
+ char *start = *str;
+
+ if ((reg = score_reg_parse (str, all_reg_maps[REG_TYPE_SCORE].htab)) != (int) FAIL)
+ {
+ if ((reg == 1) && (nor1 == 1) && (inst.bwarn == 0))
+ {
+ as_warn ("Using temp register(r1)");
+ inst.bwarn = 1;
+ }
+ if (reg < 16)
+ {
+ if (shift >= 0)
+ inst.instruction |= reg << shift;
+
+ return reg;
+ }
+ }
+
+ /* Restore the start point, we may have got a reg of the wrong class. */
+ *str = start;
+ sprintf (buff, _("low register(r0-r15)expected, not '%.100s'"), start);
+ inst.error = buff;
+ return (int) FAIL;
+}
+
+/* Handle addc!/add!/and!/cmp!/neg!/not!/or!/sll!/srl!/sra!/xor!/sub!. */
+static void
+do16_rdrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reglow_required_here (&str, 8) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reglow_required_here (&str, 4) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ if ((inst.instruction & 0x700f) == 0x2003) /* cmp! */
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 15)
+ | (((inst.instruction >> 4) & 0xf) << 10);
+ }
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 8) & 0xf) << 15) | (((inst.instruction >> 4) & 0xf) << 10);
+ }
+ inst.relax_size = 4;
+ }
+}
+
+static void
+do16_rs (char *str)
+{
+ int rd = 0;
+
+ skip_whitespace (str);
+
+ if ((rd = reglow_required_here (&str, 4)) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ inst.relax_inst |= rd << 20;
+ inst.relax_size = 4;
+ }
+}
+
+/* Handle br!/brl!. */
+static void
+do16_xrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reglow_required_here (&str, 4) == (int) FAIL || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 10)
+ | (((inst.instruction >> 4) & 0xf) << 15);
+ inst.relax_size = 4;
+ }
+}
+
+static int
+reghigh_required_here (char **str, int shift)
+{
+ static char buff[MAX_LITERAL_POOL_SIZE];
+ int reg;
+ char *start = *str;
+
+ if ((reg = score_reg_parse (str, all_reg_maps[REG_TYPE_SCORE].htab)) != (int) FAIL)
+ {
+ if (15 < reg && reg < 32)
+ {
+ if (shift >= 0)
+ inst.instruction |= (reg & 0xf) << shift;
+
+ return reg;
+ }
+ }
+
+ *str = start;
+ sprintf (buff, _("high register(r16-r31)expected, not '%.100s'"), start);
+ inst.error = buff;
+ return (int) FAIL;
+}
+
+/* Handle mhfl!. */
+static void
+do16_hrdrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reghigh_required_here (&str, 8) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reglow_required_here (&str, 4) != (int) FAIL
+ && end_of_line (str) != (int) FAIL)
+ {
+ inst.relax_inst |= ((((inst.instruction >> 8) & 0xf) | 0x10) << 20)
+ | (((inst.instruction >> 4) & 0xf) << 15) | (0xf << 10);
+ inst.relax_size = 4;
+ }
+}
+
+/* Handle mlfh!. */
+static void
+do16_rdhrs (char *str)
+{
+ skip_whitespace (str);
+
+ if (reglow_required_here (&str, 8) != (int) FAIL
+ && skip_past_comma (&str) != (int) FAIL
+ && reghigh_required_here (&str, 4) != (int) FAIL
+ && end_of_line (str) != (int) FAIL)
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | ((((inst.instruction >> 4) & 0xf) | 0x10) << 15) | (0xf << 10);
+ inst.relax_size = 4;
+ }
+}
+
+/* We need to be able to fix up arbitrary expressions in some statements.
+ This is so that we can handle symbols that are an arbitrary distance from
+ the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
+ which returns part of an address in a form which will be valid for
+ a data instruction. We do this by pushing the expression into a symbol
+ in the expr_section, and creating a fix for that. */
+static fixS *
+fix_new_score (fragS * frag, int where, short int size, expressionS * exp, int pc_rel, int reloc)
+{
+ fixS *new_fix;
+
+ switch (exp->X_op)
+ {
+ case O_constant:
+ case O_symbol:
+ case O_add:
+ case O_subtract:
+ new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
+ break;
+ default:
+ new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, pc_rel, reloc);
+ break;
+ }
+ return new_fix;
+}
+
+static void
+init_dependency_vector (void)
+{
+ int i;
+
+ for (i = 0; i < vector_size; i++)
+ memset (&dependency_vector[i], '\0', sizeof (dependency_vector[i]));
+
+ return;
+}
+
+static enum insn_type_for_dependency
+dependency_type_from_insn (char *insn_name)
+{
+ char name[INSN_NAME_LEN];
+ const struct insn_to_dependency *tmp;
+
+ strcpy (name, insn_name);
+ tmp = (const struct insn_to_dependency *) hash_find (dependency_insn_hsh, name);
+
+ if (tmp)
+ return tmp->type;
+
+ return D_all_insn;
+}
+
+static int
+check_dependency (char *pre_insn, char *pre_reg,
+ char *cur_insn, char *cur_reg, int *warn_or_error)
+{
+ int bubbles = 0;
+ unsigned int i;
+ enum insn_type_for_dependency pre_insn_type;
+ enum insn_type_for_dependency cur_insn_type;
+
+ pre_insn_type = dependency_type_from_insn (pre_insn);
+ cur_insn_type = dependency_type_from_insn (cur_insn);
+
+ for (i = 0; i < sizeof (data_dependency_table) / sizeof (data_dependency_table[0]); i++)
+ {
+ if ((pre_insn_type == data_dependency_table[i].pre_insn_type)
+ && (D_all_insn == data_dependency_table[i].cur_insn_type
+ || cur_insn_type == data_dependency_table[i].cur_insn_type)
+ && (strcmp (data_dependency_table[i].pre_reg, "") == 0
+ || strcmp (data_dependency_table[i].pre_reg, pre_reg) == 0)
+ && (strcmp (data_dependency_table[i].cur_reg, "") == 0
+ || strcmp (data_dependency_table[i].cur_reg, cur_reg) == 0))
+ {
+ bubbles = (score7) ? data_dependency_table[i].bubblenum_7 : data_dependency_table[i].bubblenum_5;
+ *warn_or_error = data_dependency_table[i].warn_or_error;
+ break;
+ }
+ }
+
+ return bubbles;
+}
+
+static void
+build_one_frag (struct score_it one_inst)
+{
+ char *p;
+ int relaxable_p = g_opt;
+ int relax_size = 0;
+
+ /* Start a new frag if frag_now is not empty. */
+ if (frag_now_fix () != 0)
+ {
+ if (!frag_now->tc_frag_data.is_insn)
+ frag_wane (frag_now);
+
+ frag_new (0);
+ }
+ frag_grow (20);
+
+ p = frag_more (one_inst.size);
+ md_number_to_chars (p, one_inst.instruction, one_inst.size);
+
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (one_inst.size);
+#endif
+
+ relaxable_p &= (one_inst.relax_size != 0);
+ relax_size = relaxable_p ? one_inst.relax_size : 0;
+
+ p = frag_var (rs_machine_dependent, relax_size + RELAX_PAD_BYTE, 0,
+ RELAX_ENCODE (one_inst.size, one_inst.relax_size,
+ one_inst.type, 0, 0, relaxable_p),
+ NULL, 0, NULL);
+
+ if (relaxable_p)
+ md_number_to_chars (p, one_inst.relax_inst, relax_size);
+}
+
+static void
+handle_dependency (struct score_it *theinst)
+{
+ int i;
+ int warn_or_error = 0; /* warn - 0; error - 1 */
+ int bubbles = 0;
+ int remainder_bubbles = 0;
+ char cur_insn[INSN_NAME_LEN];
+ char pre_insn[INSN_NAME_LEN];
+ struct score_it nop_inst;
+ struct score_it pflush_inst;
+
+ nop_inst.instruction = 0x0000;
+ nop_inst.size = 2;
+ nop_inst.relax_inst = 0x80008000;
+ nop_inst.relax_size = 4;
+ nop_inst.type = NO16_OPD;
+
+ pflush_inst.instruction = 0x8000800a;
+ pflush_inst.size = 4;
+ pflush_inst.relax_inst = 0x8000;
+ pflush_inst.relax_size = 0;
+ pflush_inst.type = NO_OPD;
+
+ /* pflush will clear all data dependency. */
+ if (strcmp (theinst->name, "pflush") == 0)
+ {
+ init_dependency_vector ();
+ return;
+ }
+
+ /* Push current instruction to dependency_vector[0]. */
+ for (i = vector_size - 1; i > 0; i--)
+ memcpy (&dependency_vector[i], &dependency_vector[i - 1], sizeof (dependency_vector[i]));
+
+ memcpy (&dependency_vector[0], theinst, sizeof (dependency_vector[i]));
+
+ /* There is no dependency between nop and any instruction. */
+ if (strcmp (dependency_vector[0].name, "nop") == 0
+ || strcmp (dependency_vector[0].name, "nop!") == 0)
+ return;
+
+ /* "pce" is defined in insn_to_dependency_table. */
+#define PCE_NAME "pce"
+
+ if (dependency_vector[0].type == Insn_Type_PCE)
+ strcpy (cur_insn, PCE_NAME);
+ else
+ strcpy (cur_insn, dependency_vector[0].name);
+
+ for (i = 1; i < vector_size; i++)
+ {
+ /* The element of dependency_vector is NULL. */
+ if (dependency_vector[i].name[0] == '\0')
+ continue;
+
+ if (dependency_vector[i].type == Insn_Type_PCE)
+ strcpy (pre_insn, PCE_NAME);
+ else
+ strcpy (pre_insn, dependency_vector[i].name);
+
+ bubbles = check_dependency (pre_insn, dependency_vector[i].reg,
+ cur_insn, dependency_vector[0].reg, &warn_or_error);
+ remainder_bubbles = bubbles - i + 1;
+
+ if (remainder_bubbles > 0)
+ {
+ int j;
+
+ if (fix_data_dependency == 1)
+ {
+ if (remainder_bubbles <= 2)
+ {
+ if (warn_fix_data_dependency)
+ as_warn ("Fix data dependency: %s %s -- %s %s (insert %d nop!/%d)",
+ dependency_vector[i].name, dependency_vector[i].reg,
+ dependency_vector[0].name, dependency_vector[0].reg,
+ remainder_bubbles, bubbles);
+
+ for (j = (vector_size - 1); (j - remainder_bubbles) > 0; j--)
+ memcpy (&dependency_vector[j], &dependency_vector[j - remainder_bubbles],
+ sizeof (dependency_vector[j]));
+
+ for (j = 1; j <= remainder_bubbles; j++)
+ {
+ memset (&dependency_vector[j], '\0', sizeof (dependency_vector[j]));
+ /* Insert nop!. */
+ build_one_frag (nop_inst);
+ }
+ }
+ else
+ {
+ if (warn_fix_data_dependency)
+ as_warn ("Fix data dependency: %s %s -- %s %s (insert 1 pflush/%d)",
+ dependency_vector[i].name, dependency_vector[i].reg,
+ dependency_vector[0].name, dependency_vector[0].reg,
+ bubbles);
+
+ for (j = 1; j < vector_size; j++)
+ memset (&dependency_vector[j], '\0', sizeof (dependency_vector[j]));
+
+ /* Insert pflush. */
+ build_one_frag (pflush_inst);
+ }
+ }
+ else
+ {
+ if (warn_or_error)
+ {
+ as_bad ("data dependency: %s %s -- %s %s (%d/%d bubble)",
+ dependency_vector[i].name, dependency_vector[i].reg,
+ dependency_vector[0].name, dependency_vector[0].reg,
+ remainder_bubbles, bubbles);
+ }
+ else
+ {
+ as_warn ("data dependency: %s %s -- %s %s (%d/%d bubble)",
+ dependency_vector[i].name, dependency_vector[i].reg,
+ dependency_vector[0].name, dependency_vector[0].reg,
+ remainder_bubbles, bubbles);
+ }
+ }
+ }
+ }
+}
+
+static enum insn_class
+get_insn_class_from_type (enum score_insn_type type)
+{
+ enum insn_class retval = (int) FAIL;
+
+ switch (type)
+ {
+ case Rd_I4:
+ case Rd_I5:
+ case Rd_rvalueBP_I5:
+ case Rd_lvalueBP_I5:
+ case Rd_I8:
+ case PC_DISP8div2:
+ case PC_DISP11div2:
+ case Rd_Rs:
+ case Rd_HighRs:
+ case Rd_lvalueRs:
+ case Rd_rvalueRs:
+ case x_Rs:
+ case Rd_LowRs:
+ case NO16_OPD:
+ retval = INSN_CLASS_16;
+ break;
+ case Rd_Rs_I5:
+ case x_Rs_I5:
+ case x_I5_x:
+ case Rd_Rs_I14:
+ case I15:
+ case Rd_I16:
+ case Rd_SI16:
+ case Rd_rvalueRs_SI10:
+ case Rd_lvalueRs_SI10:
+ case Rd_rvalueRs_preSI12:
+ case Rd_rvalueRs_postSI12:
+ case Rd_lvalueRs_preSI12:
+ case Rd_lvalueRs_postSI12:
+ case Rd_Rs_SI14:
+ case Rd_rvalueRs_SI15:
+ case Rd_lvalueRs_SI15:
+ case PC_DISP19div2:
+ case PC_DISP24div2:
+ case Rd_Rs_Rs:
+ case x_Rs_x:
+ case x_Rs_Rs:
+ case Rd_Rs_x:
+ case Rd_x_Rs:
+ case Rd_x_x:
+ case OP5_rvalueRs_SI15:
+ case I5_Rs_Rs_I5_OP5:
+ case x_rvalueRs_post4:
+ case Rd_rvalueRs_post4:
+ case Rd_x_I5:
+ case Rd_lvalueRs_post4:
+ case x_lvalueRs_post4:
+ case Rd_Rs_Rs_imm:
+ case NO_OPD:
+ case Rd_lvalue32Rs:
+ case Rd_rvalue32Rs:
+ case Insn_GP:
+ case Insn_PIC:
+ retval = INSN_CLASS_32;
+ break;
+ case Insn_Type_PCE:
+ retval = INSN_CLASS_PCE;
+ break;
+ case Insn_Type_SYN:
+ retval = INSN_CLASS_SYN;
+ break;
+ default:
+ abort ();
+ break;
+ }
+ return retval;
+}
+
+static unsigned long
+adjust_paritybit (unsigned long m_code, enum insn_class class)
+{
+ unsigned long result = 0;
+ unsigned long m_code_high = 0;
+ unsigned long m_code_low = 0;
+ unsigned long pb_high = 0;
+ unsigned long pb_low = 0;
+
+ if (class == INSN_CLASS_32)
+ {
+ pb_high = 0x80000000;
+ pb_low = 0x00008000;
+ }
+ else if (class == INSN_CLASS_16)
+ {
+ pb_high = 0;
+ pb_low = 0;
+ }
+ else if (class == INSN_CLASS_PCE)
+ {
+ pb_high = 0;
+ pb_low = 0x00008000;
+ }
+ else if (class == INSN_CLASS_SYN)
+ {
+ /* FIXME. at this time, INSN_CLASS_SYN must be 32 bit, but, instruction type should
+ be changed if macro instruction has been expanded. */
+ pb_high = 0x80000000;
+ pb_low = 0x00008000;
+ }
+ else
+ {
+ abort ();
+ }
+
+ m_code_high = m_code & 0x3fff8000;
+ m_code_low = m_code & 0x00007fff;
+ result = pb_high | (m_code_high << 1) | pb_low | m_code_low;
+ return result;
+
+}
+
+static void
+gen_insn_frag (struct score_it *part_1, struct score_it *part_2)
+{
+ char *p;
+ bfd_boolean pce_p = FALSE;
+ int relaxable_p = g_opt;
+ int relax_size = 0;
+ struct score_it *inst1 = part_1;
+ struct score_it *inst2 = part_2;
+ struct score_it backup_inst1;
+
+ pce_p = (inst2) ? TRUE : FALSE;
+ memcpy (&backup_inst1, inst1, sizeof (struct score_it));
+
+ /* Adjust instruction opcode and to be relaxed instruction opcode. */
+ if (pce_p)
+ {
+ backup_inst1.instruction = ((backup_inst1.instruction & 0x7FFF) << 15)
+ | (inst2->instruction & 0x7FFF);
+ backup_inst1.instruction = adjust_paritybit (backup_inst1.instruction, INSN_CLASS_PCE);
+ backup_inst1.relax_inst = 0x8000;
+ backup_inst1.size = INSN_SIZE;
+ backup_inst1.relax_size = 0;
+ backup_inst1.type = Insn_Type_PCE;
+ }
+ else
+ {
+ backup_inst1.instruction = adjust_paritybit (backup_inst1.instruction,
+ GET_INSN_CLASS (backup_inst1.type));
+ }
+
+ if (backup_inst1.relax_size != 0)
+ {
+ enum insn_class tmp;
+
+ tmp = (backup_inst1.size == INSN_SIZE) ? INSN_CLASS_16 : INSN_CLASS_32;
+ backup_inst1.relax_inst = adjust_paritybit (backup_inst1.relax_inst, tmp);
+ }
+
+ /* Check data dependency. */
+ handle_dependency (&backup_inst1);
+
+ /* Start a new frag if frag_now is not empty and is not instruction frag, maybe it contains
+ data produced by .ascii etc. Doing this is to make one instruction per frag. */
+ if (frag_now_fix () != 0)
+ {
+ if (!frag_now->tc_frag_data.is_insn)
+ frag_wane (frag_now);
+
+ frag_new (0);
+ }
+
+ /* Here, we must call frag_grow in order to keep the instruction frag type is
+ rs_machine_dependent.
+ For, frag_var may change frag_now->fr_type to rs_fill by calling frag_grow which
+ acturally will call frag_wane.
+ Calling frag_grow first will create a new frag_now which free size is 20 that is enough
+ for frag_var. */
+ frag_grow (20);
+
+ p = frag_more (backup_inst1.size);
+ md_number_to_chars (p, backup_inst1.instruction, backup_inst1.size);
+
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (backup_inst1.size);
+#endif
+
+ /* Generate fixup structure. */
+ if (pce_p)
+ {
+ if (inst1->reloc.type != BFD_RELOC_NONE)
+ fix_new_score (frag_now, p - frag_now->fr_literal,
+ inst1->size, &inst1->reloc.exp,
+ inst1->reloc.pc_rel, inst1->reloc.type);
+
+ if (inst2->reloc.type != BFD_RELOC_NONE)
+ fix_new_score (frag_now, p - frag_now->fr_literal + 2,
+ inst2->size, &inst2->reloc.exp, inst2->reloc.pc_rel, inst2->reloc.type);
+ }
+ else
+ {
+ if (backup_inst1.reloc.type != BFD_RELOC_NONE)
+ fix_new_score (frag_now, p - frag_now->fr_literal,
+ backup_inst1.size, &backup_inst1.reloc.exp,
+ backup_inst1.reloc.pc_rel, backup_inst1.reloc.type);
+ }
+
+ /* relax_size may be 2, 4, 12 or 0, 0 indicates no relaxation. */
+ relaxable_p &= (backup_inst1.relax_size != 0);
+ relax_size = relaxable_p ? backup_inst1.relax_size : 0;
+
+ p = frag_var (rs_machine_dependent, relax_size + RELAX_PAD_BYTE, 0,
+ RELAX_ENCODE (backup_inst1.size, backup_inst1.relax_size,
+ backup_inst1.type, 0, 0, relaxable_p),
+ backup_inst1.reloc.exp.X_add_symbol, 0, NULL);
+
+ if (relaxable_p)
+ md_number_to_chars (p, backup_inst1.relax_inst, relax_size);
+
+ memcpy (inst1, &backup_inst1, sizeof (struct score_it));
+}
+
+static void
+parse_16_32_inst (char *insnstr, bfd_boolean gen_frag_p)
+{
+ char c;
+ char *p;
+ char *operator = insnstr;
+ const struct asm_opcode *opcode;
+
+ /* Parse operator and operands. */
+ skip_whitespace (operator);
+
+ for (p = operator; *p != '\0'; p++)
+ if ((*p == ' ') || (*p == '!'))
+ break;
+
+ if (*p == '!')
+ p++;
+
+ c = *p;
+ *p = '\0';
+
+ opcode = (const struct asm_opcode *) hash_find (score_ops_hsh, operator);
+ *p = c;
+
+ memset (&inst, '\0', sizeof (inst));
+ sprintf (inst.str, "%s", insnstr);
+ if (opcode)
+ {
+ inst.instruction = opcode->value;
+ inst.relax_inst = opcode->relax_value;
+ inst.type = opcode->type;
+ inst.size = GET_INSN_SIZE (inst.type);
+ inst.relax_size = 0;
+ inst.bwarn = 0;
+ sprintf (inst.name, "%s", opcode->template);
+ strcpy (inst.reg, "");
+ inst.error = NULL;
+ inst.reloc.type = BFD_RELOC_NONE;
+
+ (*opcode->parms) (p);
+
+ /* It indicates current instruction is a macro instruction if inst.bwarn equals -1. */
+ if ((inst.bwarn != -1) && (!inst.error) && (gen_frag_p))
+ gen_insn_frag (&inst, NULL);
+ }
+ else
+ inst.error = _("unrecognized opcode");
+}
+
+static int
+append_insn (char *str, bfd_boolean gen_frag_p)
+{
+ int retval = SUCCESS;
+
+ parse_16_32_inst (str, gen_frag_p);
+
+ if (inst.error)
+ {
+ retval = (int) FAIL;
+ as_bad ("%s -- `%s'", inst.error, inst.str);
+ inst.error = NULL;
+ }
+
+ return retval;
+}
+
+/* Handle mv! reg_high, reg_low;
+ mv! reg_low, reg_high;
+ mv! reg_low, reg_low; */
+static void
+do16_mv_rdrs (char *str)
+{
+ int reg_rd;
+ int reg_rs;
+ char *backupstr = NULL;
+
+ backupstr = str;
+ skip_whitespace (str);
+
+ if ((reg_rd = reg_required_here (&str, 8, REG_TYPE_SCORE)) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || (reg_rs = reg_required_here (&str, 4, REG_TYPE_SCORE)) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ /* Case 1 : mv! or mlfh!. */
+ if (reg_rd < 16)
+ {
+ if (reg_rs < 16)
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 4) & 0xf) << 15) | (0xf << 10);
+ inst.relax_size = 4;
+ }
+ else
+ {
+ char append_str[MAX_LITERAL_POOL_SIZE];
+
+ sprintf (append_str, "mlfh! %s", backupstr);
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ }
+ /* Case 2 : mhfl!. */
+ else
+ {
+ if (reg_rs > 16)
+ {
+ SET_INSN_ERROR (BAD_ARGS);
+ return;
+ }
+ else
+ {
+ char append_str[MAX_LITERAL_POOL_SIZE];
+
+ sprintf (append_str, "mhfl! %s", backupstr);
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ }
+ }
+}
+
+static void
+do16_rdi4 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reglow_required_here (&str, 8) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 3, _IMM4) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ if (((inst.instruction >> 3) & 0x10) == 0) /* for judge is addei or subei : bit 5 =0 : addei */
+ {
+ if (((inst.instruction >> 3) & 0xf) != 0xf)
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | ((1 << ((inst.instruction >> 3) & 0xf)) << 1);
+ inst.relax_size = 4;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ if (((inst.instruction >> 3) & 0xf) != 0xf)
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((-(1 << ((inst.instruction >> 3) & 0xf))) & 0xffff) << 1);
+ inst.relax_size = 4;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ }
+}
+
+static void
+do16_rdi5 (char *str)
+{
+ skip_whitespace (str);
+
+ if (reglow_required_here (&str, 8) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || data_op2 (&str, 3, _IMM5) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 8) & 0xf) << 15) | (((inst.instruction >> 3) & 0x1f) << 10);
+ inst.relax_size = 4;
+ }
+}
+
+/* Handle sdbbp. */
+static void
+do16_xi5 (char *str)
+{
+ skip_whitespace (str);
+
+ if (data_op2 (&str, 3, _IMM5) == (int) FAIL || end_of_line (str) == (int) FAIL)
+ return;
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 3) & 0x1f) << 15);
+ inst.relax_size = 4;
+ }
+}
+
+/* Check that an immediate is word alignment or half word alignment.
+ If so, convert it to the right format. */
+static int
+validate_immediate_align (int val, unsigned int data_type)
+{
+ if (data_type == _IMM5_RSHIFT_1)
+ {
+ if (val % 2)
+ {
+ inst.error = _("address offset must be half word alignment");
+ return (int) FAIL;
+ }
+ }
+ else if ((data_type == _IMM5_RSHIFT_2) || (data_type == _IMM10_RSHIFT_2))
+ {
+ if (val % 4)
+ {
+ inst.error = _("address offset must be word alignment");
+ return (int) FAIL;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static int
+exp_ldst_offset (char **str, int shift, unsigned int data_type)
+{
+ char *dataptr;
+
+ dataptr = * str;
+
+ if ((*dataptr == '0') && (*(dataptr + 1) == 'x')
+ && (data_type != _SIMM16_LA)
+ && (data_type != _VALUE_HI16)
+ && (data_type != _VALUE_LO16)
+ && (data_type != _IMM16)
+ && (data_type != _IMM15)
+ && (data_type != _IMM14)
+ && (data_type != _IMM4)
+ && (data_type != _IMM5)
+ && (data_type != _IMM8)
+ && (data_type != _IMM5_RSHIFT_1)
+ && (data_type != _IMM5_RSHIFT_2)
+ && (data_type != _SIMM14_NEG)
+ && (data_type != _IMM10_RSHIFT_2))
+ {
+ data_type += 24;
+ }
+
+ if (my_get_expression (&inst.reloc.exp, str) == (int) FAIL)
+ return (int) FAIL;
+
+ if (inst.reloc.exp.X_op == O_constant)
+ {
+ /* Need to check the immediate align. */
+ int value = validate_immediate_align (inst.reloc.exp.X_add_number, data_type);
+
+ if (value == (int) FAIL)
+ return (int) FAIL;
+
+ value = validate_immediate (inst.reloc.exp.X_add_number, data_type);
+ if (value == (int) FAIL)
+ {
+ char err_msg[255];
+
+ if (data_type < 30)
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type].bits,
+ score_df_range[data_type].range[0], score_df_range[data_type].range[1]);
+ else
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type - 24].bits,
+ score_df_range[data_type - 24].range[0], score_df_range[data_type - 24].range[1]);
+ inst.error = _(err_msg);
+ return (int) FAIL;
+ }
+
+ if (data_type == _IMM5_RSHIFT_1)
+ {
+ value >>= 1;
+ }
+ else if ((data_type == _IMM5_RSHIFT_2) || (data_type == _IMM10_RSHIFT_2))
+ {
+ value >>= 2;
+ }
+
+ if (score_df_range[data_type].range[0] != 0)
+ {
+ value &= (1 << score_df_range[data_type].bits) - 1;
+ }
+
+ inst.instruction |= value << shift;
+ }
+ else
+ {
+ inst.reloc.pc_rel = 0;
+ }
+
+ return SUCCESS;
+}
+
+static void
+do_ldst_insn (char *str)
+{
+ int pre_inc = 0;
+ int conflict_reg;
+ int value;
+ char * temp;
+ char *strbak;
+ char *dataptr;
+ int reg;
+ int ldst_idx = 0;
+
+ strbak = str;
+ skip_whitespace (str);
+
+ if (((conflict_reg = reg_required_here (&str, 20, REG_TYPE_SCORE)) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ return;
+
+ /* ld/sw rD, [rA, simm15] ld/sw rD, [rA]+, simm12 ld/sw rD, [rA, simm12]+. */
+ if (*str == '[')
+ {
+ str++;
+ skip_whitespace (str);
+
+ if ((reg = reg_required_here (&str, 15, REG_TYPE_SCORE)) == (int) FAIL)
+ return;
+
+ /* Conflicts can occur on stores as well as loads. */
+ conflict_reg = (conflict_reg == reg);
+ skip_whitespace (str);
+ temp = str + 1; /* The latter will process decimal/hex expression. */
+
+ /* ld/sw rD, [rA]+, simm12 ld/sw rD, [rA]+. */
+ if (*str == ']')
+ {
+ str++;
+ if (*str == '+')
+ {
+ str++;
+ /* ld/sw rD, [rA]+, simm12. */
+ if (skip_past_comma (&str) == SUCCESS)
+ {
+ if ((exp_ldst_offset (&str, 3, _SIMM12) == (int) FAIL)
+ || (end_of_line (str) == (int) FAIL))
+ return;
+
+ if (conflict_reg)
+ {
+ unsigned int ldst_func = inst.instruction & OPC_PSEUDOLDST_MASK;
+
+ if ((ldst_func == INSN_LH)
+ || (ldst_func == INSN_LHU)
+ || (ldst_func == INSN_LW)
+ || (ldst_func == INSN_LB)
+ || (ldst_func == INSN_LBU))
+ {
+ inst.error = _("register same as write-back base");
+ return;
+ }
+ }
+
+ ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+ inst.instruction &= ~OPC_PSEUDOLDST_MASK;
+ inst.instruction |= score_ldst_insns[ldst_idx * 3 + LDST_POST].value;
+
+ /* lw rD, [rA]+, 4 convert to pop rD, [rA]. */
+ if ((inst.instruction & 0x3e000007) == 0x0e000000)
+ {
+ /* rs = r0-r7, offset = 4 */
+ if ((((inst.instruction >> 15) & 0x18) == 0)
+ && (((inst.instruction >> 3) & 0xfff) == 4))
+ {
+ /* Relax to pophi. */
+ if ((((inst.instruction >> 20) & 0x10) == 0x10))
+ {
+ inst.relax_inst = 0x0000200a | (((inst.instruction >> 20) & 0xf)
+ << 8) | 1 << 7 |
+ (((inst.instruction >> 15) & 0x7) << 4);
+ }
+ /* Relax to pop. */
+ else
+ {
+ inst.relax_inst = 0x0000200a | (((inst.instruction >> 20) & 0xf)
+ << 8) | 0 << 7 |
+ (((inst.instruction >> 15) & 0x7) << 4);
+ }
+ inst.relax_size = 2;
+ }
+ }
+ return;
+ }
+ /* ld/sw rD, [rA]+ convert to ld/sw rD, [rA, 0]+. */
+ else
+ {
+ SET_INSN_ERROR (NULL);
+ if (end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+
+ pre_inc = 1;
+ value = validate_immediate (inst.reloc.exp.X_add_number, _SIMM12);
+ value &= (1 << score_df_range[_SIMM12].bits) - 1;
+ ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+ inst.instruction &= ~OPC_PSEUDOLDST_MASK;
+ inst.instruction |= score_ldst_insns[ldst_idx * 3 + pre_inc].value;
+ inst.instruction |= value << 3;
+ inst.relax_inst = 0x8000;
+ return;
+ }
+ }
+ /* ld/sw rD, [rA] convert to ld/sw rD, [rA, simm15]. */
+ else
+ {
+ if (end_of_line (str) == (int) FAIL)
+ return;
+
+ ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+ inst.instruction &= ~OPC_PSEUDOLDST_MASK;
+ inst.instruction |= score_ldst_insns[ldst_idx * 3 + LDST_NOUPDATE].value;
+
+ /* lbu rd, [rs] -> lbu! rd, [rs] */
+ if (ldst_idx == INSN_LBU)
+ {
+ inst.relax_inst = INSN16_LBU;
+ }
+ else if (ldst_idx == INSN_LH)
+ {
+ inst.relax_inst = INSN16_LH;
+ }
+ else if (ldst_idx == INSN_LW)
+ {
+ inst.relax_inst = INSN16_LW;
+ }
+ else if (ldst_idx == INSN_SB)
+ {
+ inst.relax_inst = INSN16_SB;
+ }
+ else if (ldst_idx == INSN_SH)
+ {
+ inst.relax_inst = INSN16_SH;
+ }
+ else if (ldst_idx == INSN_SW)
+ {
+ inst.relax_inst = INSN16_SW;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+
+ /* lw/lh/lbu/sw/sh/sb, offset = 0, relax to 16 bit instruction. */
+ if ((ldst_idx == INSN_LBU)
+ || (ldst_idx == INSN_LH)
+ || (ldst_idx == INSN_LW)
+ || (ldst_idx == INSN_SB) || (ldst_idx == INSN_SH) || (ldst_idx == INSN_SW))
+ {
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ inst.relax_inst |= (2 << 12) | (((inst.instruction >> 20) & 0xf) << 8) |
+ (((inst.instruction >> 15) & 0xf) << 4);
+ inst.relax_size = 2;
+ }
+ }
+
+ return;
+ }
+ }
+ /* ld/sw rD, [rA, simm15] ld/sw rD, [rA, simm12]+. */
+ else
+ {
+ if (skip_past_comma (&str) == (int) FAIL)
+ {
+ inst.error = _("pre-indexed expression expected");
+ return;
+ }
+
+ if (my_get_expression (&inst.reloc.exp, &str) == (int) FAIL)
+ return;
+
+ skip_whitespace (str);
+ if (*str++ != ']')
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+
+ skip_whitespace (str);
+ /* ld/sw rD, [rA, simm12]+. */
+ if (*str == '+')
+ {
+ str++;
+ pre_inc = 1;
+ if (conflict_reg)
+ {
+ unsigned int ldst_func = inst.instruction & OPC_PSEUDOLDST_MASK;
+
+ if ((ldst_func == INSN_LH)
+ || (ldst_func == INSN_LHU)
+ || (ldst_func == INSN_LW)
+ || (ldst_func == INSN_LB)
+ || (ldst_func == INSN_LBU))
+ {
+ inst.error = _("register same as write-back base");
+ return;
+ }
+ }
+ }
+
+ if (end_of_line (str) == (int) FAIL)
+ return;
+
+ if (inst.reloc.exp.X_op == O_constant)
+ {
+ int value;
+ unsigned int data_type;
+
+ if (pre_inc == 1)
+ data_type = _SIMM12;
+ else
+ data_type = _SIMM15;
+ dataptr = temp;
+
+ if ((*dataptr == '0') && (*(dataptr + 1) == 'x')
+ && (data_type != _SIMM16_LA)
+ && (data_type != _VALUE_HI16)
+ && (data_type != _VALUE_LO16)
+ && (data_type != _IMM16)
+ && (data_type != _IMM15)
+ && (data_type != _IMM14)
+ && (data_type != _IMM4)
+ && (data_type != _IMM5)
+ && (data_type != _IMM8)
+ && (data_type != _IMM5_RSHIFT_1)
+ && (data_type != _IMM5_RSHIFT_2)
+ && (data_type != _SIMM14_NEG)
+ && (data_type != _IMM10_RSHIFT_2))
+ {
+ data_type += 24;
+ }
+
+ value = validate_immediate (inst.reloc.exp.X_add_number, data_type);
+ if (value == (int) FAIL)
+ {
+ char err_msg[255];
+
+ if (data_type < 27)
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type].bits,
+ score_df_range[data_type].range[0], score_df_range[data_type].range[1]);
+ else
+ sprintf (err_msg,
+ "invalid constant: %d bit expression not in range %d..%d",
+ score_df_range[data_type - 21].bits,
+ score_df_range[data_type - 21].range[0],
+ score_df_range[data_type - 21].range[1]);
+ inst.error = _(err_msg);
+ return;
+ }
+
+ value &= (1 << score_df_range[data_type].bits) - 1;
+ ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+ inst.instruction &= ~OPC_PSEUDOLDST_MASK;
+ inst.instruction |= score_ldst_insns[ldst_idx * 3 + pre_inc].value;
+ if (pre_inc == 1)
+ inst.instruction |= value << 3;
+ else
+ inst.instruction |= value;
+
+ /* lw rD, [rA, simm15] */
+ if ((inst.instruction & 0x3e000000) == 0x20000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0)
+ && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, lw -> lw!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, lw -> lwp!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x3) == 0)
+ && ((inst.instruction & 0x7fff) < 128))
+ {
+ inst.relax_inst = 0x7000 | (((inst.instruction >> 20) & 0xf) << 8)
+ | (((inst.instruction & 0x7fff) >> 2) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* sw rD, [rA, simm15] */
+ else if ((inst.instruction & 0x3e000000) == 0x28000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, sw -> sw!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, sw -> swp!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x3) == 0)
+ && ((inst.instruction & 0x7fff) < 128))
+ {
+ inst.relax_inst = 0x7004 | (((inst.instruction >> 20) & 0xf) << 8)
+ | (((inst.instruction & 0x7fff) >> 2) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* sw rD, [rA, simm15]+ sw pre. */
+ else if ((inst.instruction & 0x3e000007) == 0x06000004)
+ {
+ /* rA is in [r0 - r7], and simm15 = -4. */
+ if ((((inst.instruction >> 15) & 0x18) == 0)
+ && (((inst.instruction >> 3) & 0xfff) == 0xffc))
+ {
+ /* sw -> pushhi!. */
+ if ((((inst.instruction >> 20) & 0x10) == 0x10))
+ {
+ inst.relax_inst = 0x0000200e | (((inst.instruction >> 20) & 0xf) << 8)
+ | 1 << 7 | (((inst.instruction >> 15) & 0x7) << 4);
+ inst.relax_size = 2;
+ }
+ /* sw -> push!. */
+ else
+ {
+ inst.relax_inst = 0x0000200e | (((inst.instruction >> 20) & 0xf) << 8)
+ | 0 << 7 | (((inst.instruction >> 15) & 0x7) << 4);
+ inst.relax_size = 2;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* lh rD, [rA, simm15] */
+ else if ((inst.instruction & 0x3e000000) == 0x22000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, lh -> lh!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, lh -> lhp!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x1) == 0)
+ && ((inst.instruction & 0x7fff) < 64))
+ {
+ inst.relax_inst = 0x7001 | (((inst.instruction >> 20) & 0xf) << 8)
+ | (((inst.instruction & 0x7fff) >> 1) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* sh rD, [rA, simm15] */
+ else if ((inst.instruction & 0x3e000000) == 0x2a000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, sh -> sh!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, sh -> shp!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x1) == 0)
+ && ((inst.instruction & 0x7fff) < 64))
+ {
+ inst.relax_inst = 0x7005 | (((inst.instruction >> 20) & 0xf) << 8)
+ | (((inst.instruction & 0x7fff) >> 1) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* lbu rD, [rA, simm15] */
+ else if ((inst.instruction & 0x3e000000) == 0x2c000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, lbu -> lbu!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, lbu -> lbup!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x7fff) < 32))
+ {
+ inst.relax_inst = 0x7003 | (((inst.instruction >> 20) & 0xf) << 8)
+ | ((inst.instruction & 0x7fff) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ /* sb rD, [rA, simm15] */
+ else if ((inst.instruction & 0x3e000000) == 0x2e000000)
+ {
+ /* Both rD and rA are in [r0 - r15]. */
+ if ((((inst.instruction >> 15) & 0x10) == 0) && (((inst.instruction >> 20) & 0x10) == 0))
+ {
+ /* simm15 = 0, sb -> sb!. */
+ if ((inst.instruction & 0x7fff) == 0)
+ {
+ inst.relax_inst |= (((inst.instruction >> 15) & 0xf) << 4)
+ | (((inst.instruction >> 20) & 0xf) << 8);
+ inst.relax_size = 2;
+ }
+ /* rA = r2, sb -> sb!. */
+ else if ((((inst.instruction >> 15) & 0xf) == 2)
+ && ((inst.instruction & 0x7fff) < 32))
+ {
+ inst.relax_inst = 0x7007 | (((inst.instruction >> 20) & 0xf) << 8)
+ | ((inst.instruction & 0x7fff) << 3);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+
+ return;
+ }
+ else
+ {
+ /* FIXME: may set error, for there is no ld/sw rD, [rA, label] */
+ inst.reloc.pc_rel = 0;
+ }
+ }
+ }
+ else
+ {
+ inst.error = BAD_ARGS;
+ }
+}
+
+/* Handle cache. */
+
+static void
+do_cache (char *str)
+{
+ skip_whitespace (str);
+
+ if ((data_op2 (&str, 20, _IMM5) == (int) FAIL) || (skip_past_comma (&str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ int cache_op;
+
+ cache_op = (inst.instruction >> 20) & 0x1F;
+ sprintf (inst.name, "cache %d", cache_op);
+ }
+
+ if (*str == '[')
+ {
+ str++;
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL)
+ return;
+
+ skip_whitespace (str);
+
+ /* cache op, [rA] */
+ if (skip_past_comma (&str) == (int) FAIL)
+ {
+ SET_INSN_ERROR (NULL);
+ if (*str != ']')
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+ str++;
+ }
+ /* cache op, [rA, simm15] */
+ else
+ {
+ if (exp_ldst_offset (&str, 0, _SIMM15) == (int) FAIL)
+ {
+ return;
+ }
+
+ skip_whitespace (str);
+ if (*str++ != ']')
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+ }
+
+ if (end_of_line (str) == (int) FAIL)
+ return;
+ }
+ else
+ {
+ inst.error = BAD_ARGS;
+ }
+}
+
+static void
+do_crdcrscrsimm5 (char *str)
+{
+ char *strbak;
+
+ strbak = str;
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE_CR) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 15, REG_TYPE_SCORE_CR) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL
+ || reg_required_here (&str, 10, REG_TYPE_SCORE_CR) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL)
+ {
+ str = strbak;
+ /* cop1 cop_code20. */
+ if (data_op2 (&str, 5, _IMM20) == (int) FAIL)
+ return;
+ }
+ else
+ {
+ if (data_op2 (&str, 5, _IMM5) == (int) FAIL)
+ return;
+ }
+
+ end_of_line (str);
+}
+
+/* Handle ldc/stc. */
+static void
+do_ldst_cop (char *str)
+{
+ skip_whitespace (str);
+
+ if ((reg_required_here (&str, 15, REG_TYPE_SCORE_CR) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ return;
+
+ if (*str == '[')
+ {
+ str++;
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL)
+ return;
+
+ skip_whitespace (str);
+
+ if (*str++ != ']')
+ {
+ if (exp_ldst_offset (&str, 5, _IMM10_RSHIFT_2) == (int) FAIL)
+ return;
+
+ skip_whitespace (str);
+ if (*str++ != ']')
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+ }
+
+ end_of_line (str);
+ }
+ else
+ inst.error = BAD_ARGS;
+}
+
+static void
+do16_ldst_insn (char *str)
+{
+ skip_whitespace (str);
+
+ if ((reglow_required_here (&str, 8) == (int) FAIL) || (skip_past_comma (&str) == (int) FAIL))
+ return;
+
+ if (*str == '[')
+ {
+ int reg;
+
+ str++;
+ skip_whitespace (str);
+
+ if ((reg = reglow_required_here (&str, 4)) == (int) FAIL)
+ return;
+
+ skip_whitespace (str);
+ if (*str++ == ']')
+ {
+ if (end_of_line (str) == (int) FAIL)
+ return;
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 4) & 0xf) << 15);
+ inst.relax_size = 4;
+ }
+ }
+ else
+ {
+ inst.error = _("missing ]");
+ }
+ }
+ else
+ {
+ inst.error = BAD_ARGS;
+ }
+}
+
+/* Handle lbup!/lhp!/ldiu!/lwp!/sbp!/shp!/swp!. */
+static void
+do16_ldst_imm_insn (char *str)
+{
+ char data_exp[MAX_LITERAL_POOL_SIZE];
+ int reg_rd;
+ char *dataptr = NULL, *pp = NULL;
+ int cnt = 0;
+ int assign_data = (int) FAIL;
+ unsigned int ldst_func;
+
+ skip_whitespace (str);
+
+ if (((reg_rd = reglow_required_here (&str, 8)) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ return;
+
+ skip_whitespace (str);
+ dataptr = str;
+
+ while ((*dataptr != '\0') && (*dataptr != '|') && (cnt <= MAX_LITERAL_POOL_SIZE))
+ {
+ data_exp[cnt] = *dataptr;
+ dataptr++;
+ cnt++;
+ }
+
+ data_exp[cnt] = '\0';
+ pp = &data_exp[0];
+
+ str = dataptr;
+
+ ldst_func = inst.instruction & LDST16_RI_MASK;
+ if (ldst_func == N16_LIU)
+ assign_data = exp_ldst_offset (&pp, 0, _IMM8);
+ else if (ldst_func == N16_LHP || ldst_func == N16_SHP)
+ assign_data = exp_ldst_offset (&pp, 3, _IMM5_RSHIFT_1);
+ else if (ldst_func == N16_LWP || ldst_func == N16_SWP)
+ assign_data = exp_ldst_offset (&pp, 3, _IMM5_RSHIFT_2);
+ else
+ assign_data = exp_ldst_offset (&pp, 3, _IMM5);
+
+ if ((assign_data == (int) FAIL) || (end_of_line (pp) == (int) FAIL))
+ return;
+ else
+ {
+ if ((inst.instruction & 0x7000) == N16_LIU)
+ {
+ inst.relax_inst |= ((inst.instruction >> 8) & 0xf) << 20
+ | ((inst.instruction & 0xff) << 1);
+ }
+ else if (((inst.instruction & 0x7007) == N16_LHP)
+ || ((inst.instruction & 0x7007) == N16_SHP))
+ {
+ inst.relax_inst |= ((inst.instruction >> 8) & 0xf) << 20 | 2 << 15
+ | (((inst.instruction >> 3) & 0x1f) << 1);
+ }
+ else if (((inst.instruction & 0x7007) == N16_LWP)
+ || ((inst.instruction & 0x7007) == N16_SWP))
+ {
+ inst.relax_inst |= ((inst.instruction >> 8) & 0xf) << 20 | 2 << 15
+ | (((inst.instruction >> 3) & 0x1f) << 2);
+ }
+ else if (((inst.instruction & 0x7007) == N16_LBUP)
+ || ((inst.instruction & 0x7007) == N16_SBP))
+ {
+ inst.relax_inst |= ((inst.instruction >> 8) & 0xf) << 20 | 2 << 15
+ | (((inst.instruction >> 3) & 0x1f));
+ }
+
+ inst.relax_size = 4;
+ }
+}
+
+static void
+do16_push_pop (char *str)
+{
+ int reg_rd;
+ int H_bit_mask = 0;
+
+ skip_whitespace (str);
+ if (((reg_rd = reg_required_here (&str, 8, REG_TYPE_SCORE)) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ return;
+
+ if (reg_rd >= 16)
+ H_bit_mask = 1;
+
+ /* reg_required_here will change bit 12 of opcode, so we must restore bit 12. */
+ inst.instruction &= ~(1 << 12);
+
+ inst.instruction |= H_bit_mask << 7;
+
+ if (*str == '[')
+ {
+ int reg;
+
+ str++;
+ skip_whitespace (str);
+ if ((reg = reg_required_here (&str, 4, REG_TYPE_SCORE)) == (int) FAIL)
+ return;
+ else if (reg > 7)
+ {
+ if (!inst.error)
+ inst.error = _("base register nums are over 3 bit");
+
+ return;
+ }
+
+ skip_whitespace (str);
+ if ((*str++ != ']') || (end_of_line (str) == (int) FAIL))
+ {
+ if (!inst.error)
+ inst.error = _("missing ]");
+
+ return;
+ }
+
+ /* pop! */
+ if ((inst.instruction & 0xf) == 0xa)
+ {
+ if (H_bit_mask)
+ {
+ inst.relax_inst |= ((((inst.instruction >> 8) & 0xf) | 0x10) << 20)
+ | (((inst.instruction >> 4) & 0x7) << 15) | (4 << 3);
+ }
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 4) & 0x7) << 15) | (4 << 3);
+ }
+ }
+ /* push! */
+ else
+ {
+ if (H_bit_mask)
+ {
+ inst.relax_inst |= ((((inst.instruction >> 8) & 0xf) | 0x10) << 20)
+ | (((inst.instruction >> 4) & 0x7) << 15) | (((-4) & 0xfff) << 3);
+ }
+ else
+ {
+ inst.relax_inst |= (((inst.instruction >> 8) & 0xf) << 20)
+ | (((inst.instruction >> 4) & 0x7) << 15) | (((-4) & 0xfff) << 3);
+ }
+ }
+ inst.relax_size = 4;
+ }
+ else
+ {
+ inst.error = BAD_ARGS;
+ }
+}
+
+/* Handle lcb/lcw/lce/scb/scw/sce. */
+static void
+do_ldst_unalign (char *str)
+{
+ int conflict_reg;
+
+ if (university_version == 1)
+ {
+ inst.error = ERR_FOR_SCORE5U_ATOMIC;
+ return;
+ }
+
+ skip_whitespace (str);
+
+ /* lcb/scb [rA]+. */
+ if (*str == '[')
+ {
+ str++;
+ skip_whitespace (str);
+
+ if (reg_required_here (&str, 15, REG_TYPE_SCORE) == (int) FAIL)
+ return;
+
+ if (*str++ == ']')
+ {
+ if (*str++ != '+')
+ {
+ inst.error = _("missing +");
+ return;
+ }
+ }
+ else
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+
+ if (end_of_line (str) == (int) FAIL)
+ return;
+ }
+ /* lcw/lce/scb/sce rD, [rA]+. */
+ else
+ {
+ if (((conflict_reg = reg_required_here (&str, 20, REG_TYPE_SCORE)) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ {
+ return;
+ }
+
+ skip_whitespace (str);
+ if (*str++ == '[')
+ {
+ int reg;
+
+ skip_whitespace (str);
+ if ((reg = reg_required_here (&str, 15, REG_TYPE_SCORE)) == (int) FAIL)
+ {
+ return;
+ }
+
+ /* Conflicts can occur on stores as well as loads. */
+ conflict_reg = (conflict_reg == reg);
+ skip_whitespace (str);
+ if (*str++ == ']')
+ {
+ unsigned int ldst_func = inst.instruction & LDST_UNALIGN_MASK;
+
+ if (*str++ == '+')
+ {
+ if (conflict_reg)
+ {
+ as_warn (_("%s register same as write-back base"),
+ ((ldst_func & UA_LCE) || (ldst_func & UA_LCW)
+ ? _("destination") : _("source")));
+ }
+ }
+ else
+ {
+ inst.error = _("missing +");
+ return;
+ }
+
+ if (end_of_line (str) == (int) FAIL)
+ return;
+ }
+ else
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+ }
+ else
+ {
+ inst.error = BAD_ARGS;
+ return;
+ }
+ }
+}
+
+/* Handle alw/asw. */
+static void
+do_ldst_atomic (char *str)
+{
+ if (university_version == 1)
+ {
+ inst.error = ERR_FOR_SCORE5U_ATOMIC;
+ return;
+ }
+
+ skip_whitespace (str);
+
+ if ((reg_required_here (&str, 20, REG_TYPE_SCORE) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+
+ skip_whitespace (str);
+ if (*str++ == '[')
+ {
+ int reg;
+
+ skip_whitespace (str);
+ if ((reg = reg_required_here (&str, 15, REG_TYPE_SCORE)) == (int) FAIL)
+ {
+ return;
+ }
+
+ skip_whitespace (str);
+ if (*str++ != ']')
+ {
+ inst.error = _("missing ]");
+ return;
+ }
+
+ end_of_line (str);
+ }
+ else
+ inst.error = BAD_ARGS;
+ }
+}
+
+static void
+build_relax_frag (struct score_it fix_insts[RELAX_INST_NUM], int fix_num ATTRIBUTE_UNUSED,
+ struct score_it var_insts[RELAX_INST_NUM], int var_num,
+ symbolS *add_symbol)
+{
+ int i;
+ char *p;
+ fixS *fixp = NULL;
+ fixS *head_fixp = NULL;
+ long where;
+ struct score_it inst_main;
+
+ memcpy (&inst_main, &fix_insts[0], sizeof (struct score_it));
+
+ /* Adjust instruction opcode and to be relaxed instruction opcode. */
+ inst_main.instruction = adjust_paritybit (inst_main.instruction, GET_INSN_CLASS (inst_main.type));
+ inst_main.type = Insn_PIC;
+
+ for (i = 0; i < var_num; i++)
+ {
+ inst_main.relax_size += var_insts[i].size;
+ var_insts[i].instruction = adjust_paritybit (var_insts[i].instruction,
+ GET_INSN_CLASS (var_insts[i].type));
+ }
+
+ /* Check data dependency. */
+ handle_dependency (&inst_main);
+
+ /* Start a new frag if frag_now is not empty. */
+ if (frag_now_fix () != 0)
+ {
+ if (!frag_now->tc_frag_data.is_insn)
+ {
+ frag_wane (frag_now);
+ }
+ frag_new (0);
+ }
+ frag_grow (20);
+
+ /* Write fr_fix part. */
+ p = frag_more (inst_main.size);
+ md_number_to_chars (p, inst_main.instruction, inst_main.size);
+
+ if (inst_main.reloc.type != BFD_RELOC_NONE)
+ {
+ fixp = fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size,
+ &inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type);
+ }
+
+ head_fixp = xmalloc (sizeof (fixS *));
+ frag_now->tc_frag_data.fixp = head_fixp;
+
+ if (fixp)
+ {
+ head_fixp->fx_next = fixp;
+ head_fixp = head_fixp->fx_next;
+ }
+
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (inst_main.size);
+#endif
+
+ where = p - frag_now->fr_literal + inst_main.size;
+ for (i = 0; i < var_num; i++)
+ {
+ if (i > 0)
+ where += var_insts[i - 1].size;
+
+ if (var_insts[i].reloc.type != BFD_RELOC_NONE)
+ {
+ fixp = fix_new_score (frag_now, where, var_insts[i].size,
+ &var_insts[i].reloc.exp, var_insts[i].reloc.pc_rel,
+ var_insts[i].reloc.type);
+ if (fixp)
+ {
+ head_fixp->fx_next = fixp;
+ head_fixp = head_fixp->fx_next;
+ }
+ }
+ }
+
+ head_fixp = frag_now->tc_frag_data.fixp;
+ frag_now->tc_frag_data.fixp = head_fixp->fx_next;
+ free (head_fixp);
+
+ p = frag_var (rs_machine_dependent, inst_main.relax_size + RELAX_PAD_BYTE, 0,
+ RELAX_ENCODE (inst_main.size, inst_main.relax_size, inst_main.type,
+ 0, inst_main.size, 0), add_symbol, 0, NULL);
+
+ /* Write fr_var part.
+ no calling gen_insn_frag, no fixS will be generated. */
+ for (i = 0; i < var_num; i++)
+ {
+ md_number_to_chars (p, var_insts[i].instruction, var_insts[i].size);
+ p += var_insts[i].size;
+ }
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+}
+
+/* Build a relax frag for la instruction when generating PIC,
+ external symbol first and local symbol second. */
+
+static void
+build_la_pic (int reg_rd, expressionS exp)
+{
+ symbolS *add_symbol = exp.X_add_symbol;
+ offsetT add_number = exp.X_add_number;
+ struct score_it fix_insts[RELAX_INST_NUM];
+ struct score_it var_insts[RELAX_INST_NUM];
+ int fix_num = 0;
+ int var_num = 0;
+ char tmp[MAX_LITERAL_POOL_SIZE];
+ int r1_bak;
+
+ r1_bak = nor1;
+ nor1 = 0;
+
+ if (add_number == 0)
+ {
+ fix_num = 1;
+ var_num = 2;
+
+ /* Insn 1 and Insn 2 */
+ /* Fix part
+ For an external symbol: lw rD, <sym>($gp)
+ (BFD_RELOC_SCORE_GOT15 or BFD_RELOC_SCORE_CALL15) */
+ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ if (reg_rd == PIC_CALL_REG)
+ inst.reloc.type = BFD_RELOC_SCORE_CALL15;
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol :
+ lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15)
+ addi rD, <sym> (BFD_RELOC_GOT_LO16) */
+ inst.reloc.type = BFD_RELOC_SCORE_GOT15;
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[1], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+ }
+ else if (add_number >= -0x8000 && add_number <= 0x7fff)
+ {
+ /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */
+ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Insn 2 */
+ fix_num = 1;
+ var_num = 1;
+ /* Fix part
+ For an external symbol: addi rD, <constant> */
+ sprintf (tmp, "addi r%d, %d", reg_rd, (int)add_number);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol: addi rD, <sym>+<constant> (BFD_RELOC_GOT_LO16) */
+ sprintf (tmp, "addi_s_pic r%d, %s + %d", reg_rd, add_symbol->bsym->name, (int)add_number);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+ }
+ else
+ {
+ int hi = (add_number >> 16) & 0x0000FFFF;
+ int lo = add_number & 0x0000FFFF;
+
+ /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */
+ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Insn 2 */
+ fix_num = 1;
+ var_num = 1;
+ /* Fix part
+ For an external symbol: ldis r1, HI%<constant> */
+ sprintf (tmp, "ldis %s, %d", "r1", hi);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol: ldis r1, HI%<constant>
+ but, if lo is outof 16 bit, make hi plus 1 */
+ if ((lo < -0x8000) || (lo > 0x7fff))
+ {
+ hi += 1;
+ }
+ sprintf (tmp, "ldis_pic %s, %d", "r1", hi);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+
+ /* Insn 3 */
+ fix_num = 1;
+ var_num = 1;
+ /* Fix part
+ For an external symbol: ori r1, LO%<constant> */
+ sprintf (tmp, "ori %s, %d", "r1", lo);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol: addi r1, <sym>+LO%<constant> (BFD_RELOC_GOT_LO16) */
+ sprintf (tmp, "addi_u_pic %s, %s + %d", "r1", add_symbol->bsym->name, lo);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+
+ /* Insn 4: add rD, rD, r1 */
+ sprintf (tmp, "add r%d, r%d, %s", reg_rd, reg_rd, "r1");
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+
+ nor1 = r1_bak;
+}
+
+/* Handle la. */
+static void
+do_macro_la_rdi32 (char *str)
+{
+ int reg_rd;
+
+ skip_whitespace (str);
+ if ((reg_rd = reg_required_here (&str, 20, REG_TYPE_SCORE)) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ char append_str[MAX_LITERAL_POOL_SIZE];
+ char *keep_data = str;
+
+ /* la rd, simm16. */
+ if (data_op2 (&str, 1, _SIMM16_LA) != (int) FAIL)
+ {
+ end_of_line (str);
+ return;
+ }
+ /* la rd, imm32 or la rd, label. */
+ else
+ {
+ SET_INSN_ERROR (NULL);
+ str = keep_data;
+ if ((data_op2 (&str, 1, _VALUE_HI16) == (int) FAIL)
+ || (end_of_line (str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ if ((score_pic == NO_PIC) || (!inst.reloc.exp.X_add_symbol))
+ {
+ sprintf (append_str, "ld_i32hi r%d, %s", reg_rd, keep_data);
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+
+ sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+ }
+ else
+ {
+ assert (inst.reloc.exp.X_add_symbol);
+ build_la_pic (reg_rd, inst.reloc.exp);
+ }
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ }
+ }
+}
+
+/* Handle li. */
+static void
+do_macro_li_rdi32 (char *str){
+
+ int reg_rd;
+
+ skip_whitespace (str);
+ if ((reg_rd = reg_required_here (&str, 20, REG_TYPE_SCORE)) == (int) FAIL
+ || skip_past_comma (&str) == (int) FAIL)
+ {
+ return;
+ }
+ else
+ {
+ char *keep_data = str;
+
+ /* li rd, simm16. */
+ if (data_op2 (&str, 1, _SIMM16_LA) != (int) FAIL)
+ {
+ end_of_line (str);
+ return;
+ }
+ /* li rd, imm32. */
+ else
+ {
+ char append_str[MAX_LITERAL_POOL_SIZE];
+
+ str = keep_data;
+
+ if ((data_op2 (&str, 1, _VALUE_HI16) == (int) FAIL)
+ || (end_of_line (str) == (int) FAIL))
+ {
+ return;
+ }
+ else if (inst.reloc.exp.X_add_symbol)
+ {
+ inst.error = _("li rd label isn't correct instruction form");
+ return;
+ }
+ else
+ {
+ sprintf (append_str, "ld_i32hi r%d, %s", reg_rd, keep_data);
+
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+ else
+ {
+ sprintf (append_str, "ld_i32lo r%d, %s", reg_rd, keep_data);
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ }
+ }
+ }
+}
+
+/* Handle mul/mulu/div/divu/rem/remu. */
+static void
+do_macro_mul_rdrsrs (char *str)
+{
+ int reg_rd;
+ int reg_rs1;
+ int reg_rs2;
+ char *backupstr;
+ char append_str[MAX_LITERAL_POOL_SIZE];
+
+ if (university_version == 1)
+ as_warn ("%s", ERR_FOR_SCORE5U_MUL_DIV);
+
+ strcpy (append_str, str);
+ backupstr = append_str;
+ skip_whitespace (backupstr);
+ if (((reg_rd = reg_required_here (&backupstr, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ || (skip_past_comma (&backupstr) == (int) FAIL)
+ || ((reg_rs1 = reg_required_here (&backupstr, -1, REG_TYPE_SCORE)) == (int) FAIL))
+ {
+ inst.error = BAD_ARGS;
+ return;
+ }
+
+ if (skip_past_comma (&backupstr) == (int) FAIL)
+ {
+ /* rem/remu rA, rB is error format. */
+ if (strcmp (inst.name, "rem") == 0 || strcmp (inst.name, "remu") == 0)
+ {
+ SET_INSN_ERROR (BAD_ARGS);
+ }
+ else
+ {
+ SET_INSN_ERROR (NULL);
+ do_rsrs (str);
+ }
+ return;
+ }
+ else
+ {
+ SET_INSN_ERROR (NULL);
+ if (((reg_rs2 = reg_required_here (&backupstr, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ || (end_of_line (backupstr) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ char append_str1[MAX_LITERAL_POOL_SIZE];
+
+ if (strcmp (inst.name, "rem") == 0)
+ {
+ sprintf (append_str, "%s r%d, r%d", "mul", reg_rs1, reg_rs2);
+ sprintf (append_str1, "mfceh r%d", reg_rd);
+ }
+ else if (strcmp (inst.name, "remu") == 0)
+ {
+ sprintf (append_str, "%s r%d, r%d", "mulu", reg_rs1, reg_rs2);
+ sprintf (append_str1, "mfceh r%d", reg_rd);
+ }
+ else
+ {
+ sprintf (append_str, "%s r%d, r%d", inst.name, reg_rs1, reg_rs2);
+ sprintf (append_str1, "mfcel r%d", reg_rd);
+ }
+
+ /* Output mul/mulu or div/divu or rem/remu. */
+ if (append_insn (append_str, TRUE) == (int) FAIL)
+ return;
+
+ /* Output mfcel or mfceh. */
+ if (append_insn (append_str1, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ }
+}
+
+static void
+exp_macro_ldst_abs (char *str)
+{
+ int reg_rd;
+ char *backupstr, *tmp;
+ char append_str[MAX_LITERAL_POOL_SIZE];
+ char verifystr[MAX_LITERAL_POOL_SIZE];
+ struct score_it inst_backup;
+ int r1_bak = 0;
+
+ r1_bak = nor1;
+ nor1 = 0;
+ memcpy (&inst_backup, &inst, sizeof (struct score_it));
+
+ strcpy (verifystr, str);
+ backupstr = verifystr;
+ skip_whitespace (backupstr);
+ if ((reg_rd = reg_required_here (&backupstr, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ return;
+
+ tmp = backupstr;
+ if (skip_past_comma (&backupstr) == (int) FAIL)
+ return;
+
+ backupstr = tmp;
+ sprintf (append_str, "li r1 %s", backupstr);
+ append_insn (append_str, TRUE);
+
+ memcpy (&inst, &inst_backup, sizeof (struct score_it));
+ sprintf (append_str, " r%d, [r1,0]", reg_rd);
+ do_ldst_insn (append_str);
+
+ nor1 = r1_bak;
+}
+
+static int
+nopic_need_relax (symbolS * sym, int before_relaxing)
+{
+ if (sym == NULL)
+ return 0;
+ else if (USE_GLOBAL_POINTER_OPT && g_switch_value > 0)
+ {
+ const char *symname;
+ const char *segname;
+
+ /* Find out whether this symbol can be referenced off the $gp
+ register. It can be if it is smaller than the -G size or if
+ it is in the .sdata or .sbss section. Certain symbols can
+ not be referenced off the $gp, although it appears as though
+ they can. */
+ symname = S_GET_NAME (sym);
+ if (symname != (const char *)NULL
+ && (strcmp (symname, "eprol") == 0
+ || strcmp (symname, "etext") == 0
+ || strcmp (symname, "_gp") == 0
+ || strcmp (symname, "edata") == 0
+ || strcmp (symname, "_fbss") == 0
+ || strcmp (symname, "_fdata") == 0
+ || strcmp (symname, "_ftext") == 0
+ || strcmp (symname, "end") == 0
+ || strcmp (symname, GP_DISP_LABEL) == 0))
+ {
+ return 1;
+ }
+ else if ((!S_IS_DEFINED (sym) || S_IS_COMMON (sym)) && (0
+ /* We must defer this decision until after the whole file has been read,
+ since there might be a .extern after the first use of this symbol. */
+ || (before_relaxing
+ && S_GET_VALUE (sym) == 0)
+ || (S_GET_VALUE (sym) != 0
+ && S_GET_VALUE (sym) <= g_switch_value)))
+ {
+ return 0;
+ }
+
+ segname = segment_name (S_GET_SEGMENT (sym));
+ return (strcmp (segname, ".sdata") != 0
+ && strcmp (segname, ".sbss") != 0
+ && strncmp (segname, ".sdata.", 7) != 0
+ && strncmp (segname, ".gnu.linkonce.s.", 16) != 0);
+ }
+ /* We are not optimizing for the $gp register. */
+ else
+ return 1;
+}
+
+/* Build a relax frag for lw instruction when generating PIC,
+ external symbol first and local symbol second. */
+
+static void
+build_lw_pic (int reg_rd, expressionS exp)
+{
+ symbolS *add_symbol = exp.X_add_symbol;
+ int add_number = exp.X_add_number;
+ struct score_it fix_insts[RELAX_INST_NUM];
+ struct score_it var_insts[RELAX_INST_NUM];
+ int fix_num = 0;
+ int var_num = 0;
+ char tmp[MAX_LITERAL_POOL_SIZE];
+ int r1_bak;
+
+ r1_bak = nor1;
+ nor1 = 0;
+
+ if ((add_number == 0) || (add_number >= -0x8000 && add_number <= 0x7fff))
+ {
+ fix_num = 1;
+ var_num = 2;
+
+ /* Insn 1 and Insn 2 */
+ /* Fix part
+ For an external symbol: lw rD, <sym>($gp)
+ (BFD_RELOC_SCORE_GOT15) */
+ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol :
+ lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15)
+ addi rD, <sym> (BFD_RELOC_GOT_LO16) */
+ inst.reloc.type = BFD_RELOC_SCORE_GOT15;
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[1], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+
+ /* Insn 2: lw rD, [rD, constant] */
+ sprintf (tmp, "lw r%d, [r%d, %d]", reg_rd, reg_rd, add_number);
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+ else
+ {
+ int hi = (add_number >> 16) & 0x0000FFFF;
+ int lo = add_number & 0x0000FFFF;
+
+ /* Insn 1: lw rD, <sym>($gp) (BFD_RELOC_SCORE_GOT15) */
+ sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Insn 2 */
+ fix_num = 1;
+ var_num = 1;
+ /* Fix part
+ For an external symbol: ldis r1, HI%<constant> */
+ sprintf (tmp, "ldis %s, %d", "r1", hi);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol: ldis r1, HI%<constant>
+ but, if lo is outof 16 bit, make hi plus 1 */
+ if ((lo < -0x8000) || (lo > 0x7fff))
+ {
+ hi += 1;
+ }
+ sprintf (tmp, "ldis_pic %s, %d", "r1", hi);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+
+ /* Insn 3 */
+ fix_num = 1;
+ var_num = 1;
+ /* Fix part
+ For an external symbol: ori r1, LO%<constant> */
+ sprintf (tmp, "ori %s, %d", "r1", lo);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
+
+ /* Var part
+ For a local symbol: addi r1, <sym>+LO%<constant> (BFD_RELOC_GOT_LO16) */
+ sprintf (tmp, "addi_u_pic %s, %s + %d", "r1", add_symbol->bsym->name, lo);
+ if (append_insn (tmp, FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&var_insts[0], &inst, sizeof (struct score_it));
+ build_relax_frag (fix_insts, fix_num, var_insts, var_num, add_symbol);
+
+ /* Insn 4: add rD, rD, r1 */
+ sprintf (tmp, "add r%d, r%d, %s", reg_rd, reg_rd, "r1");
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+
+ /* Insn 5: lw rD, [rD, 0] */
+ sprintf (tmp, "lw r%d, [r%d, 0]", reg_rd, reg_rd);
+ if (append_insn (tmp, TRUE) == (int) FAIL)
+ return;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+ }
+
+ nor1 = r1_bak;
+}
+
+static void
+do_macro_ldst_label (char *str)
+{
+ int i;
+ int ldst_gp_p = 0;
+ int reg_rd;
+ int r1_bak;
+ char *backup_str;
+ char *label_str;
+ char *absolute_value;
+ char append_str[3][MAX_LITERAL_POOL_SIZE];
+ char verifystr[MAX_LITERAL_POOL_SIZE];
+ struct score_it inst_backup;
+ struct score_it inst_expand[3];
+ struct score_it inst_main;
+
+ memcpy (&inst_backup, &inst, sizeof (struct score_it));
+ strcpy (verifystr, str);
+ backup_str = verifystr;
+
+ skip_whitespace (backup_str);
+ if ((reg_rd = reg_required_here (&backup_str, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ return;
+
+ if (skip_past_comma (&backup_str) == (int) FAIL)
+ return;
+
+ label_str = backup_str;
+
+ /* Ld/st rD, [rA, imm] ld/st rD, [rA]+, imm ld/st rD, [rA, imm]+. */
+ if (*backup_str == '[')
+ {
+ do_ldst_insn (str);
+ return;
+ }
+
+ /* Ld/st rD, imm. */
+ absolute_value = backup_str;
+ if ((my_get_expression (&inst.reloc.exp, &backup_str) == (int) FAIL)
+ || (validate_immediate (inst.reloc.exp.X_add_number, _VALUE) == (int) FAIL)
+ || (end_of_line (backup_str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ memcpy (&inst, &inst_backup, sizeof (struct score_it));
+ exp_macro_ldst_abs (str);
+ return;
+ }
+ }
+
+ /* Ld/st rD, label. */
+ backup_str = absolute_value;
+ if ((data_op2 (&backup_str, 1, _GP_IMM15) == (int) FAIL)
+ || (end_of_line (backup_str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+
+ return;
+ }
+
+ if (score_pic == PIC)
+ {
+ build_lw_pic (reg_rd, inst.reloc.exp);
+ return;
+ }
+ else
+ {
+ if ((inst.reloc.exp.X_add_number <= 0x3fff)
+ && (inst.reloc.exp.X_add_number >= -0x4000)
+ && (!nopic_need_relax (inst.reloc.exp.X_add_symbol, 1)))
+ {
+ int ldst_idx = 0;
+
+ /* Assign the real opcode. */
+ ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+ inst.instruction &= ~OPC_PSEUDOLDST_MASK;
+ inst.instruction |= score_ldst_insns[ldst_idx * 3 + 0].value;
+ inst.instruction |= reg_rd << 20;
+ inst.instruction |= GP << 15;
+ inst.relax_inst = 0x8000;
+ inst.relax_size = 0;
+ ldst_gp_p = 1;
+ }
+ }
+ }
+
+ /* Backup inst. */
+ memcpy (&inst_main, &inst, sizeof (struct score_it));
+ r1_bak = nor1;
+ nor1 = 0;
+
+ /* Determine which instructions should be output. */
+ sprintf (append_str[0], "ld_i32hi r1, %s", label_str);
+ sprintf (append_str[1], "ld_i32lo r1, %s", label_str);
+ sprintf (append_str[2], "%s r%d, [r1, 0]", inst_backup.name, reg_rd);
+
+ /* Generate three instructions.
+ la r1, label
+ ld/st rd, [r1, 0] */
+ for (i = 0; i < 3; i++)
+ {
+ if (append_insn (append_str[i], FALSE) == (int) FAIL)
+ return;
+
+ memcpy (&inst_expand[i], &inst, sizeof (struct score_it));
+ }
+
+ if (ldst_gp_p)
+ {
+ char *p;
+
+ /* Adjust instruction opcode and to be relaxed instruction opcode. */
+ inst_main.instruction = adjust_paritybit (inst_main.instruction, GET_INSN_CLASS (inst_main.type));
+ inst_main.relax_size = inst_expand[0].size + inst_expand[1].size + inst_expand[2].size;
+ inst_main.type = Insn_GP;
+
+ for (i = 0; i < 3; i++)
+ inst_expand[i].instruction = adjust_paritybit (inst_expand[i].instruction
+ , GET_INSN_CLASS (inst_expand[i].type));
+
+ /* Check data dependency. */
+ handle_dependency (&inst_main);
+
+ /* Start a new frag if frag_now is not empty. */
+ if (frag_now_fix () != 0)
+ {
+ if (!frag_now->tc_frag_data.is_insn)
+ frag_wane (frag_now);
+
+ frag_new (0);
+ }
+ frag_grow (20);
+
+ /* Write fr_fix part. */
+ p = frag_more (inst_main.size);
+ md_number_to_chars (p, inst_main.instruction, inst_main.size);
+
+ if (inst_main.reloc.type != BFD_RELOC_NONE)
+ {
+ fix_new_score (frag_now, p - frag_now->fr_literal, inst_main.size,
+ &inst_main.reloc.exp, inst_main.reloc.pc_rel, inst_main.reloc.type);
+ }
+
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (inst_main.size);
+#endif
+
+ /* GP instruction can not do optimization, only can do relax between
+ 1 instruction and 3 instructions. */
+ p = frag_var (rs_machine_dependent, inst_main.relax_size + RELAX_PAD_BYTE, 0,
+ RELAX_ENCODE (inst_main.size, inst_main.relax_size, inst_main.type, 0, 4, 0),
+ inst_main.reloc.exp.X_add_symbol, 0, NULL);
+
+ /* Write fr_var part.
+ no calling gen_insn_frag, no fixS will be generated. */
+ md_number_to_chars (p, inst_expand[0].instruction, inst_expand[0].size);
+ p += inst_expand[0].size;
+ md_number_to_chars (p, inst_expand[1].instruction, inst_expand[1].size);
+ p += inst_expand[1].size;
+ md_number_to_chars (p, inst_expand[2].instruction, inst_expand[2].size);
+ }
+ else
+ {
+ gen_insn_frag (&inst_expand[0], NULL);
+ gen_insn_frag (&inst_expand[1], NULL);
+ gen_insn_frag (&inst_expand[2], NULL);
+ }
+ nor1 = r1_bak;
+
+ /* Set bwarn as -1, so macro instruction itself will not be generated frag. */
+ inst.bwarn = -1;
+}
+
+static void
+do_lw_pic (char *str)
+{
+ int reg_rd;
+
+ skip_whitespace (str);
+ if (((reg_rd = reg_required_here (&str, 20, REG_TYPE_SCORE)) == (int) FAIL)
+ || (skip_past_comma (&str) == (int) FAIL)
+ || (my_get_expression (&inst.reloc.exp, &str) == (int) FAIL)
+ || (end_of_line (str) == (int) FAIL))
+ {
+ return;
+ }
+ else
+ {
+ if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ if (!inst.error)
+ inst.error = BAD_ARGS;
+
+ return;
+ }
+
+ inst.instruction |= GP << 15;
+ inst.reloc.type = BFD_RELOC_SCORE_GOT15;
+ }
+}
+
+static void
+do_empty (char *str)
+{
+ str = str;
+ if (university_version == 1)
+ {
+ if (((inst.instruction & 0x3e0003ff) == 0x0c000004)
+ || ((inst.instruction & 0x3e0003ff) == 0x0c000024)
+ || ((inst.instruction & 0x3e0003ff) == 0x0c000044)
+ || ((inst.instruction & 0x3e0003ff) == 0x0c000064))
+ {
+ inst.error = ERR_FOR_SCORE5U_MMU;
+ return;
+ }
+ }
+ if (end_of_line (str) == (int) FAIL)
+ return;
+
+ if (inst.relax_inst != 0x8000)
+ {
+ if (inst.type == NO_OPD)
+ {
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_size = 4;
+ }
+ }
+}
+
+static void
+do_jump (char *str)
+{
+ char *save_in;
+ char err_msg[100];
+
+ skip_whitespace (str);
+ if (my_get_expression (&inst.reloc.exp, &str) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ return;
+
+ if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ inst.error = _("lacking label ");
+ return;
+ }
+
+ if (((inst.reloc.exp.X_add_number & 0xff000000) != 0)
+ && ((inst.reloc.exp.X_add_number & 0xff000000) != 0xff000000))
+ {
+ sprintf (err_msg, "invalid constant: 25 bit expression not in range -2^24..2^24");
+ inst.error = _(err_msg);
+ return;
+ }
+
+ save_in = input_line_pointer;
+ input_line_pointer = str;
+ inst.reloc.type = BFD_RELOC_SCORE_JMP;
+ inst.reloc.pc_rel = 1;
+ input_line_pointer = save_in;
+}
+
+static void
+do16_jump (char *str)
+{
+ skip_whitespace (str);
+ if (my_get_expression (&inst.reloc.exp, &str) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ inst.error = _("lacking label ");
+ return;
+ }
+ else if (((inst.reloc.exp.X_add_number & 0xfffff800) != 0)
+ && ((inst.reloc.exp.X_add_number & 0xfffff800) != 0xfffff800))
+ {
+ inst.error = _("invalid constant: 12 bit expression not in range -2^11..2^11");
+ return;
+ }
+
+ inst.reloc.type = BFD_RELOC_SCORE16_JMP;
+ inst.reloc.pc_rel = 1;
+}
+
+static void
+do_branch (char *str)
+{
+ unsigned long abs_value = 0;
+
+ if (my_get_expression (&inst.reloc.exp, &str) == (int) FAIL
+ || end_of_line (str) == (int) FAIL)
+ {
+ return;
+ }
+ else if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ inst.error = _("lacking label ");
+ return;
+ }
+ else if (((inst.reloc.exp.X_add_number & 0xff000000) != 0)
+ && ((inst.reloc.exp.X_add_number & 0xff000000) != 0xff000000))
+ {
+ inst.error = "invalid constant: 20 bit expression not in range -2^19..2^19";
+ return;
+ }
+
+ inst.reloc.type = BFD_RELOC_SCORE_BRANCH;
+ inst.reloc.pc_rel = 1;
+
+ /* Branch 32 offset field : 20 bit, 16 bit branch offset field : 8 bit. */
+ inst.instruction |= (inst.reloc.exp.X_add_number & 0x3fe) | ((inst.reloc.exp.X_add_number & 0xffc00) << 5);
+
+ /* Take the branch condition code. */
+ inst.relax_inst = 0x4000 | (((inst.instruction >> 10) & 0xf) << 8);
+
+ if ((abs_value & 0xfffffe00) == 0)
+ {
+ inst.relax_inst |= ((inst.reloc.exp.X_add_number >> 1) & 0xff);
+ inst.relax_size = 2;
+ }
+ else
+ {
+ inst.relax_inst = 0x8000;
+ }
+
+ if (inst.instruction & 1)
+ inst.relax_inst = 0x8000;
+}
+
+static void
+do16_branch (char *str)
+{
+ if ((my_get_expression (&inst.reloc.exp, &str) == (int) FAIL
+ || end_of_line (str) == (int) FAIL))
+ {
+ ;
+ }
+ else if (inst.reloc.exp.X_add_symbol == 0)
+ {
+ inst.error = _("lacking label");
+ }
+ else if (((inst.reloc.exp.X_add_number & 0xffffff00) != 0)
+ && ((inst.reloc.exp.X_add_number & 0xffffff00) != 0xffffff00))
+ {
+ inst.error = _("invalid constant: 9 bit expression not in range -2^8..2^8");
+ }
+ else
+ {
+ inst.reloc.type = BFD_RELOC_SCORE16_BRANCH;
+ inst.reloc.pc_rel = 1;
+ inst.instruction |= ((inst.reloc.exp.X_add_number >> 1) & 0xff);
+ }
+}
+
+/* Iterate over the base tables to create the instruction patterns. */
+static void
+build_score_ops_hsh (void)
+{
+ unsigned int i;
+ static struct obstack insn_obstack;
+
+ obstack_begin (&insn_obstack, 4000);
+ for (i = 0; i < sizeof (score_insns) / sizeof (struct asm_opcode); i++)
+ {
+ const struct asm_opcode *insn = score_insns + i;
+ unsigned len = strlen (insn->template);
+ struct asm_opcode *new;
+ char *template;
+ new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode));
+ template = obstack_alloc (&insn_obstack, len + 1);
+
+ strcpy (template, insn->template);
+ new->template = template;
+ new->parms = insn->parms;
+ new->value = insn->value;
+ new->relax_value = insn->relax_value;
+ new->type = insn->type;
+ new->bitmask = insn->bitmask;
+ hash_insert (score_ops_hsh, new->template, (void *) new);
+ }
+}
+
+static void
+build_dependency_insn_hsh (void)
+{
+ unsigned int i;
+ static struct obstack dependency_obstack;
+
+ obstack_begin (&dependency_obstack, 4000);
+ for (i = 0; i < sizeof (insn_to_dependency_table) / sizeof (insn_to_dependency_table[0]); i++)
+ {
+ const struct insn_to_dependency *tmp = insn_to_dependency_table + i;
+ unsigned len = strlen (tmp->insn_name);
+ struct insn_to_dependency *new;
+
+ new = obstack_alloc (&dependency_obstack, sizeof (struct insn_to_dependency));
+ new->insn_name = obstack_alloc (&dependency_obstack, len + 1);
+
+ strcpy (new->insn_name, tmp->insn_name);
+ new->type = tmp->type;
+ hash_insert (dependency_insn_hsh, new->insn_name, (void *) new);
+ }
+}
+
+/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
+ for use in the a.out file, and stores them in the array pointed to by buf.
+ This knows about the endian-ness of the target machine and does
+ THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
+ 2 (short) and 4 (long) Floating numbers are put out as a series of
+ LITTLENUMS (shorts, here at least). */
+
+void
+md_number_to_chars (char *buf, valueT val, int n)
+{
+ if (target_big_endian)
+ number_to_chars_bigendian (buf, val, n);
+ else
+ number_to_chars_littleendian (buf, val, n);
+}
+
+static valueT
+md_chars_to_number (char *buf, int n)
+{
+ valueT result = 0;
+ unsigned char *where = (unsigned char *)buf;
+
+ if (target_big_endian)
+ {
+ while (n--)
+ {
+ result <<= 8;
+ result |= (*where++ & 255);
+ }
+ }
+ else
+ {
+ while (n--)
+ {
+ result <<= 8;
+ result |= (where[n] & 255);
+ }
+ }
+
+ return result;
+}
+
+/* Turn a string in input_line_pointer into a floating point constant
+ of type TYPE, and store the appropriate bytes in *LITP. The number
+ of LITTLENUMS emitted is stored in *SIZEP. An error message is
+ returned, or NULL on OK.
+
+ Note that fp constants aren't represent in the normal way on the ARM.
+ In big endian mode, things are as expected. However, in little endian
+ mode fp constants are big-endian word-wise, and little-endian byte-wise
+ within the words. For example, (double) 1.1 in big endian mode is
+ the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
+ the byte sequence 99 99 f1 3f 9a 99 99 99. */
+
+char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ int prec;
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ char *t;
+ int i;
+
+ switch (type)
+ {
+ case 'f':
+ case 'F':
+ case 's':
+ case 'S':
+ prec = 2;
+ break;
+ case 'd':
+ case 'D':
+ case 'r':
+ case 'R':
+ prec = 4;
+ break;
+ case 'x':
+ case 'X':
+ case 'p':
+ case 'P':
+ prec = 6;
+ break;
+ default:
+ *sizeP = 0;
+ return _("bad call to MD_ATOF()");
+ }
+
+ t = atof_ieee (input_line_pointer, type, words);
+ if (t)
+ input_line_pointer = t;
+ *sizeP = prec * 2;
+
+ if (target_big_endian)
+ {
+ for (i = 0; i < prec; i++)
+ {
+ md_number_to_chars (litP, (valueT) words[i], 2);
+ litP += 2;
+ }
+ }
+ else
+ {
+ for (i = 0; i < prec; i += 2)
+ {
+ md_number_to_chars (litP, (valueT) words[i + 1], 2);
+ md_number_to_chars (litP + 2, (valueT) words[i], 2);
+ litP += 4;
+ }
+ }
+
+ return 0;
+}
+
+/* Return true if the given symbol should be considered local for PIC. */
+
+static bfd_boolean
+pic_need_relax (symbolS *sym, asection *segtype)
+{
+ asection *symsec;
+ bfd_boolean linkonce;
+
+ /* Handle the case of a symbol equated to another symbol. */
+ while (symbol_equated_reloc_p (sym))
+ {
+ symbolS *n;
+
+ /* It's possible to get a loop here in a badly written
+ program. */
+ n = symbol_get_value_expression (sym)->X_add_symbol;
+ if (n == sym)
+ break;
+ sym = n;
+ }
+
+ symsec = S_GET_SEGMENT (sym);
+
+ /* duplicate the test for LINK_ONCE sections as in adjust_reloc_syms */
+ linkonce = FALSE;
+ if (symsec != segtype && ! S_IS_LOCAL (sym))
+ {
+ if ((bfd_get_section_flags (stdoutput, symsec) & SEC_LINK_ONCE) != 0)
+ linkonce = TRUE;
+
+ /* The GNU toolchain uses an extension for ELF: a section
+ beginning with the magic string .gnu.linkonce is a linkonce
+ section. */
+ if (strncmp (segment_name (symsec), ".gnu.linkonce",
+ sizeof ".gnu.linkonce" - 1) == 0)
+ linkonce = TRUE;
+ }
+
+ /* This must duplicate the test in adjust_reloc_syms. */
+ return (symsec != &bfd_und_section
+ && symsec != &bfd_abs_section
+ && ! bfd_is_com_section (symsec)
+ && !linkonce
+#ifdef OBJ_ELF
+ /* A global or weak symbol is treated as external. */
+ && (OUTPUT_FLAVOR != bfd_target_elf_flavour
+ || (! S_IS_WEAK (sym) && ! S_IS_EXTERNAL (sym)))
+#endif
+ );
+}
+
+static int
+judge_size_before_relax (fragS * fragp, asection *sec)
+{
+ int change = 0;
+
+ if (score_pic == NO_PIC)
+ change = nopic_need_relax (fragp->fr_symbol, 0);
+ else
+ change = pic_need_relax (fragp->fr_symbol, sec);
+
+ if (change == 1)
+ {
+ /* Only at the first time determining whether GP instruction relax should be done,
+ return the difference between insntruction size and instruction relax size. */
+ if (fragp->fr_opcode == NULL)
+ {
+ fragp->fr_fix = RELAX_NEW (fragp->fr_subtype);
+ fragp->fr_opcode = fragp->fr_literal + RELAX_RELOC1 (fragp->fr_subtype);
+ return RELAX_NEW (fragp->fr_subtype) - RELAX_OLD (fragp->fr_subtype);
+ }
+ }
+
+ return 0;
+}
+
+/* In this function, we determine whether GP instruction should do relaxation,
+ for the label being against was known now.
+ Doing this here but not in md_relax_frag() can induce iteration times
+ in stage of doing relax. */
+int
+md_estimate_size_before_relax (fragS * fragp, asection * sec ATTRIBUTE_UNUSED)
+{
+ if ((RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
+ || (RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
+ return judge_size_before_relax (fragp, sec);
+
+ return 0;
+}
+
+static int
+b32_relax_to_b16 (fragS * fragp)
+{
+ int grows = 0;
+ int relaxable_p = 0;
+ int old;
+ int new;
+ int frag_addr = fragp->fr_address + fragp->insn_addr;
+
+ addressT symbol_address = 0;
+ symbolS *s;
+ offsetT offset;
+ unsigned long value;
+ unsigned long abs_value;
+
+ /* FIXME : here may be able to modify better .
+ I don't know how to get the fragp's section ,
+ so in relax stage , it may be wrong to calculate the symbol's offset when the frag's section
+ is different from the symbol's. */
+
+ old = RELAX_OLD (fragp->fr_subtype);
+ new = RELAX_NEW (fragp->fr_subtype);
+ relaxable_p = RELAX_OPT (fragp->fr_subtype);
+
+ s = fragp->fr_symbol;
+ /* b/bl immediate */
+ if (s == NULL)
+ frag_addr = 0;
+ else
+ {
+ if (s->bsym != 0)
+ symbol_address = (addressT) s->sy_frag->fr_address;
+ }
+
+ value = md_chars_to_number (fragp->fr_literal, INSN_SIZE);
+
+ /* b 32's offset : 20 bit, b 16's tolerate field : 0xff. */
+ offset = ((value & 0x3ff0000) >> 6) | (value & 0x3fe);
+ if ((offset & 0x80000) == 0x80000)
+ offset |= 0xfff00000;
+
+ abs_value = offset + symbol_address - frag_addr;
+ if ((abs_value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - abs_value + 1;
+
+ /* Relax branch 32 to branch 16. */
+ if (relaxable_p && (s->bsym != NULL) && ((abs_value & 0xffffff00) == 0)
+ && (S_IS_DEFINED (s) && !S_IS_COMMON (s) && !S_IS_EXTERNAL (s)))
+ {
+ /* do nothing. */
+ }
+ else
+ {
+ /* Branch 32 can not be relaxed to b 16, so clear OPT bit. */
+ fragp->fr_opcode = NULL;
+ fragp->fr_subtype = RELAX_OPT_CLEAR (fragp->fr_subtype);
+ }
+
+ return grows;
+}
+
+/* Main purpose is to determine whether one frag should do relax.
+ frag->fr_opcode indicates this point. */
+
+int
+score_relax_frag (asection * sec ATTRIBUTE_UNUSED, fragS * fragp, long stretch ATTRIBUTE_UNUSED)
+{
+ int grows = 0;
+ int insn_size;
+ int insn_relax_size;
+ int do_relax_p = 0; /* Indicate doing relaxation for this frag. */
+ int relaxable_p = 0;
+ bfd_boolean word_align_p = FALSE;
+ fragS *next_fragp;
+
+ /* If the instruction address is odd, make it half word align first. */
+ if ((fragp->fr_address) % 2 != 0)
+ {
+ if ((fragp->fr_address + fragp->insn_addr) % 2 != 0)
+ {
+ fragp->insn_addr = 1;
+ grows += 1;
+ }
+ }
+
+ word_align_p = ((fragp->fr_address + fragp->insn_addr) % 4 == 0) ? TRUE : FALSE;
+
+ /* Get instruction size and relax size after the last relaxation. */
+ if (fragp->fr_opcode)
+ {
+ insn_size = RELAX_NEW (fragp->fr_subtype);
+ insn_relax_size = RELAX_OLD (fragp->fr_subtype);
+ }
+ else
+ {
+ insn_size = RELAX_OLD (fragp->fr_subtype);
+ insn_relax_size = RELAX_NEW (fragp->fr_subtype);
+ }
+
+ /* Handle specially for GP instruction. for, judge_size_before_relax() has already determine
+ whether the GP instruction should do relax. */
+ if ((RELAX_TYPE (fragp->fr_subtype) == Insn_GP)
+ || (RELAX_TYPE (fragp->fr_subtype) == Insn_PIC))
+ {
+ if (!word_align_p)
+ {
+ fragp->insn_addr += 2;
+ grows += 2;
+ }
+
+ if (fragp->fr_opcode)
+ fragp->fr_fix = RELAX_NEW (fragp->fr_subtype) + fragp->insn_addr;
+ else
+ fragp->fr_fix = RELAX_OLD (fragp->fr_subtype) + fragp->insn_addr;
+ }
+ else
+ {
+ if (RELAX_TYPE (fragp->fr_subtype) == PC_DISP19div2)
+ b32_relax_to_b16 (fragp);
+
+ relaxable_p = RELAX_OPT (fragp->fr_subtype);
+ next_fragp = fragp->fr_next;
+ while ((next_fragp) && (next_fragp->fr_type != rs_machine_dependent))
+ {
+ next_fragp = next_fragp->fr_next;
+ }
+
+ if (next_fragp)
+ {
+ int n_insn_size;
+ int n_relaxable_p = 0;
+
+ if (next_fragp->fr_opcode)
+ {
+ n_insn_size = RELAX_NEW (next_fragp->fr_subtype);
+ }
+ else
+ {
+ n_insn_size = RELAX_OLD (next_fragp->fr_subtype);
+ }
+
+ n_relaxable_p = RELAX_OPT (next_fragp->fr_subtype);
+
+ if (word_align_p)
+ {
+ if (insn_size == 4)
+ {
+ /* 32 -> 16. */
+ if (relaxable_p && ((n_insn_size == 2) || n_relaxable_p))
+ {
+ grows -= 2;
+ do_relax_p = 1;
+ }
+ }
+ else if (insn_size == 2)
+ {
+ /* 16 -> 32. */
+ if (relaxable_p && ((n_insn_size == 4) && !n_relaxable_p))
+ {
+ grows += 2;
+ do_relax_p = 1;
+ }
+ }
+ else
+ {
+ abort ();
+ }
+ }
+ else
+ {
+ if (insn_size == 4)
+ {
+ /* 32 -> 16. */
+ if (relaxable_p)
+ {
+ grows -= 2;
+ do_relax_p = 1;
+ }
+ /* Make the 32 bit insturction word align. */
+ else
+ {
+ fragp->insn_addr += 2;
+ grows += 2;
+ }
+ }
+ else if (insn_size == 2)
+ {
+ /* Do nothing. */
+ }
+ else
+ {
+ abort ();
+ }
+ }
+ }
+ else
+ {
+ /* Here, try best to do relax regardless fragp->fr_next->fr_type. */
+ if (word_align_p == FALSE)
+ {
+ if (insn_size % 4 == 0)
+ {
+ /* 32 -> 16. */
+ if (relaxable_p)
+ {
+ grows -= 2;
+ do_relax_p = 1;
+ }
+ else
+ {
+ fragp->insn_addr += 2;
+ grows += 2;
+ }
+ }
+ }
+ else
+ {
+ /* Do nothing. */
+ }
+ }
+
+ /* fragp->fr_opcode indicates whether this frag should be relaxed. */
+ if (do_relax_p)
+ {
+ if (fragp->fr_opcode)
+ {
+ fragp->fr_opcode = NULL;
+ /* Guarantee estimate stage is correct. */
+ fragp->fr_fix = RELAX_OLD (fragp->fr_subtype);
+ fragp->fr_fix += fragp->insn_addr;
+ }
+ else
+ {
+ fragp->fr_opcode = fragp->fr_literal + RELAX_RELOC1 (fragp->fr_subtype);
+ /* Guarantee estimate stage is correct. */
+ fragp->fr_fix = RELAX_NEW (fragp->fr_subtype);
+ fragp->fr_fix += fragp->insn_addr;
+ }
+ }
+ else
+ {
+ if (fragp->fr_opcode)
+ {
+ /* Guarantee estimate stage is correct. */
+ fragp->fr_fix = RELAX_NEW (fragp->fr_subtype);
+ fragp->fr_fix += fragp->insn_addr;
+ }
+ else
+ {
+ /* Guarantee estimate stage is correct. */
+ fragp->fr_fix = RELAX_OLD (fragp->fr_subtype);
+ fragp->fr_fix += fragp->insn_addr;
+ }
+ }
+ }
+
+ return grows;
+}
+
+void
+md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, fragS * fragp)
+{
+ int old;
+ int new;
+ char backup[20];
+ fixS *fixp;
+
+ old = RELAX_OLD (fragp->fr_subtype);
+ new = RELAX_NEW (fragp->fr_subtype);
+
+ /* fragp->fr_opcode indicates whether this frag should be relaxed. */
+ if (fragp->fr_opcode == NULL)
+ {
+ memcpy (backup, fragp->fr_literal, old);
+ fragp->fr_fix = old;
+ }
+ else
+ {
+ memcpy (backup, fragp->fr_literal + old, new);
+ fragp->fr_fix = new;
+ }
+
+ fixp = fragp->tc_frag_data.fixp;
+ while (fixp && fixp->fx_frag == fragp && fixp->fx_where < old)
+ {
+ if (fragp->fr_opcode)
+ fixp->fx_done = 1;
+ fixp = fixp->fx_next;
+ }
+ while (fixp && fixp->fx_frag == fragp)
+ {
+ if (fragp->fr_opcode)
+ fixp->fx_where -= old + fragp->insn_addr;
+ else
+ fixp->fx_done = 1;
+ fixp = fixp->fx_next;
+ }
+
+ if (fragp->insn_addr)
+ {
+ md_number_to_chars (fragp->fr_literal, 0x0, fragp->insn_addr);
+ }
+ memcpy (fragp->fr_literal + fragp->insn_addr, backup, fragp->fr_fix);
+ fragp->fr_fix += fragp->insn_addr;
+}
+
+/* Implementation of md_frag_check.
+ Called after md_convert_frag(). */
+
+void
+score_frag_check (fragS * fragp ATTRIBUTE_UNUSED)
+{
+ know (fragp->insn_addr <= RELAX_PAD_BYTE);
+}
+
+bfd_boolean
+score_fix_adjustable (fixS * fixP)
+{
+ if (fixP->fx_addsy == NULL)
+ {
+ return 1;
+ }
+ else if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+ && (S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)))
+ {
+ return 0;
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Implementation of TC_VALIDATE_FIX.
+ Called before md_apply_fix() and after md_convert_frag(). */
+void
+score_validate_fix (fixS *fixP)
+{
+ fixP->fx_where += fixP->fx_frag->insn_addr;
+}
+
+long
+md_pcrel_from (fixS * fixP)
+{
+ long retval = 0;
+
+ if (fixP->fx_addsy
+ && (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
+ && (fixP->fx_subsy == NULL))
+ {
+ retval = 0;
+ }
+ else
+ {
+ retval = fixP->fx_where + fixP->fx_frag->fr_address;
+ }
+
+ return retval;
+}
+
+int
+score_force_relocation (struct fix *fixp)
+{
+ int retval = 0;
+
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
+ || fixp->fx_r_type == BFD_RELOC_SCORE_JMP
+ || fixp->fx_r_type == BFD_RELOC_SCORE_BRANCH
+ || fixp->fx_r_type == BFD_RELOC_SCORE16_JMP
+ || fixp->fx_r_type == BFD_RELOC_SCORE16_BRANCH)
+ {
+ retval = 1;
+ }
+
+ return retval;
+}
+
+/* Round up a section size to the appropriate boundary. */
+valueT
+md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size)
+{
+ int align = bfd_get_section_alignment (stdoutput, segment);
+
+#ifdef OBJ_ELF
+ /* We don't need to align ELF sections to the full alignment.
+ However, Irix 5 may prefer that we align them at least to a 16
+ byte boundary. We don't bother to align the sections if we are
+ targeted for an embedded system. */
+ if (strcmp (TARGET_OS, "elf") == 0)
+ return size;
+ if (align > 4)
+ align = 4;
+#endif
+
+ return ((size + (1 << align) - 1) & (-1 << align));
+}
+
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
+{
+ offsetT value = *valP;
+ offsetT abs_value = 0;
+ offsetT newval;
+ offsetT content;
+ unsigned short HI, LO;
+
+ char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
+ if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
+ {
+ if (fixP->fx_r_type != BFD_RELOC_SCORE_DUMMY_HI16)
+ fixP->fx_done = 1;
+ }
+
+ /* If this symbol is in a different section then we need to leave it for
+ the linker to deal with. Unfortunately, md_pcrel_from can't tell,
+ so we have to undo it's effects here. */
+ if (fixP->fx_pcrel)
+ {
+ if (fixP->fx_addsy != NULL
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && S_GET_SEGMENT (fixP->fx_addsy) != seg)
+ value += md_pcrel_from (fixP);
+ }
+
+ /* Remember value for emit_reloc. */
+ fixP->fx_addnumber = value;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_HI16_S:
+ if (fixP->fx_done)
+ { /* For la rd, imm32. */
+ newval = md_chars_to_number (buf, INSN_SIZE);
+ HI = (value) >> 16; /* mul to 2, then take the hi 16 bit. */
+ newval |= (HI & 0x3fff) << 1;
+ newval |= ((HI >> 14) & 0x3) << 16;
+ md_number_to_chars (buf, newval, INSN_SIZE);
+ }
+ break;
+ case BFD_RELOC_LO16:
+ if (fixP->fx_done) /* For la rd, imm32. */
+ {
+ newval = md_chars_to_number (buf, INSN_SIZE);
+ LO = (value) & 0xffff;
+ newval |= (LO & 0x3fff) << 1; /* 16 bit: imm -> 14 bit in lo, 2 bit in hi. */
+ newval |= ((LO >> 14) & 0x3) << 16;
+ md_number_to_chars (buf, newval, INSN_SIZE);
+ }
+ break;
+ case BFD_RELOC_SCORE_JMP:
+ {
+ content = md_chars_to_number (buf, INSN_SIZE);
+ value = fixP->fx_offset;
+ content = (content & ~0x3ff7ffe) | ((value << 1) & 0x3ff0000) | (value & 0x7fff);
+ md_number_to_chars (buf, content, INSN_SIZE);
+ }
+ break;
+ case BFD_RELOC_SCORE_BRANCH:
+ if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) || (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
+ value = fixP->fx_offset;
+ else
+ fixP->fx_done = 1;
+
+ content = md_chars_to_number (buf, INSN_SIZE);
+ if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) != 0x80008000))
+ {
+ if ((value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - value + 1;
+ if ((abs_value & 0xffffff00) != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _(" branch relocation truncate (0x%x) [-2^8 ~ 2^8]"), (unsigned int)value);
+ return;
+ }
+ content = md_chars_to_number (buf, INSN16_SIZE);
+ content &= 0xff00;
+ content = (content & 0xff00) | ((value >> 1) & 0xff);
+ md_number_to_chars (buf, content, INSN16_SIZE);
+ fixP->fx_r_type = BFD_RELOC_SCORE16_BRANCH;
+ fixP->fx_size = 2;
+ }
+ else
+ {
+ if ((value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - value + 1;
+ if ((abs_value & 0xfff80000) != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"), (unsigned int)value);
+ return;
+ }
+ content = md_chars_to_number (buf, INSN_SIZE);
+ content &= 0xfc00fc01;
+ content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
+ md_number_to_chars (buf, content, INSN_SIZE);
+ }
+ break;
+ case BFD_RELOC_SCORE16_JMP:
+ content = md_chars_to_number (buf, INSN16_SIZE);
+ content &= 0xf001;
+ value = fixP->fx_offset & 0xfff;
+ content = (content & 0xfc01) | (value & 0xffe);
+ md_number_to_chars (buf, content, INSN16_SIZE);
+ break;
+ case BFD_RELOC_SCORE16_BRANCH:
+ content = md_chars_to_number (buf, INSN_SIZE);
+ if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0x80008000) == 0x80008000))
+ {
+ if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
+ (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
+ value = fixP->fx_offset;
+ else
+ fixP->fx_done = 1;
+ if ((value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - value + 1;
+ if ((abs_value & 0xfff80000) != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _(" branch relocation truncate (0x%x) [-2^19 ~ 2^19]"), (unsigned int)value);
+ return;
+ }
+ content = md_chars_to_number (buf, INSN_SIZE);
+ content = (content & 0xfc00fc01) | (value & 0x3fe) | ((value << 6) & 0x3ff0000);
+ md_number_to_chars (buf, content, INSN_SIZE);
+ fixP->fx_r_type = BFD_RELOC_SCORE_BRANCH;
+ fixP->fx_size = 4;
+ break;
+ }
+ else
+ {
+ /* In differnt section. */
+ if ((S_GET_SEGMENT (fixP->fx_addsy) != seg) ||
+ (fixP->fx_addsy != NULL && S_IS_EXTERNAL (fixP->fx_addsy)))
+ value = fixP->fx_offset;
+ else
+ fixP->fx_done = 1;
+
+ if ((value & 0x80000000) == 0x80000000)
+ abs_value = 0xffffffff - value + 1;
+ if ((abs_value & 0xffffff00) != 0)
+ {
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _(" branch relocation truncate (0x%x) [-2^8 ~ 2^8]"), (unsigned int)value);
+ return;
+ }
+ content = md_chars_to_number (buf, INSN16_SIZE);
+ content = (content & 0xff00) | ((value >> 1) & 0xff);
+ md_number_to_chars (buf, content, INSN16_SIZE);
+ break;
+ }
+ case BFD_RELOC_8:
+ if (fixP->fx_done || fixP->fx_pcrel)
+ md_number_to_chars (buf, value, 1);
+#ifdef OBJ_ELF
+ else
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 1);
+ }
+#endif
+ break;
+
+ case BFD_RELOC_16:
+ if (fixP->fx_done || fixP->fx_pcrel)
+ md_number_to_chars (buf, value, 2);
+#ifdef OBJ_ELF
+ else
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 2);
+ }
+#endif
+ break;
+ case BFD_RELOC_RVA:
+ case BFD_RELOC_32:
+ if (fixP->fx_done || fixP->fx_pcrel)
+ md_number_to_chars (buf, value, 4);
+#ifdef OBJ_ELF
+ else
+ {
+ value = fixP->fx_offset;
+ md_number_to_chars (buf, value, 4);
+ }
+#endif
+ break;
+ case BFD_RELOC_VTABLE_INHERIT:
+ fixP->fx_done = 0;
+ if (fixP->fx_addsy && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
+ S_SET_WEAK (fixP->fx_addsy);
+ break;
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = 0;
+ break;
+ case BFD_RELOC_SCORE_GPREL15:
+ content = md_chars_to_number (buf, INSN_SIZE);
+ if ((fixP->fx_frag->fr_opcode != 0) && ((content & 0xfc1c8000) != 0x94188000))
+ fixP->fx_r_type = BFD_RELOC_NONE;
+ fixP->fx_done = 0;
+ break;
+ case BFD_RELOC_SCORE_GOT15:
+ case BFD_RELOC_SCORE_DUMMY_HI16:
+ case BFD_RELOC_SCORE_GOT_LO16:
+ case BFD_RELOC_SCORE_CALL15:
+ case BFD_RELOC_GPREL32:
+ break;
+ case BFD_RELOC_NONE:
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("bad relocation fixup type (%d)"), fixP->fx_r_type);
+ }
+}
+
+/* Translate internal representation of relocation info to BFD target format. */
+arelent **
+tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
+{
+ static arelent *retval[MAX_RELOC_EXPANSION + 1]; /* MAX_RELOC_EXPANSION equals 2. */
+ arelent *reloc;
+ bfd_reloc_code_real_type code;
+ char *type;
+ fragS *f;
+ symbolS *s;
+ expressionS e;
+
+ reloc = retval[0] = xmalloc (sizeof (arelent));
+ retval[1] = NULL;
+
+ reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc->addend = fixp->fx_offset;
+
+ /* If this is a variant frag, we may need to adjust the existing
+ reloc and generate a new one. */
+ if (fixp->fx_frag->fr_opcode != NULL && (fixp->fx_r_type == BFD_RELOC_SCORE_GPREL15))
+ {
+ /* Update instruction imm bit. */
+ offsetT newval;
+ unsigned short off;
+ char *buf;
+
+ buf = fixp->fx_frag->fr_literal + fixp->fx_frag->insn_addr;
+ newval = md_chars_to_number (buf, INSN_SIZE);
+ off = fixp->fx_offset >> 16;
+ newval |= (off & 0x3fff) << 1;
+ newval |= ((off >> 14) & 0x3) << 16;
+ md_number_to_chars (buf, newval, INSN_SIZE);
+
+ buf += INSN_SIZE;
+ newval = md_chars_to_number (buf, INSN_SIZE);
+ off = fixp->fx_offset & 0xffff;
+ newval |= ((off & 0x3fff) << 1);
+ newval |= (((off >> 14) & 0x3) << 16);
+ md_number_to_chars (buf, newval, INSN_SIZE);
+
+ retval[1] = xmalloc (sizeof (arelent));
+ retval[2] = NULL;
+ retval[1]->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ *retval[1]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ retval[1]->address = (reloc->address + RELAX_RELOC2 (fixp->fx_frag->fr_subtype));
+
+ f = fixp->fx_frag;
+ s = f->fr_symbol;
+ e = s->sy_value;
+
+ retval[1]->addend = 0;
+ retval[1]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16);
+ assert (retval[1]->howto != NULL);
+
+ fixp->fx_r_type = BFD_RELOC_HI16_S;
+ }
+
+ code = fixp->fx_r_type;
+ switch (fixp->fx_r_type)
+ {
+ case BFD_RELOC_32:
+ if (fixp->fx_pcrel)
+ {
+ code = BFD_RELOC_32_PCREL;
+ break;
+ }
+ case BFD_RELOC_HI16_S:
+ case BFD_RELOC_LO16:
+ case BFD_RELOC_SCORE_JMP:
+ case BFD_RELOC_SCORE_BRANCH:
+ case BFD_RELOC_SCORE16_JMP:
+ case BFD_RELOC_SCORE16_BRANCH:
+ case BFD_RELOC_VTABLE_ENTRY:
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_SCORE_GPREL15:
+ case BFD_RELOC_SCORE_GOT15:
+ case BFD_RELOC_SCORE_DUMMY_HI16:
+ case BFD_RELOC_SCORE_GOT_LO16:
+ case BFD_RELOC_SCORE_CALL15:
+ case BFD_RELOC_GPREL32:
+ case BFD_RELOC_NONE:
+ code = fixp->fx_r_type;
+ break;
+ default:
+ type = _("<unknown>");
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("cannot represent %s relocation in this object file format"), type);
+ return NULL;
+ }
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
+ if (reloc->howto == NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("cannot represent %s relocation in this object file format1"),
+ bfd_get_reloc_code_name (code));
+ return NULL;
+ }
+ /* HACK: Since arm ELF uses Rel instead of Rela, encode the
+ vtable entry to be used in the relocation's section offset. */
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ reloc->address = fixp->fx_offset;
+
+ return retval;
+}
+
+void
+score_elf_final_processing (void)
+{
+ if (fix_data_dependency == 1)
+ {
+ elf_elfheader (stdoutput)->e_flags |= EF_SCORE_FIXDEP;
+ }
+ if (score_pic == PIC)
+ {
+ elf_elfheader (stdoutput)->e_flags |= EF_SCORE_PIC;
+ }
+}
+
+static void
+parse_pce_inst (char *insnstr)
+{
+ char c;
+ char *p;
+ char first[MAX_LITERAL_POOL_SIZE];
+ char second[MAX_LITERAL_POOL_SIZE];
+ struct score_it pec_part_1;
+
+ /* Get first part string of PCE. */
+ p = strstr (insnstr, "||");
+ c = *p;
+ *p = '\0';
+ sprintf (first, "%s", insnstr);
+
+ /* Get second part string of PCE. */
+ *p = c;
+ p += 2;
+ sprintf (second, "%s", p);
+
+ parse_16_32_inst (first, FALSE);
+ if (inst.error)
+ return;
+
+ memcpy (&pec_part_1, &inst, sizeof (inst));
+
+ parse_16_32_inst (second, FALSE);
+ if (inst.error)
+ return;
+
+ if ( ((pec_part_1.size == INSN_SIZE) && (inst.size == INSN_SIZE))
+ || ((pec_part_1.size == INSN_SIZE) && (inst.size == INSN16_SIZE))
+ || ((pec_part_1.size == INSN16_SIZE) && (inst.size == INSN_SIZE)))
+ {
+ inst.error = _("pce instruction error (16 bit || 16 bit)'");
+ sprintf (inst.str, "%s", insnstr);
+ return;
+ }
+
+ if (!inst.error)
+ gen_insn_frag (&pec_part_1, &inst);
+}
+
+void
+md_assemble (char *str)
+{
+ know (str);
+ know (strlen (str) < MAX_LITERAL_POOL_SIZE);
+
+ memset (&inst, '\0', sizeof (inst));
+ if (INSN_IS_PCE_P (str))
+ parse_pce_inst (str);
+ else
+ parse_16_32_inst (str, TRUE);
+
+ if (inst.error)
+ as_bad ("%s -- `%s'", inst.error, inst.str);
+}
+
+/* We handle all bad expressions here, so that we can report the faulty
+ instruction in the error message. */
+void
+md_operand (expressionS * expr)
+{
+ if (in_my_get_expression)
+ {
+ expr->X_op = O_illegal;
+ if (inst.error == NULL)
+ {
+ inst.error = _("bad expression");
+ }
+ }
+}
+
+const char *md_shortopts = "nO::g::G:";
+
+#ifdef SCORE_BI_ENDIAN
+#define OPTION_EB (OPTION_MD_BASE + 0)
+#define OPTION_EL (OPTION_MD_BASE + 1)
+#else
+#if TARGET_BYTES_BIG_ENDIAN
+#define OPTION_EB (OPTION_MD_BASE + 0)
+#else
+#define OPTION_EL (OPTION_MD_BASE + 1)
+#endif
+#endif
+#define OPTION_FIXDD (OPTION_MD_BASE + 2)
+#define OPTION_NWARN (OPTION_MD_BASE + 3)
+#define OPTION_SCORE5 (OPTION_MD_BASE + 4)
+#define OPTION_SCORE5U (OPTION_MD_BASE + 5)
+#define OPTION_SCORE7 (OPTION_MD_BASE + 6)
+#define OPTION_R1 (OPTION_MD_BASE + 7)
+#define OPTION_O0 (OPTION_MD_BASE + 8)
+#define OPTION_SCORE_VERSION (OPTION_MD_BASE + 9)
+#define OPTION_PIC (OPTION_MD_BASE + 10)
+
+struct option md_longopts[] =
+{
+#ifdef OPTION_EB
+ {"EB" , no_argument, NULL, OPTION_EB},
+#endif
+#ifdef OPTION_EL
+ {"EL" , no_argument, NULL, OPTION_EL},
+#endif
+ {"FIXDD" , no_argument, NULL, OPTION_FIXDD},
+ {"NWARN" , no_argument, NULL, OPTION_NWARN},
+ {"SCORE5" , no_argument, NULL, OPTION_SCORE5},
+ {"SCORE5U", no_argument, NULL, OPTION_SCORE5U},
+ {"SCORE7" , no_argument, NULL, OPTION_SCORE7},
+ {"USE_R1" , no_argument, NULL, OPTION_R1},
+ {"O0" , no_argument, NULL, OPTION_O0},
+ {"V" , no_argument, NULL, OPTION_SCORE_VERSION},
+ {"KPIC" , no_argument, NULL, OPTION_PIC},
+ {NULL , no_argument, NULL, 0}
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+int
+md_parse_option (int c, char *arg)
+{
+ switch (c)
+ {
+#ifdef OPTION_EB
+ case OPTION_EB:
+ target_big_endian = 1;
+ break;
+#endif
+#ifdef OPTION_EL
+ case OPTION_EL:
+ target_big_endian = 0;
+ break;
+#endif
+ case OPTION_FIXDD:
+ fix_data_dependency = 1;
+ break;
+ case OPTION_NWARN:
+ warn_fix_data_dependency = 0;
+ break;
+ case OPTION_SCORE5:
+ score7 = 0;
+ university_version = 0;
+ vector_size = SCORE5_PIPELINE;
+ break;
+ case OPTION_SCORE5U:
+ score7 = 0;
+ university_version = 1;
+ vector_size = SCORE5_PIPELINE;
+ break;
+ case OPTION_SCORE7:
+ score7 = 1;
+ university_version = 0;
+ vector_size = SCORE7_PIPELINE;
+ break;
+ case OPTION_R1:
+ nor1 = 0;
+ break;
+ case 'G':
+ g_switch_value = atoi (arg);
+ break;
+ case OPTION_O0:
+ g_opt = 0;
+ break;
+ case OPTION_SCORE_VERSION:
+ printf (_("Sunplus-v2-0-0-20060510\n"));
+ break;
+ case OPTION_PIC:
+ score_pic = PIC;
+ g_switch_value = 0; /* Must set -G num as 0 to generate PIC code. */
+ break;
+ default:
+ /* as_bad (_("unrecognized option `-%c%s'"), c, arg ? arg : ""); */
+ return 0;
+ }
+ return 1;
+}
+
+void
+md_show_usage (FILE * fp)
+{
+ fprintf (fp, _(" Score-specific assembler options:\n"));
+#ifdef OPTION_EB
+ fprintf (fp, _("\
+ -EB\t\tassemble code for a big-endian cpu\n"));
+#endif
+
+#ifdef OPTION_EL
+ fprintf (fp, _("\
+ -EL\t\tassemble code for a little-endian cpu\n"));
+#endif
+
+ fprintf (fp, _("\
+ -FIXDD\t\tassemble code for fix data dependency\n"));
+ fprintf (fp, _("\
+ -NWARN\t\tassemble code for no warning message for fix data dependency\n"));
+ fprintf (fp, _("\
+ -SCORE5\t\tassemble code for target is SCORE5\n"));
+ fprintf (fp, _("\
+ -SCORE5U\tassemble code for target is SCORE5U\n"));
+ fprintf (fp, _("\
+ -SCORE7\t\tassemble code for target is SCORE7, this is default setting\n"));
+ fprintf (fp, _("\
+ -USE_R1\t\tassemble code for no warning message when using temp register r1\n"));
+ fprintf (fp, _("\
+ -O0\t\tassemble will not any optimization \n"));
+ fprintf (fp, _("\
+ -G gpnum\tassemble code for setting gpsize and default is 8 byte \n"));
+ fprintf (fp, _("\
+ -V \t\tSunplus release version \n"));
+}
+
+
+/* Pesudo handling functions. */
+
+/* If we change section we must dump the literal pool first. */
+static void
+s_score_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ subseg_set (bss_section, (subsegT) get_absolute_expression ());
+ demand_empty_rest_of_line ();
+}
+
+static void
+s_score_text (int ignore)
+{
+ obj_elf_text (ignore);
+ record_alignment (now_seg, 2);
+}
+
+static void
+score_s_section (int ignore)
+{
+ obj_elf_section (ignore);
+ if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+ record_alignment (now_seg, 2);
+
+}
+
+static void
+s_change_sec (int sec)
+{
+ segT seg;
+
+#ifdef OBJ_ELF
+ /* The ELF backend needs to know that we are changing sections, so
+ that .previous works correctly. We could do something like check
+ for an obj_section_change_hook macro, but that might be confusing
+ as it would not be appropriate to use it in the section changing
+ functions in read.c, since obj-elf.c intercepts those. FIXME:
+ This should be cleaner, somehow. */
+ obj_elf_section_change_hook ();
+#endif
+ switch (sec)
+ {
+ case 'r':
+ seg = subseg_new (RDATA_SECTION_NAME, (subsegT) get_absolute_expression ());
+ bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_RELOC | SEC_DATA));
+ if (strcmp (TARGET_OS, "elf") != 0)
+ record_alignment (seg, 4);
+ demand_empty_rest_of_line ();
+ break;
+ case 's':
+ seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
+ bfd_set_section_flags (stdoutput, seg, SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
+ if (strcmp (TARGET_OS, "elf") != 0)
+ record_alignment (seg, 4);
+ demand_empty_rest_of_line ();
+ break;
+ }
+}
+
+static void
+s_score_mask (int reg_type ATTRIBUTE_UNUSED)
+{
+ long mask, off;
+
+ if (cur_proc_ptr == (procS *) NULL)
+ {
+ as_warn (_(".mask outside of .ent"));
+ demand_empty_rest_of_line ();
+ return;
+ }
+ if (get_absolute_expression_and_terminator (&mask) != ',')
+ {
+ as_warn (_("Bad .mask directive"));
+ --input_line_pointer;
+ demand_empty_rest_of_line ();
+ return;
+ }
+ off = get_absolute_expression ();
+ cur_proc_ptr->reg_mask = mask;
+ cur_proc_ptr->reg_offset = off;
+ demand_empty_rest_of_line ();
+}
+
+static symbolS *
+get_symbol (void)
+{
+ int c;
+ char *name;
+ symbolS *p;
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ p = (symbolS *) symbol_find_or_make (name);
+ *input_line_pointer = c;
+ return p;
+}
+
+static long
+get_number (void)
+{
+ int negative = 0;
+ long val = 0;
+
+ if (*input_line_pointer == '-')
+ {
+ ++input_line_pointer;
+ negative = 1;
+ }
+ if (!ISDIGIT (*input_line_pointer))
+ as_bad (_("expected simple number"));
+ if (input_line_pointer[0] == '0')
+ {
+ if (input_line_pointer[1] == 'x')
+ {
+ input_line_pointer += 2;
+ while (ISXDIGIT (*input_line_pointer))
+ {
+ val <<= 4;
+ val |= hex_value (*input_line_pointer++);
+ }
+ return negative ? -val : val;
+ }
+ else
+ {
+ ++input_line_pointer;
+ while (ISDIGIT (*input_line_pointer))
+ {
+ val <<= 3;
+ val |= *input_line_pointer++ - '0';
+ }
+ return negative ? -val : val;
+ }
+ }
+ if (!ISDIGIT (*input_line_pointer))
+ {
+ printf (_(" *input_line_pointer == '%c' 0x%02x\n"), *input_line_pointer, *input_line_pointer);
+ as_warn (_("invalid number"));
+ return -1;
+ }
+ while (ISDIGIT (*input_line_pointer))
+ {
+ val *= 10;
+ val += *input_line_pointer++ - '0';
+ }
+ return negative ? -val : val;
+}
+
+/* The .aent and .ent directives. */
+
+static void
+s_score_ent (int aent)
+{
+ symbolS *symbolP;
+ int maybe_text;
+
+ symbolP = get_symbol ();
+ if (*input_line_pointer == ',')
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ if (ISDIGIT (*input_line_pointer) || *input_line_pointer == '-')
+ get_number ();
+
+#ifdef BFD_ASSEMBLER
+ if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#else
+ if (now_seg != data_section && now_seg != bss_section)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#endif
+ if (!maybe_text)
+ as_warn (_(".ent or .aent not in text section."));
+ if (!aent && cur_proc_ptr)
+ as_warn (_("missing .end"));
+ if (!aent)
+ {
+ cur_proc_ptr = &cur_proc;
+ cur_proc_ptr->reg_mask = 0xdeadbeaf;
+ cur_proc_ptr->reg_offset = 0xdeadbeaf;
+ cur_proc_ptr->fpreg_mask = 0xdeafbeaf;
+ cur_proc_ptr->leaf = 0xdeafbeaf;
+ cur_proc_ptr->frame_offset = 0xdeafbeaf;
+ cur_proc_ptr->frame_reg = 0xdeafbeaf;
+ cur_proc_ptr->pc_reg = 0xdeafbeaf;
+ cur_proc_ptr->isym = symbolP;
+ symbol_get_bfdsym (symbolP)->flags |= BSF_FUNCTION;
+ ++numprocs;
+ if (debug_type == DEBUG_STABS)
+ stabs_generate_asm_func (S_GET_NAME (symbolP), S_GET_NAME (symbolP));
+ }
+ demand_empty_rest_of_line ();
+}
+
+static void
+s_score_frame (int ignore ATTRIBUTE_UNUSED)
+{
+ char *backupstr;
+ char str[30];
+ long val;
+ int i = 0;
+
+ backupstr = input_line_pointer;
+
+#ifdef OBJ_ELF
+ if (cur_proc_ptr == (procS *) NULL)
+ {
+ as_warn (_(".frame outside of .ent"));
+ demand_empty_rest_of_line ();
+ return;
+ }
+ cur_proc_ptr->frame_reg = reg_required_here ((&backupstr), 0, REG_TYPE_SCORE);
+ SKIP_WHITESPACE ();
+ skip_past_comma (&backupstr);
+ while (*backupstr != ',')
+ {
+ str[i] = *backupstr;
+ i++;
+ backupstr++;
+ }
+ str[i] = '\0';
+ val = atoi (str);
+
+ SKIP_WHITESPACE ();
+ skip_past_comma (&backupstr);
+ cur_proc_ptr->frame_offset = val;
+ cur_proc_ptr->pc_reg = reg_required_here ((&backupstr), 0, REG_TYPE_SCORE);
+
+ SKIP_WHITESPACE ();
+ skip_past_comma (&backupstr);
+ i = 0;
+ while (*backupstr != '\n')
+ {
+ str[i] = *backupstr;
+ i++;
+ backupstr++;
+ }
+ str[i] = '\0';
+ val = atoi (str);
+ cur_proc_ptr->leaf = val;
+ SKIP_WHITESPACE ();
+ skip_past_comma (&backupstr);
+
+#endif /* OBJ_ELF */
+ while (input_line_pointer != backupstr)
+ input_line_pointer++;
+}
+
+/* The .end directive. */
+static void
+s_score_end (int x ATTRIBUTE_UNUSED)
+{
+ symbolS *p;
+ int maybe_text;
+
+ /* Generate a .pdr section. */
+ segT saved_seg = now_seg;
+ subsegT saved_subseg = now_subseg;
+ valueT dot;
+ expressionS exp;
+ char *fragp;
+
+ if (!is_end_of_line[(unsigned char)*input_line_pointer])
+ {
+ p = get_symbol ();
+ demand_empty_rest_of_line ();
+ }
+ else
+ p = NULL;
+
+#ifdef BFD_ASSEMBLER
+ if ((bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#else
+ if (now_seg != data_section && now_seg != bss_section)
+ maybe_text = 1;
+ else
+ maybe_text = 0;
+#endif
+
+ if (!maybe_text)
+ as_warn (_(".end not in text section"));
+ if (!cur_proc_ptr)
+ {
+ as_warn (_(".end directive without a preceding .ent directive."));
+ demand_empty_rest_of_line ();
+ return;
+ }
+ if (p != NULL)
+ {
+ assert (S_GET_NAME (p));
+ if (strcmp (S_GET_NAME (p), S_GET_NAME (cur_proc_ptr->isym)))
+ as_warn (_(".end symbol does not match .ent symbol."));
+ if (debug_type == DEBUG_STABS)
+ stabs_generate_asm_endfunc (S_GET_NAME (p), S_GET_NAME (p));
+ }
+ else
+ as_warn (_(".end directive missing or unknown symbol"));
+
+ if ((cur_proc_ptr->reg_mask == 0xdeadbeaf) ||
+ (cur_proc_ptr->reg_offset == 0xdeadbeaf) ||
+ (cur_proc_ptr->leaf == 0xdeafbeaf) ||
+ (cur_proc_ptr->frame_offset == 0xdeafbeaf) ||
+ (cur_proc_ptr->frame_reg == 0xdeafbeaf) || (cur_proc_ptr->pc_reg == 0xdeafbeaf));
+
+ else
+ {
+ dot = frag_now_fix ();
+ assert (pdr_seg);
+ subseg_set (pdr_seg, 0);
+ /* Write the symbol. */
+ exp.X_op = O_symbol;
+ exp.X_add_symbol = p;
+ exp.X_add_number = 0;
+ emit_expr (&exp, 4);
+ fragp = frag_more (7 * 4);
+ md_number_to_chars (fragp, (valueT) cur_proc_ptr->reg_mask, 4);
+ md_number_to_chars (fragp + 4, (valueT) cur_proc_ptr->reg_offset, 4);
+ md_number_to_chars (fragp + 8, (valueT) cur_proc_ptr->fpreg_mask, 4);
+ md_number_to_chars (fragp + 12, (valueT) cur_proc_ptr->leaf, 4);
+ md_number_to_chars (fragp + 16, (valueT) cur_proc_ptr->frame_offset, 4);
+ md_number_to_chars (fragp + 20, (valueT) cur_proc_ptr->frame_reg, 4);
+ md_number_to_chars (fragp + 24, (valueT) cur_proc_ptr->pc_reg, 4);
+ subseg_set (saved_seg, saved_subseg);
+
+ }
+ cur_proc_ptr = NULL;
+}
+
+/* Handle the .set pseudo-op. */
+static void
+s_score_set (int x ATTRIBUTE_UNUSED)
+{
+ int i = 0;
+ char name[MAX_LITERAL_POOL_SIZE];
+ char * orig_ilp = input_line_pointer;
+
+ while (!is_end_of_line[(unsigned char)*input_line_pointer])
+ {
+ name[i] = (char) * input_line_pointer;
+ i++;
+ ++input_line_pointer;
+ }
+
+ name[i] = '\0';
+
+ if (strcmp (name, "nwarn") == 0)
+ {
+ warn_fix_data_dependency = 0;
+ }
+ else if (strcmp (name, "fixdd") == 0)
+ {
+ fix_data_dependency = 1;
+ }
+ else if (strcmp (name, "nofixdd") == 0)
+ {
+ fix_data_dependency = 0;
+ }
+ else if (strcmp (name, "r1") == 0)
+ {
+ nor1 = 0;
+ }
+ else if (strcmp (name, "nor1") == 0)
+ {
+ nor1 = 1;
+ }
+ else if (strcmp (name, "optimize") == 0)
+ {
+ g_opt = 1;
+ }
+ else if (strcmp (name, "volatile") == 0)
+ {
+ g_opt = 0;
+ }
+ else if (strcmp (name, "pic") == 0)
+ {
+ score_pic = PIC;
+ }
+ else
+ {
+ input_line_pointer = orig_ilp;
+ s_set (0);
+ }
+}
+
+/* Handle the .cpload pseudo-op. This is used when generating PIC code. It sets the
+ $gp register for the function based on the function address, which is in the register
+ named in the argument. This uses a relocation against GP_DISP_LABEL, which is handled
+ specially by the linker. The result is:
+ ldis gp, %hi(GP_DISP_LABEL)
+ ori gp, %low(GP_DISP_LABEL)
+ add gp, gp, .cpload argument
+ The .cpload argument is normally r29. */
+
+static void
+s_score_cpload (int ignore ATTRIBUTE_UNUSED)
+{
+ int reg;
+ char insn_str[MAX_LITERAL_POOL_SIZE];
+
+ /* If we are not generating PIC code, .cpload is ignored. */
+ if (score_pic == NO_PIC)
+ {
+ s_ignore (0);
+ return;
+ }
+
+ if ((reg = reg_required_here (&input_line_pointer, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ return;
+
+ demand_empty_rest_of_line ();
+
+ sprintf (insn_str, "ld_i32hi r%d, %s", GP, GP_DISP_LABEL);
+ if (append_insn (insn_str, TRUE) == (int) FAIL)
+ return;
+
+ sprintf (insn_str, "ld_i32lo r%d, %s", GP, GP_DISP_LABEL);
+ if (append_insn (insn_str, TRUE) == (int) FAIL)
+ return;
+
+ sprintf (insn_str, "add r%d, r%d, r%d", GP, GP, reg);
+ if (append_insn (insn_str, TRUE) == (int) FAIL)
+ return;
+}
+
+/* Handle the .cprestore pseudo-op. This stores $gp into a given
+ offset from $sp. The offset is remembered, and after making a PIC
+ call $gp is restored from that location. */
+
+static void
+s_score_cprestore (int ignore ATTRIBUTE_UNUSED)
+{
+#define SCORE_BP_REG 2
+ int cprestore_offset;
+ char insn_str[MAX_LITERAL_POOL_SIZE];
+
+ /* If we are not generating PIC code, .cprestore is ignored. */
+ if (score_pic == NO_PIC)
+ {
+ s_ignore (0);
+ return;
+ }
+
+ cprestore_offset = get_absolute_expression ();
+
+ sprintf (insn_str, "sw r%d, [r%d, %d]", GP, SCORE_BP_REG, cprestore_offset);
+ if (append_insn (insn_str, TRUE) == (int) FAIL)
+ return;
+}
+
+/* Handle the .gpword pseudo-op. This is used when generating PIC
+ code. It generates a 32 bit GP relative reloc. */
+static void
+s_score_gpword (int ignore ATTRIBUTE_UNUSED)
+{
+ expressionS ex;
+ char *p;
+
+ /* When not generating PIC code, this is treated as .word. */
+ if (score_pic == NO_PIC)
+ {
+ cons (4);
+ return;
+ }
+ expression (&ex);
+ if (ex.X_op != O_symbol || ex.X_add_number != 0)
+ {
+ as_bad (_("Unsupported use of .gpword"));
+ ignore_rest_of_line ();
+ }
+ p = frag_more (4);
+ md_number_to_chars (p, (valueT) 0, 4);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE, BFD_RELOC_GPREL32);
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .cpadd pseudo-op. This is used when dealing with switch
+ tables in PIC code. */
+
+static void
+s_score_cpadd (int ignore ATTRIBUTE_UNUSED)
+{
+ int reg;
+ char insn_str[MAX_LITERAL_POOL_SIZE];
+
+ /* If we are not generating PIC code, .cpload is ignored. */
+ if (score_pic == NO_PIC)
+ {
+ s_ignore (0);
+ return;
+ }
+
+ if ((reg = reg_required_here (&input_line_pointer, -1, REG_TYPE_SCORE)) == (int) FAIL)
+ {
+ return;
+ }
+ demand_empty_rest_of_line ();
+
+ /* Add $gp to the register named as an argument. */
+ sprintf (insn_str, "add r%d, r%d, r%d", reg, reg, GP);
+ if (append_insn (insn_str, TRUE) == (int) FAIL)
+ return;
+}
+
+#ifndef TC_IMPLICIT_LCOMM_ALIGNMENT
+#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \
+ do \
+ { \
+ if ((SIZE) >= 8) \
+ (P2VAR) = 3; \
+ else if ((SIZE) >= 4) \
+ (P2VAR) = 2; \
+ else if ((SIZE) >= 2) \
+ (P2VAR) = 1; \
+ else \
+ (P2VAR) = 0; \
+ } \
+ while (0)
+#endif
+
+static void
+s_score_lcomm (int bytes_p)
+{
+ char *name;
+ char c;
+ char *p;
+ int temp;
+ symbolS *symbolP;
+ segT current_seg = now_seg;
+ subsegT current_subseg = now_subseg;
+ const int max_alignment = 15;
+ int align = 0;
+ segT bss_seg = bss_section;
+ int needs_align = 0;
+
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ p = input_line_pointer;
+ *p = c;
+
+ if (name == p)
+ {
+ as_bad (_("expected symbol name"));
+ discard_rest_of_line ();
+ return;
+ }
+
+ SKIP_WHITESPACE ();
+
+ /* Accept an optional comma after the name. The comma used to be
+ required, but Irix 5 cc does not generate it. */
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+ }
+
+ if (is_end_of_line[(unsigned char)*input_line_pointer])
+ {
+ as_bad (_("missing size expression"));
+ return;
+ }
+
+ if ((temp = get_absolute_expression ()) < 0)
+ {
+ as_warn (_("BSS length (%d) < 0 ignored"), temp);
+ ignore_rest_of_line ();
+ return;
+ }
+
+#if defined (TC_SCORE)
+ if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour || OUTPUT_FLAVOR == bfd_target_elf_flavour)
+ {
+ /* For Score and Alpha ECOFF or ELF, small objects are put in .sbss. */
+ if ((unsigned)temp <= bfd_get_gp_size (stdoutput))
+ {
+ bss_seg = subseg_new (".sbss", 1);
+ seg_info (bss_seg)->bss = 1;
+#ifdef BFD_ASSEMBLER
+ if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC))
+ as_warn (_("error setting flags for \".sbss\": %s"), bfd_errmsg (bfd_get_error ()));
+#endif
+ }
+ }
+#endif
+
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer == ',')
+ {
+ ++input_line_pointer;
+ SKIP_WHITESPACE ();
+
+ if (is_end_of_line[(unsigned char)*input_line_pointer])
+ {
+ as_bad (_("missing alignment"));
+ return;
+ }
+ else
+ {
+ align = get_absolute_expression ();
+ needs_align = 1;
+ }
+ }
+
+ if (!needs_align)
+ {
+ TC_IMPLICIT_LCOMM_ALIGNMENT (temp, align);
+
+ /* Still zero unless TC_IMPLICIT_LCOMM_ALIGNMENT set it. */
+ if (align)
+ record_alignment (bss_seg, align);
+ }
+
+ if (needs_align)
+ {
+ if (bytes_p)
+ {
+ /* Convert to a power of 2. */
+ if (align != 0)
+ {
+ unsigned int i;
+
+ for (i = 0; align != 0; align >>= 1, ++i)
+ ;
+ align = i - 1;
+ }
+ }
+
+ if (align > max_alignment)
+ {
+ align = max_alignment;
+ as_warn (_("alignment too large; %d assumed"), align);
+ }
+ else if (align < 0)
+ {
+ align = 0;
+ as_warn (_("alignment negative; 0 assumed"));
+ }
+
+ record_alignment (bss_seg, align);
+ }
+ else
+ {
+ /* Assume some objects may require alignment on some systems. */
+#if defined (TC_ALPHA) && ! defined (VMS)
+ if (temp > 1)
+ {
+ align = ffs (temp) - 1;
+ if (temp % (1 << align))
+ abort ();
+ }
+#endif
+ }
+
+ *p = 0;
+ symbolP = symbol_find_or_make (name);
+ *p = c;
+
+ if (
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT) \
+ || defined (OBJ_BOUT) || defined (OBJ_MAYBE_BOUT))
+#ifdef BFD_ASSEMBLER
+ (OUTPUT_FLAVOR != bfd_target_aout_flavour
+ || (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) &&
+#else
+ (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0) &&
+#endif
+#endif
+ (S_GET_SEGMENT (symbolP) == bss_seg || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0)))
+ {
+ char *pfrag;
+
+ subseg_set (bss_seg, 1);
+
+ if (align)
+ frag_align (align, 0, 0);
+
+ /* Detach from old frag. */
+ if (S_GET_SEGMENT (symbolP) == bss_seg)
+ symbol_get_frag (symbolP)->fr_symbol = NULL;
+
+ symbol_set_frag (symbolP, frag_now);
+ pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, (offsetT) temp, NULL);
+ *pfrag = 0;
+
+
+ S_SET_SEGMENT (symbolP, bss_seg);
+
+#ifdef OBJ_COFF
+ /* The symbol may already have been created with a preceding
+ ".globl" directive -- be careful not to step on storage class
+ in that case. Otherwise, set it to static. */
+ if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
+ {
+ S_SET_STORAGE_CLASS (symbolP, C_STAT);
+ }
+#endif /* OBJ_COFF */
+
+#ifdef S_SET_SIZE
+ S_SET_SIZE (symbolP, temp);
+#endif
+ }
+ else
+ as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP));
+
+ subseg_set (current_seg, current_subseg);
+
+ demand_empty_rest_of_line ();
+}
+
+static void
+insert_reg (const struct reg_entry *r, struct hash_control *htab)
+{
+ int i = 0;
+ int len = strlen (r->name) + 2;
+ char *buf = xmalloc (len);
+ char *buf2 = xmalloc (len);
+
+ strcpy (buf + i, r->name);
+ for (i = 0; buf[i]; i++)
+ {
+ buf2[i] = TOUPPER (buf[i]);
+ }
+ buf2[i] = '\0';
+
+ hash_insert (htab, buf, (void *) r);
+ hash_insert (htab, buf2, (void *) r);
+}
+
+static void
+build_reg_hsh (struct reg_map *map)
+{
+ const struct reg_entry *r;
+
+ if ((map->htab = hash_new ()) == NULL)
+ {
+ as_fatal (_("virtual memory exhausted"));
+ }
+ for (r = map->names; r->name != NULL; r++)
+ {
+ insert_reg (r, map->htab);
+ }
+}
+
+void
+md_begin (void)
+{
+ unsigned int i;
+ segT seg;
+ subsegT subseg;
+
+ if ((score_ops_hsh = hash_new ()) == NULL)
+ as_fatal (_("virtual memory exhausted"));
+
+ build_score_ops_hsh ();
+
+ if ((dependency_insn_hsh = hash_new ()) == NULL)
+ as_fatal (_("virtual memory exhausted"));
+
+ build_dependency_insn_hsh ();
+
+ for (i = (int)REG_TYPE_FIRST; i < (int)REG_TYPE_MAX; i++)
+ build_reg_hsh (all_reg_maps + i);
+
+ /* Initialize dependency vector. */
+ init_dependency_vector ();
+
+ bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
+ seg = now_seg;
+ subseg = now_subseg;
+ pdr_seg = subseg_new (".pdr", (subsegT) 0);
+ (void)bfd_set_section_flags (stdoutput, pdr_seg, SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
+ (void)bfd_set_section_alignment (stdoutput, pdr_seg, 2);
+ subseg_set (seg, subseg);
+
+ if (USE_GLOBAL_POINTER_OPT)
+ bfd_set_gp_size (stdoutput, g_switch_value);
+}
+
+
+const pseudo_typeS md_pseudo_table[] =
+{
+ {"bss", s_score_bss, 0},
+ {"text", s_score_text, 0},
+ {"word", cons, 4},
+ {"long", cons, 4},
+ {"extend", float_cons, 'x'},
+ {"ldouble", float_cons, 'x'},
+ {"packed", float_cons, 'p'},
+ {"end", s_score_end, 0},
+ {"ent", s_score_ent, 0},
+ {"frame", s_score_frame, 0},
+ {"rdata", s_change_sec, 'r'},
+ {"sdata", s_change_sec, 's'},
+ {"set", s_score_set, 0},
+ {"mask", s_score_mask, 'R'},
+ {"dword", cons, 8},
+ {"lcomm", s_score_lcomm, 1},
+ {"section", score_s_section, 0},
+ {"cpload", s_score_cpload, 0},
+ {"cprestore", s_score_cprestore, 0},
+ {"gpword", s_score_gpword, 0},
+ {"cpadd", s_score_cpadd, 0},
+ {0, 0, 0}
+};
+
--- /dev/null
+/* tc-score.h -- Score specific file for assembler
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by:
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS 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.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef TC_SCORE
+#define TC_SCORE
+
+#define TARGET_ARCH bfd_arch_score
+#define WORKING_DOT_WORD
+#define DIFF_EXPR_OK
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+#define MAX_MEM_FOR_RS_ALIGN_CODE (3 + 4)
+
+#define md_undefined_symbol(name) NULL
+
+#define TARGET_FORMAT (target_big_endian ? "elf32-bigscore" : "elf32-littlescore")
+
+#define md_relax_frag(segment, fragp, stretch) score_relax_frag (segment, fragp, stretch)
+extern int score_relax_frag (asection *, struct frag *, long);
+
+#define md_frag_check(fragp) score_frag_check (fragp)
+extern void score_frag_check (fragS *);
+
+#define TC_VALIDATE_FIX(FIXP, SEGTYPE, SKIP) score_validate_fix (FIXP)
+extern void score_validate_fix (struct fix *);
+
+#define TC_FORCE_RELOCATION(FIXP) score_force_relocation (FIXP)
+extern int score_force_relocation (struct fix *);
+
+#define tc_fix_adjustable(fixp) score_fix_adjustable (fixp)
+extern bfd_boolean score_fix_adjustable (struct fix *);
+
+#define elf_tc_final_processing score_elf_final_processing
+extern void score_elf_final_processing (void);
+
+struct score_tc_frag_data
+{
+ unsigned int is_insn;
+ struct fix *fixp;
+};
+
+#define TC_FRAG_TYPE struct score_tc_frag_data
+
+#define TC_FRAG_INIT(FRAGP) \
+ do \
+ { \
+ (FRAGP)->tc_frag_data.is_insn = (((FRAGP)->fr_type == rs_machine_dependent) ? 1 : 0); \
+ } \
+ while (0)
+
+#ifdef OBJ_ELF
+#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
+#else
+#define GLOBAL_OFFSET_TABLE_NAME "__GLOBAL_OFFSET_TABLE_"
+#endif
+
+enum score_pic_level
+{
+ NO_PIC,
+ PIC
+};
+
+#endif /*TC_SCORE */
rs6000*) cpu_type=ppc ;;
s390x*) cpu_type=s390 arch=s390x ;;
s390*) cpu_type=s390 arch=s390 ;;
+ score*l) cpu_type=score endian=little ;;
+ score*) cpu_type=score endian=big ;;
sh5le*) cpu_type=sh64 endian=little ;;
sh5*) cpu_type=sh64 endian=big ;;
sh64le*) cpu_type=sh64 endian=little ;;
s390-*-linux-*) fmt=elf em=linux ;;
s390-*-tpf*) fmt=elf ;;
+ score-*-elf) fmt=elf ;;
+
sh*-*-linux*) fmt=elf em=linux
case ${cpu} in
sh*eb) endian=big ;;
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * gas/score: New directory.
+ * gas/elf/section2.e-score: New file.
+ * gas/elf/elf.exp: Add special case for Score target.
+
2006-09-16 Paul Brook <paul@codesourcery.com>
* gas/arm/unwind.s: Test two argument form of .movsp.
if {[istarget m32r*-*-*]} then {
set target_machine -m32r
}
+ if {[istarget "score-*-*"]} then {
+ set target_machine -score
+ }
if { ([istarget "*arm*-*-*"]
|| [istarget "xscale*-*-*"])
&& ([istarget "*-*-*eabi"]
--- /dev/null
+
+Symbol table '.symtab' contains 6 entries:
+ Num: Value Size Type Bind Vis Ndx Name
+ 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
+ 1: 00000000 0 SECTION LOCAL DEFAULT 1
+ 2: 00000000 0 SECTION LOCAL DEFAULT 2
+ 3: 00000000 0 SECTION LOCAL DEFAULT 3
+ 4: 00000000 0 SECTION LOCAL DEFAULT 5
+ 5: 00000000 0 SECTION LOCAL DEFAULT 4
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * dis-asm.h: Add prototypes for Score disassembler routines.
+
2006-09-07 H.J. Lu <hongjiu.lu@intel.com>
* bfdlink.h (bfd_elf_dynamic_list): New.
/* Interface between the opcode library and its callers.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
typedef int (*fprintf_ftype) (void *, const char*, ...) ATTRIBUTE_FPTR_PRINTF_2;
-enum dis_insn_type {
+enum dis_insn_type
+{
dis_noninsn, /* Not a valid instruction */
dis_nonbranch, /* Not a branch instruction */
dis_branch, /* Unconditional branch */
It must be initialized before it is first passed; this can be done
by hand, or using one of the initialization macros below. */
-typedef struct disassemble_info {
+typedef struct disassemble_info
+{
fprintf_ftype fprintf_func;
void *stream;
void *application_data;
target address. Return number of octets processed. */
typedef int (*disassembler_ftype) (bfd_vma, disassemble_info *);
-extern int print_insn_big_mips (bfd_vma, disassemble_info *);
-extern int print_insn_little_mips (bfd_vma, disassemble_info *);
-extern int print_insn_i386 (bfd_vma, disassemble_info *);
-extern int print_insn_i386_att (bfd_vma, disassemble_info *);
-extern int print_insn_i386_intel (bfd_vma, disassemble_info *);
-extern int print_insn_ia64 (bfd_vma, disassemble_info *);
-extern int print_insn_i370 (bfd_vma, disassemble_info *);
-extern int print_insn_m68hc11 (bfd_vma, disassemble_info *);
-extern int print_insn_m68hc12 (bfd_vma, disassemble_info *);
-extern int print_insn_m68k (bfd_vma, disassemble_info *);
-extern int print_insn_z80 (bfd_vma, disassemble_info *);
-extern int print_insn_z8001 (bfd_vma, disassemble_info *);
-extern int print_insn_z8002 (bfd_vma, disassemble_info *);
-extern int print_insn_h8300 (bfd_vma, disassemble_info *);
-extern int print_insn_h8300h (bfd_vma, disassemble_info *);
-extern int print_insn_h8300s (bfd_vma, disassemble_info *);
-extern int print_insn_h8500 (bfd_vma, disassemble_info *);
extern int print_insn_alpha (bfd_vma, disassemble_info *);
-extern int print_insn_big_arm (bfd_vma, disassemble_info *);
-extern int print_insn_little_arm (bfd_vma, disassemble_info *);
-extern int print_insn_sparc (bfd_vma, disassemble_info *);
extern int print_insn_avr (bfd_vma, disassemble_info *);
extern int print_insn_bfin (bfd_vma, disassemble_info *);
+extern int print_insn_big_arm (bfd_vma, disassemble_info *);
+extern int print_insn_big_mips (bfd_vma, disassemble_info *);
+extern int print_insn_big_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_big_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_big_score (bfd_vma, disassemble_info *);
+extern int print_insn_crx (bfd_vma, disassemble_info *);
extern int print_insn_d10v (bfd_vma, disassemble_info *);
extern int print_insn_d30v (bfd_vma, disassemble_info *);
extern int print_insn_dlx (bfd_vma, disassemble_info *);
extern int print_insn_fr30 (bfd_vma, disassemble_info *);
+extern int print_insn_frv (bfd_vma, disassemble_info *);
+extern int print_insn_h8300 (bfd_vma, disassemble_info *);
+extern int print_insn_h8300h (bfd_vma, disassemble_info *);
+extern int print_insn_h8300s (bfd_vma, disassemble_info *);
+extern int print_insn_h8500 (bfd_vma, disassemble_info *);
extern int print_insn_hppa (bfd_vma, disassemble_info *);
+extern int print_insn_i370 (bfd_vma, disassemble_info *);
+extern int print_insn_i386 (bfd_vma, disassemble_info *);
+extern int print_insn_i386_att (bfd_vma, disassemble_info *);
+extern int print_insn_i386_intel (bfd_vma, disassemble_info *);
extern int print_insn_i860 (bfd_vma, disassemble_info *);
extern int print_insn_i960 (bfd_vma, disassemble_info *);
+extern int print_insn_ia64 (bfd_vma, disassemble_info *);
extern int print_insn_ip2k (bfd_vma, disassemble_info *);
+extern int print_insn_iq2000 (bfd_vma, disassemble_info *);
+extern int print_insn_little_arm (bfd_vma, disassemble_info *);
+extern int print_insn_little_mips (bfd_vma, disassemble_info *);
+extern int print_insn_little_or32 (bfd_vma, disassemble_info *);
+extern int print_insn_little_powerpc (bfd_vma, disassemble_info *);
+extern int print_insn_little_score (bfd_vma, disassemble_info *);
+extern int print_insn_m32c (bfd_vma, disassemble_info *);
extern int print_insn_m32r (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc11 (bfd_vma, disassemble_info *);
+extern int print_insn_m68hc12 (bfd_vma, disassemble_info *);
+extern int print_insn_m68k (bfd_vma, disassemble_info *);
extern int print_insn_m88k (bfd_vma, disassemble_info *);
-extern int print_insn_maxq_little (bfd_vma, disassemble_info *);
extern int print_insn_maxq_big (bfd_vma, disassemble_info *);
+extern int print_insn_maxq_little (bfd_vma, disassemble_info *);
extern int print_insn_mcore (bfd_vma, disassemble_info *);
extern int print_insn_mmix (bfd_vma, disassemble_info *);
extern int print_insn_mn10200 (bfd_vma, disassemble_info *);
extern int print_insn_mn10300 (bfd_vma, disassemble_info *);
-extern int print_insn_mt (bfd_vma, disassemble_info *);
extern int print_insn_msp430 (bfd_vma, disassemble_info *);
+extern int print_insn_mt (bfd_vma, disassemble_info *);
extern int print_insn_ns32k (bfd_vma, disassemble_info *);
-extern int print_insn_crx (bfd_vma, disassemble_info *);
extern int print_insn_openrisc (bfd_vma, disassemble_info *);
-extern int print_insn_big_or32 (bfd_vma, disassemble_info *);
-extern int print_insn_little_or32 (bfd_vma, disassemble_info *);
extern int print_insn_pdp11 (bfd_vma, disassemble_info *);
extern int print_insn_pj (bfd_vma, disassemble_info *);
-extern int print_insn_big_powerpc (bfd_vma, disassemble_info *);
-extern int print_insn_little_powerpc (bfd_vma, disassemble_info *);
extern int print_insn_rs6000 (bfd_vma, disassemble_info *);
extern int print_insn_s390 (bfd_vma, disassemble_info *);
extern int print_insn_sh (bfd_vma, disassemble_info *);
+extern int print_insn_sh64 (bfd_vma, disassemble_info *);
+extern int print_insn_sh64x_media (bfd_vma, disassemble_info *);
+extern int print_insn_sparc (bfd_vma, disassemble_info *);
extern int print_insn_tic30 (bfd_vma, disassemble_info *);
extern int print_insn_tic4x (bfd_vma, disassemble_info *);
extern int print_insn_tic54x (bfd_vma, disassemble_info *);
extern int print_insn_v850 (bfd_vma, disassemble_info *);
extern int print_insn_vax (bfd_vma, disassemble_info *);
extern int print_insn_w65 (bfd_vma, disassemble_info *);
+extern int print_insn_xc16x (bfd_vma, disassemble_info *);
extern int print_insn_xstormy16 (bfd_vma, disassemble_info *);
extern int print_insn_xtensa (bfd_vma, disassemble_info *);
-extern int print_insn_sh64 (bfd_vma, disassemble_info *);
-extern int print_insn_sh64x_media (bfd_vma, disassemble_info *);
-extern int print_insn_frv (bfd_vma, disassemble_info *);
-extern int print_insn_iq2000 (bfd_vma, disassemble_info *);
-extern int print_insn_xc16x (bfd_vma, disassemble_info *);
-extern int print_insn_m32c (bfd_vma, disassemble_info *);
+extern int print_insn_z80 (bfd_vma, disassemble_info *);
+extern int print_insn_z8001 (bfd_vma, disassemble_info *);
+extern int print_insn_z8002 (bfd_vma, disassemble_info *);
extern disassembler_ftype arc_get_disassembler (void *);
extern disassembler_ftype cris_get_disassembler (bfd *);
extern void print_ppc_disassembler_options (FILE *);
extern void print_arm_disassembler_options (FILE *);
extern void parse_arm_disassembler_option (char *);
-extern int get_arm_regname_num_options (void);
-extern int set_arm_regname_option (int);
-extern int get_arm_regnames (int, const char **, const char **, const char *const **);
+extern int get_arm_regname_num_options (void);
+extern int set_arm_regname_option (int);
+extern int get_arm_regnames (int, const char **, const char **, const char *const **);
extern bfd_boolean arm_symbol_is_valid (asymbol *, struct disassemble_info *);
/* Fetch the disassembler for a given BFD, if that support is available. */
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * score.h: New file.
+ * common.h: Add Score machine number.
+
2006-07-10 Jakub Jelinek <jakub@redhat.com>
* common.h (SHT_GNU_HASH, DT_GNU_HASH): Define.
#define EM_BLACKFIN 106 /* ADI Blackfin */
#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
#define EM_CRX 114 /* National Semiconductor CRX */
+#define EM_SCORE 135 /* Sunplus Score */
/* If it is necessary to assign new unofficial EM_* values, please pick large
random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision
--- /dev/null
+/* Score ELF support for BFD.
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ 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,
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _ELF_SCORE_H
+#define _ELF_SCORE_H
+
+#include "elf/reloc-macros.h"
+
+#define SCORE_SIMULATOR_ACTIVE 1
+#define OPC_PTMASK 0xc0000000 /* Parity-bit Mask */
+#define OPC16_PTMASK 0x00008000
+/* The parity-bit denotes. */
+#define OPC_32 0xc0000000 /* denotes 32b instruction, (default) */
+#define OPC_16 0x00000000 /* denotes 16b instruction */
+#define OPC_PE 0x8000 /* denotes parallel-execution instructions */
+#define EF_SCORE_HASENTRY 0x02
+#define GP_DISP_LABEL "_gp_disp"
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+/* Fix data dependency. */
+#define EF_SCORE_FIXDEP 0x00000001
+
+/* File contains position independent code. */
+#define EF_SCORE_PIC 0x00000002
+
+/* Defined and allocated common symbol. Value is virtual address. If
+ relocated, alignment must be preserved. */
+#define SHN_SCORE_TEXT 0xff01
+#define SHN_SCORE_DATA 0xff02
+/* Small common symbol. */
+#define SHN_SCORE_SCOMMON 0xff03
+
+/* Processor specific section flags. */
+
+/* This section must be in the global data area. */
+#define SHF_SCORE_GPREL 0x10000000
+
+/* This section should be merged. */
+#define SHF_SCORE_MERGE 0x20000000
+
+/* This section contains address data of size implied by section
+ element size. */
+#define SHF_SCORE_ADDR 0x40000000
+
+/* This section contains string data. */
+#define SHF_SCORE_STRING 0x80000000
+
+/* This section may not be stripped. */
+#define SHF_SCORE_NOSTRIP 0x08000000
+
+/* This section is local to threads. */
+#define SHF_SCORE_LOCAL 0x04000000
+
+/* Linker should generate implicit weak names for this section. */
+#define SHF_SCORE_NAMES 0x02000000
+
+/* Section contais text/data which may be replicated in other sections.
+ Linker should retain only one copy. */
+#define SHF_SCORE_NODUPES 0x01000000
+
+/* Processor specific dynamic array tags. */
+
+/* Base address of the segment. */
+#define DT_SCORE_BASE_ADDRESS 0x70000001
+/* Number of local global offset table entries. */
+#define DT_SCORE_LOCAL_GOTNO 0x70000002
+/* Number of entries in the .dynsym section. */
+#define DT_SCORE_SYMTABNO 0x70000003
+/* Index of first dynamic symbol in global offset table. */
+#define DT_SCORE_GOTSYM 0x70000004
+/* Index of first external dynamic symbol not referenced locally. */
+#define DT_SCORE_UNREFEXTNO 0x70000005
+/* Number of page table entries in global offset table. */
+#define DT_SCORE_HIPAGENO 0x70000006
+
+
+/* Processor specific section types. */
+
+
+/* Relocation types. */
+START_RELOC_NUMBERS (elf_score_reloc_type)
+ RELOC_NUMBER (R_SCORE_NONE, 0)
+ RELOC_NUMBER (R_SCORE_HI16, 1)
+ RELOC_NUMBER (R_SCORE_LO16, 2)
+ RELOC_NUMBER (R_SCORE_DUMMY1, 3)
+ RELOC_NUMBER (R_SCORE_24, 4)
+ RELOC_NUMBER (R_SCORE_PC19, 5)
+ RELOC_NUMBER (R_SCORE16_11, 6)
+ RELOC_NUMBER (R_SCORE16_PC8, 7)
+ RELOC_NUMBER (R_SCORE_ABS32, 8)
+ RELOC_NUMBER (R_SCORE_ABS16, 9)
+ RELOC_NUMBER (R_SCORE_DUMMY2, 10)
+ RELOC_NUMBER (R_SCORE_GP15, 11)
+ RELOC_NUMBER (R_SCORE_GNU_VTINHERIT, 12)
+ RELOC_NUMBER (R_SCORE_GNU_VTENTRY, 13)
+ RELOC_NUMBER (R_SCORE_GOT15, 14)
+ RELOC_NUMBER (R_SCORE_GOT_LO16, 15)
+ RELOC_NUMBER (R_SCORE_CALL15, 16)
+ RELOC_NUMBER (R_SCORE_GPREL32, 17)
+ RELOC_NUMBER (R_SCORE_REL32, 18)
+ RELOC_NUMBER (R_SCORE_DUMMY_HI16, 19)
+END_RELOC_NUMBERS (R_SCORE_max)
+
+#endif /* _ELF_SCORE_H */
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * score-datadep.h: New file.
+ * score-inst.h: New file.
+
2006-07-14 H.J. Lu <hongjiu.lu@intel.com>
* i386.h (i386_optab): Remove InvMem from maskmovq, movhlps,
--- /dev/null
+/* score-datadep.h -- Score Instructions data dependency table
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by:
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS 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.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef SCORE_DATA_DEPENDENCY_H
+#define SCORE_DATA_DEPENDENCY_H
+
+#define INSN_NAME_LEN 16
+
+enum insn_type_for_dependency
+{
+ D_pce,
+ D_cond_br,
+ D_cond_mv,
+ D_cached,
+ D_cachei,
+ D_ldst,
+ D_ldcombine,
+ D_mtcr,
+ D_mfcr,
+ D_mfsr,
+ D_mftlb,
+ D_mtptlb,
+ D_mtrtlb,
+ D_stlb,
+ D_all_insn
+};
+
+struct insn_to_dependency
+{
+ char *insn_name;
+ enum insn_type_for_dependency type;
+};
+
+struct data_dependency
+{
+ enum insn_type_for_dependency pre_insn_type;
+ char pre_reg[6];
+ enum insn_type_for_dependency cur_insn_type;
+ char cur_reg[6];
+ int bubblenum_7;
+ int bubblenum_5;
+ int warn_or_error; /* warning - 0; error - 1 */
+};
+
+static const struct insn_to_dependency insn_to_dependency_table[] =
+{
+ /* pce instruction. */
+ {"pce", D_pce},
+ /* conditional branch instruction. */
+ {"bcs", D_cond_br},
+ {"bcc", D_cond_br},
+ {"bgtu", D_cond_br},
+ {"bleu", D_cond_br},
+ {"beq", D_cond_br},
+ {"bne", D_cond_br},
+ {"bgt", D_cond_br},
+ {"ble", D_cond_br},
+ {"bge", D_cond_br},
+ {"blt", D_cond_br},
+ {"bmi", D_cond_br},
+ {"bpl", D_cond_br},
+ {"bvs", D_cond_br},
+ {"bvc", D_cond_br},
+ {"bcsl", D_cond_br},
+ {"bccl", D_cond_br},
+ {"bgtul", D_cond_br},
+ {"bleul", D_cond_br},
+ {"beql", D_cond_br},
+ {"bnel", D_cond_br},
+ {"bgtl", D_cond_br},
+ {"blel", D_cond_br},
+ {"bgel", D_cond_br},
+ {"bltl", D_cond_br},
+ {"bmil", D_cond_br},
+ {"bpll", D_cond_br},
+ {"bvsl", D_cond_br},
+ {"bvcl", D_cond_br},
+ {"bcs!", D_cond_br},
+ {"bcc!", D_cond_br},
+ {"bgtu!", D_cond_br},
+ {"bleu!", D_cond_br},
+ {"beq!", D_cond_br},
+ {"bne!", D_cond_br},
+ {"bgt!", D_cond_br},
+ {"ble!", D_cond_br},
+ {"bge!", D_cond_br},
+ {"blt!", D_cond_br},
+ {"bmi!", D_cond_br},
+ {"bpl!", D_cond_br},
+ {"bvs!", D_cond_br},
+ {"bvc!", D_cond_br},
+ {"brcs", D_cond_br},
+ {"brcc", D_cond_br},
+ {"brgtu", D_cond_br},
+ {"brleu", D_cond_br},
+ {"breq", D_cond_br},
+ {"brne", D_cond_br},
+ {"brgt", D_cond_br},
+ {"brle", D_cond_br},
+ {"brge", D_cond_br},
+ {"brlt", D_cond_br},
+ {"brmi", D_cond_br},
+ {"brpl", D_cond_br},
+ {"brvs", D_cond_br},
+ {"brvc", D_cond_br},
+ {"brcsl", D_cond_br},
+ {"brccl", D_cond_br},
+ {"brgtul", D_cond_br},
+ {"brleul", D_cond_br},
+ {"breql", D_cond_br},
+ {"brnel", D_cond_br},
+ {"brgtl", D_cond_br},
+ {"brlel", D_cond_br},
+ {"brgel", D_cond_br},
+ {"brltl", D_cond_br},
+ {"brmil", D_cond_br},
+ {"brpll", D_cond_br},
+ {"brvsl", D_cond_br},
+ {"brvcl", D_cond_br},
+ {"brcs!", D_cond_br},
+ {"brcc!", D_cond_br},
+ {"brgtu!", D_cond_br},
+ {"brleu!", D_cond_br},
+ {"breq!", D_cond_br},
+ {"brne!", D_cond_br},
+ {"brgt!", D_cond_br},
+ {"brle!", D_cond_br},
+ {"brge!", D_cond_br},
+ {"brlt!", D_cond_br},
+ {"brmi!", D_cond_br},
+ {"brpl!", D_cond_br},
+ {"brvs!", D_cond_br},
+ {"brvc!", D_cond_br},
+ {"brcsl!", D_cond_br},
+ {"brccl!", D_cond_br},
+ {"brgtul!", D_cond_br},
+ {"brleul!", D_cond_br},
+ {"breql!", D_cond_br},
+ {"brnel!", D_cond_br},
+ {"brgtl!", D_cond_br},
+ {"brlel!", D_cond_br},
+ {"brgel!", D_cond_br},
+ {"brltl!", D_cond_br},
+ {"brmil!", D_cond_br},
+ {"brpll!", D_cond_br},
+ {"brvsl!", D_cond_br},
+ {"brvcl!", D_cond_br},
+ /* conditional move instruction. */
+ {"mvcs", D_cond_mv},
+ {"mvcc", D_cond_mv},
+ {"mvgtu", D_cond_mv},
+ {"mvleu", D_cond_mv},
+ {"mveq", D_cond_mv},
+ {"mvne", D_cond_mv},
+ {"mvgt", D_cond_mv},
+ {"mvle", D_cond_mv},
+ {"mvge", D_cond_mv},
+ {"mvlt", D_cond_mv},
+ {"mvmi", D_cond_mv},
+ {"mvpl", D_cond_mv},
+ {"mvvs", D_cond_mv},
+ {"mvvc", D_cond_mv},
+ /* move spectial instruction. */
+ {"mtcr", D_mtcr},
+ {"mftlb", D_mftlb},
+ {"mtptlb", D_mtptlb},
+ {"mtrtlb", D_mtrtlb},
+ {"stlb", D_stlb},
+ {"mfcr", D_mfcr},
+ {"mfsr", D_mfsr},
+ /* cache instruction. */
+ {"cache 8", D_cached},
+ {"cache 9", D_cached},
+ {"cache 10", D_cached},
+ {"cache 11", D_cached},
+ {"cache 12", D_cached},
+ {"cache 13", D_cached},
+ {"cache 14", D_cached},
+ {"cache 24", D_cached},
+ {"cache 26", D_cached},
+ {"cache 27", D_cached},
+ {"cache 29", D_cached},
+ {"cache 30", D_cached},
+ {"cache 31", D_cached},
+ {"cache 0", D_cachei},
+ {"cache 1", D_cachei},
+ {"cache 2", D_cachei},
+ {"cache 3", D_cachei},
+ {"cache 4", D_cachei},
+ {"cache 16", D_cachei},
+ {"cache 17", D_cachei},
+ /* load/store instruction. */
+ {"lb", D_ldst},
+ {"lbu", D_ldst},
+ {"lbu!", D_ldst},
+ {"lbup!", D_ldst},
+ {"lh", D_ldst},
+ {"lhu", D_ldst},
+ {"lh!", D_ldst},
+ {"lhp!", D_ldst},
+ {"lw", D_ldst},
+ {"lw!", D_ldst},
+ {"lwp!", D_ldst},
+ {"sb", D_ldst},
+ {"sb!", D_ldst},
+ {"sbp!", D_ldst},
+ {"sh", D_ldst},
+ {"sh!", D_ldst},
+ {"shp!", D_ldst},
+ {"sw", D_ldst},
+ {"sw!", D_ldst},
+ {"swp!", D_ldst},
+ {"alw", D_ldst},
+ {"asw", D_ldst},
+ {"push!", D_ldst},
+ {"pushhi!", D_ldst},
+ {"pop!", D_ldst},
+ {"pophi!", D_ldst},
+ {"ldc1", D_ldst},
+ {"ldc2", D_ldst},
+ {"ldc3", D_ldst},
+ {"stc1", D_ldst},
+ {"stc2", D_ldst},
+ {"stc3", D_ldst},
+ {"scb", D_ldst},
+ {"scw", D_ldst},
+ {"sce", D_ldst},
+ /* load combine instruction. */
+ {"lcb", D_ldcombine},
+ {"lcw", D_ldcombine},
+ {"lce", D_ldcombine},
+};
+
+static const struct data_dependency data_dependency_table[] =
+{
+ /* Condition register. */
+ {D_mtcr, "cr1", D_pce, "", 2, 1, 1},
+ {D_mtcr, "cr1", D_cond_br, "", 1, 0, 1},
+ {D_mtcr, "cr1", D_cond_mv, "", 1, 0, 1},
+ /* Status regiser. */
+ {D_mtcr, "cr0", D_all_insn, "", 5, 4, 0},
+ /* CCR regiser. */
+ {D_mtcr, "cr4", D_all_insn, "", 6, 5, 0},
+ /* EntryHi/EntryLo register. */
+ {D_mftlb, "", D_mtptlb, "", 1, 1, 1},
+ {D_mftlb, "", D_mtrtlb, "", 1, 1, 1},
+ {D_mftlb, "", D_stlb, "", 1, 1,1},
+ {D_mftlb, "", D_mfcr, "cr11", 1, 1, 1},
+ {D_mftlb, "", D_mfcr, "cr12", 1, 1, 1},
+ /* Index register. */
+ {D_stlb, "", D_mtptlb, "", 1, 1, 1},
+ {D_stlb, "", D_mftlb, "", 1, 1, 1},
+ {D_stlb, "", D_mfcr, "cr8", 2, 2, 1},
+ /* Cache. */
+ {D_cached, "", D_ldst, "", 1, 1, 0},
+ {D_cached, "", D_ldcombine, "", 1, 1, 0},
+ {D_cachei, "", D_all_insn, "", 5, 4, 0},
+ /* Load combine. */
+ {D_ldcombine, "", D_mfsr, "sr1", 3, 3, 1},
+};
+
+#endif
--- /dev/null
+/* score-inst.h -- Score Instructions Table
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by:
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS 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.
+
+ GAS 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 GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef SCORE_INST_H
+#define SCORE_INST_H
+
+#define LDST_UNALIGN_MASK 0x0000007f
+#define UA_LCB 0x00000060
+#define UA_LCW 0x00000062
+#define UA_LCE 0x00000066
+#define UA_SCB 0x00000068
+#define UA_SCW 0x0000006a
+#define UA_SCE 0x0000006e
+#define UA_LL 0x0000000c
+#define UA_SC 0x0000000e
+#define LDST16_RR_MASK 0x0000000f
+#define N16_LW 8
+#define N16_LH 9
+#define N16_POP 10
+#define N16_LBU 11
+#define N16_SW 12
+#define N16_SH 13
+#define N16_PUSH 14
+#define N16_SB 15
+#define LDST16_RI_MASK 0x7007
+#define N16_LWP 0x7000
+#define N16_LHP 0x7001
+#define N16_LBUP 0x7003
+#define N16_SWP 0x7004
+#define N16_SHP 0x7005
+#define N16_SBP 0x7007
+#define N16_LIU 0x5000
+
+#define OPC_PSEUDOLDST_MASK 0x00000007
+
+enum
+{
+ INSN_LW = 0,
+ INSN_LH = 1,
+ INSN_LHU = 2,
+ INSN_LB = 3,
+ INSN_SW = 4,
+ INSN_SH = 5,
+ INSN_LBU = 6,
+ INSN_SB = 7,
+};
+
+/* Sub opcdoe opcode. */
+enum
+{
+ INSN16_LBU = 11,
+ INSN16_LH = 9,
+ INSN16_LW = 8,
+ INSN16_SB = 15,
+ INSN16_SH = 13,
+ INSN16_SW = 12,
+};
+
+enum
+{
+ LDST_NOUPDATE = 0,
+ LDST_PRE = 1,
+ LDST_POST = 2,
+};
+
+enum score_insn_type
+{
+ Rd_I4,
+ Rd_I5,
+ Rd_rvalueBP_I5,
+ Rd_lvalueBP_I5,
+ Rd_Rs_I5,
+ x_Rs_I5,
+ x_I5_x,
+ Rd_I8,
+ Rd_Rs_I14,
+ I15,
+ Rd_I16,
+ Rd_rvalueRs_SI10,
+ Rd_lvalueRs_SI10,
+ Rd_rvalueRs_preSI12,
+ Rd_rvalueRs_postSI12,
+ Rd_lvalueRs_preSI12,
+ Rd_lvalueRs_postSI12,
+ Rd_Rs_SI14,
+ Rd_rvalueRs_SI15,
+ Rd_lvalueRs_SI15,
+ Rd_SI16,
+ PC_DISP8div2,
+ PC_DISP11div2,
+ PC_DISP19div2,
+ PC_DISP24div2,
+ Rd_Rs_Rs,
+ x_Rs_x,
+ x_Rs_Rs,
+ Rd_Rs_x,
+ Rd_x_Rs,
+ Rd_x_x,
+ Rd_Rs,
+ Rd_HighRs,
+ Rd_lvalueRs,
+ Rd_rvalueRs,
+ Rd_lvalue32Rs,
+ Rd_rvalue32Rs,
+ x_Rs,
+ NO_OPD,
+ NO16_OPD,
+ OP5_rvalueRs_SI15,
+ I5_Rs_Rs_I5_OP5,
+ x_rvalueRs_post4,
+ Rd_rvalueRs_post4,
+ Rd_x_I5,
+ Rd_lvalueRs_post4,
+ x_lvalueRs_post4,
+ Rd_LowRs,
+ Rd_Rs_Rs_imm,
+ Insn_Type_PCE,
+ Insn_Type_SYN,
+ Insn_GP,
+ Insn_PIC,
+};
+
+enum score_data_type
+{
+ _IMM4 = 0,
+ _IMM5,
+ _IMM8,
+ _IMM14,
+ _IMM15,
+ _IMM16,
+ _SIMM10 = 6,
+ _SIMM12,
+ _SIMM14,
+ _SIMM15,
+ _SIMM16,
+ _SIMM14_NEG = 11,
+ _IMM16_NEG,
+ _SIMM16_NEG,
+ _IMM20,
+ _IMM25,
+ _DISP8div2 = 16,
+ _DISP11div2,
+ _DISP19div2,
+ _DISP24div2,
+ _VALUE,
+ _VALUE_HI16,
+ _VALUE_LO16,
+ _VALUE_LDST_LO16 = 23,
+ _SIMM16_LA,
+ _IMM5_RSHIFT_1,
+ _IMM5_RSHIFT_2,
+ _SIMM16_LA_POS,
+ _IMM5_RANGE_8_31,
+ _IMM10_RSHIFT_2,
+ _GP_IMM15 = 30,
+ _GP_IMM14 = 31,
+ _SIMM16_pic = 42, /* Index in score_df_range. */
+ _IMM16_LO16_pic = 43,
+ _IMM16_pic = 44,
+};
+
+#define REG_TMP 1
+
+#define OP_REG_TYPE (1 << 6)
+#define OP_IMM_TYPE (1 << 7)
+#define OP_SH_REGD (OP_REG_TYPE |20)
+#define OP_SH_REGS1 (OP_REG_TYPE |15)
+#define OP_SH_REGS2 (OP_REG_TYPE |10)
+#define OP_SH_I (OP_IMM_TYPE | 1)
+#define OP_SH_RI15 (OP_IMM_TYPE | 0)
+#define OP_SH_I12 (OP_IMM_TYPE | 3)
+#define OP_SH_DISP24 (OP_IMM_TYPE | 1)
+#define OP_SH_DISP19_p1 (OP_IMM_TYPE |15)
+#define OP_SH_DISP19_p2 (OP_IMM_TYPE | 1)
+#define OP_SH_I5 (OP_IMM_TYPE |10)
+#define OP_SH_I10 (OP_IMM_TYPE | 5)
+#define OP_SH_COPID (OP_IMM_TYPE | 5)
+#define OP_SH_TRAPI5 (OP_IMM_TYPE |15)
+#define OP_SH_I15 (OP_IMM_TYPE |10)
+
+#define OP16_SH_REGD (OP_REG_TYPE | 8)
+#define OP16_SH_REGS1 (OP_REG_TYPE | 4)
+#define OP16_SH_I45 (OP_IMM_TYPE | 3)
+#define OP16_SH_I8 (OP_IMM_TYPE | 0)
+#define OP16_SH_DISP8 (OP_IMM_TYPE | 0)
+#define OP16_SH_DISP11 (OP_IMM_TYPE | 1)
+
+struct datafield_range
+{
+ int data_type;
+ int bits;
+ int range[2];
+};
+
+struct datafield_range score_df_range[] =
+{
+ {_IMM4, 4, {0, (1 << 4) - 1}}, /* ( 0 ~ 15 ) */
+ {_IMM5, 5, {0, (1 << 5) - 1}}, /* ( 0 ~ 31 ) */
+ {_IMM8, 8, {0, (1 << 8) - 1}}, /* ( 0 ~ 255 ) */
+ {_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 16383) */
+ {_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
+ {_IMM16, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
+ {_SIMM10, 10, {-(1 << 9), (1 << 9) - 1}}, /* ( -512 ~ 511 ) */
+ {_SIMM12, 12, {-(1 << 11), (1 << 11) - 1}}, /* ( -2048 ~ 2047 ) */
+ {_SIMM14, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8192 ~ 8191 ) */
+ {_SIMM15, 15, {-(1 << 14), (1 << 14) - 1}}, /* (-16384 ~ 16383) */
+ {_SIMM16, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
+ {_SIMM14_NEG, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8191 ~ 8192 ) */
+ {_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* (-65535 ~ 0 ) */
+ {_SIMM16_NEG, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
+ {_IMM20, 20, {0, (1 << 20) - 1}},
+ {_IMM25, 25, {0, (1 << 25) - 1}},
+ {_DISP8div2, 8, {-(1 << 8), (1 << 8) - 1}}, /* ( -256 ~ 255 ) */
+ {_DISP11div2, 11, {0, 0}},
+ {_DISP19div2, 19, {-(1 << 19), (1 << 19) - 1}}, /* (-524288 ~ 524287) */
+ {_DISP24div2, 24, {0, 0}},
+ {_VALUE, 32, {0, ((unsigned int)1 << 31) - 1}},
+ {_VALUE_HI16, 16, {0, (1 << 16) - 1}},
+ {_VALUE_LO16, 16, {0, (1 << 16) - 1}},
+ {_VALUE_LDST_LO16, 16, {0, (1 << 16) - 1}},
+ {_SIMM16_LA, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
+ {_IMM5_RSHIFT_1, 5, {0, (1 << 6) - 1}}, /* ( 0 ~ 63 ) */
+ {_IMM5_RSHIFT_2, 5, {0, (1 << 7) - 1}}, /* ( 0 ~ 127 ) */
+ {_SIMM16_LA_POS, 16, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
+ {_IMM5_RANGE_8_31, 5, {8, 31}}, /* But for cop0 the valid data : (8 ~ 31). */
+ {_IMM10_RSHIFT_2, 10, {-(1 << 11), (1 << 11) - 1}}, /* For ldc#, stc#. */
+ {_SIMM10, 10, {0, (1 << 10) - 1}}, /* ( -1024 ~ 1023 ) */
+ {_SIMM12, 12, {0, (1 << 12) - 1}}, /* ( -2048 ~ 2047 ) */
+ {_SIMM14, 14, {0, (1 << 14) - 1}}, /* ( -8192 ~ 8191 ) */
+ {_SIMM15, 15, {0, (1 << 15) - 1}}, /* (-16384 ~ 16383) */
+ {_SIMM16, 16, {0, (1 << 16) - 1}}, /* (-65536 ~ 65536) */
+ {_SIMM14_NEG, 14, {0, (1 << 16) - 1}}, /* ( -8191 ~ 8192 ) */
+ {_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
+ {_SIMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
+ {_IMM20, 20, {0, (1 << 20) - 1}}, /* (-32768 ~ 32767) */
+ {_IMM25, 25, {0, (1 << 25) - 1}}, /* (-32768 ~ 32767) */
+ {_GP_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 65535) */
+ {_GP_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 65535) */
+ {_SIMM16_pic, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
+ {_IMM16_LO16_pic, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
+ {_IMM16_pic, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
+};
+
+struct shift_bitmask
+{
+ int opd_type;
+ int opd_num;
+ struct datafield_range *df_range;
+ int sh[4];
+ long fieldbits[4];
+};
+
+struct shift_bitmask score_sh_bits_map[] =
+{
+ {
+ Rd_I4, 2, &score_df_range[_IMM4],
+ {OP16_SH_REGD, OP16_SH_I45, 0, 0},
+ {0xf, 0xf, 0, 0},
+ },
+ {
+ Rd_I5, 2, &score_df_range[_IMM5],
+ {OP16_SH_REGD, OP16_SH_I45, 0, 0},
+ {0xf, 0x1f, 0, 0},
+ },
+ {
+ Rd_rvalueBP_I5, 2, &score_df_range[_IMM5],
+ {OP16_SH_REGD, OP16_SH_I45, 0, 0},
+ {0xf, 0x1f, 0, 0},
+ },
+ {
+ Rd_lvalueBP_I5, 2, &score_df_range[_IMM5],
+ {OP16_SH_REGD, OP16_SH_I45, 0, 0},
+ {0xf, 0x1f, 0, 0},
+ },
+ {
+ Rd_Rs_I5, 3, &score_df_range[_IMM5],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I5, 0},
+ {0x1f, 0x1f, 0x1f, 0},
+ },
+ {
+ x_Rs_I5, 2, &score_df_range[_IMM5],
+ {OP_SH_REGS1, OP_SH_I5, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ x_I5_x, 1, &score_df_range[_IMM5],
+ {OP_SH_TRAPI5, 0, 0, 0},
+ {0x1f, 0, 0, 0},
+ },
+ {
+ Rd_I8, 2, &score_df_range[_IMM8],
+ {OP16_SH_REGD, OP16_SH_I8, 0, 0},
+ {0xf, 0xff, 0, 0},
+ },
+ {
+ Rd_Rs_I14, 3, &score_df_range[_IMM14],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I, 0},
+ {0x1f, 0x1f, 0x3fff, 0},
+ },
+ {
+ I15, 1, &score_df_range[_IMM15],
+ {OP_SH_I15, 0, 0, 0},
+ {0x7fff, 0, 0, 0},
+ },
+ {
+ Rd_I16, 2, &score_df_range[_IMM16],
+ {OP_SH_REGD, OP_SH_I, 0, 0},
+ {0x1f, 0xffff, 0, 0},
+ },
+ {
+ Rd_rvalueRs_SI10, 3, &score_df_range[_SIMM10],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I10, 0},
+ {0x1f, 0x1f, 0x3ff, 0},
+ },
+ {
+ Rd_lvalueRs_SI10, 3, &score_df_range[_SIMM10],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I10, 0},
+ {0x1f, 0x1f, 0x3ff, 0},
+ },
+ {
+ Rd_rvalueRs_preSI12, 3, &score_df_range[_SIMM12],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I12, 0},
+ {0xf, 0xf, 0xfff, 0},
+ },
+ {
+ Rd_rvalueRs_postSI12, 3, &score_df_range[_SIMM12],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I12, 0},
+ {0xf, 0xf, 0xfff, 0},
+ },
+ {
+ Rd_lvalueRs_preSI12, 3, &score_df_range[_SIMM12],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I12, 0},
+ {0xf, 0xf, 0xfff, 0},
+ },
+ {
+ Rd_lvalueRs_postSI12, 3, &score_df_range[_SIMM12],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I12, 0},
+ {0xf, 0xf, 0xfff, 0},
+ },
+ {
+ Rd_Rs_SI14, 3, &score_df_range[_SIMM14],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_I, 0},
+ {0x1f, 0x1f, 0x3fff, 0},
+ },
+ {
+ Rd_rvalueRs_SI15, 3, &score_df_range[_SIMM15],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_RI15, 0},
+ {0x1f, 0x1f, 0x7fff, 0},
+ },
+ {
+ Rd_lvalueRs_SI15, 3, &score_df_range[_SIMM15],
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_RI15, 0},
+ {0x1f, 0x1f, 0x7fff, 0},
+ },
+ {
+ Rd_SI16, 2, &score_df_range[_SIMM16],
+ {OP_SH_REGD, OP_SH_I, 0, 0},
+ {0x1f, 0xffff, 0, 0},
+ },
+ {
+ PC_DISP8div2, 1, &score_df_range[_DISP8div2],
+ {OP16_SH_DISP8, 0, 0, 0},
+ {0xff, 0, 0, 0},
+ },
+ {
+ PC_DISP11div2, 1, &score_df_range[_DISP11div2],
+ {OP16_SH_DISP11, 0, 0, 0},
+ {0x7ff, 0, 0, 0},
+ },
+ {
+ PC_DISP19div2, 2, &score_df_range[_DISP19div2],
+ {OP_SH_DISP19_p1, OP_SH_DISP19_p2, 0, 0},
+ {0x3ff, 0x1ff, 0, 0},
+ },
+ {
+ PC_DISP24div2, 1, &score_df_range[_DISP24div2],
+ {OP_SH_DISP24, 0, 0, 0},
+ {0xffffff, 0, 0, 0},
+ },
+ {
+ Rd_Rs_Rs, 3, NULL,
+ {OP_SH_REGD, OP_SH_REGS1, OP_SH_REGS2, 0},
+ {0x1f, 0x1f, 0x1f, 0}
+ },
+ {
+ Rd_Rs_x, 2, NULL,
+ {OP_SH_REGD, OP_SH_REGS1, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ Rd_x_Rs, 2, NULL,
+ {OP_SH_REGD, OP_SH_REGS2, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ Rd_x_x, 1, NULL,
+ {OP_SH_REGD, 0, 0, 0},
+ {0x1f, 0, 0, 0},
+ },
+ {
+ x_Rs_Rs, 2, NULL,
+ {OP_SH_REGS1, OP_SH_REGS2, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ x_Rs_x, 1, NULL,
+ {OP_SH_REGS1, 0, 0, 0},
+ {0x1f, 0, 0, 0},
+ },
+ {
+ Rd_Rs, 2, NULL,
+ {OP16_SH_REGD, OP16_SH_REGS1, 0, 0},
+ {0xf, 0xf, 0, 0},
+ },
+ {
+ Rd_HighRs, 2, NULL,
+ {OP16_SH_REGD, OP16_SH_REGS1, 0, 0},
+ {0xf, 0xf, 0x1f, 0},
+ },
+ {
+ Rd_rvalueRs, 2, NULL,
+ {OP16_SH_REGD, OP16_SH_REGS1, 0, 0},
+ {0xf, 0xf, 0, 0},
+ },
+ {
+ Rd_lvalueRs, 2, NULL,
+ {OP16_SH_REGD, OP16_SH_REGS1, 0, 0},
+ {0xf, 0xf, 0, 0}
+ },
+ {
+ Rd_lvalue32Rs, 2, NULL,
+ {OP_SH_REGD, OP_SH_REGS1, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ Rd_rvalue32Rs, 2, NULL,
+ {OP_SH_REGD, OP_SH_REGS1, 0, 0},
+ {0x1f, 0x1f, 0, 0},
+ },
+ {
+ x_Rs, 1, NULL,
+ {OP16_SH_REGS1, 0, 0, 0},
+ {0xf, 0, 0, 0},
+ },
+ {
+ NO_OPD, 0, NULL,
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ },
+ {
+ NO16_OPD, 0, NULL,
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ },
+};
+
+struct asm_opcode
+{
+ /* Instruction name. */
+ const char *template;
+
+ /* Instruction Opcode. */
+ unsigned long value;
+
+ /* Instruction bit mask. */
+ unsigned long bitmask;
+
+ /* Relax instruction opcode. 0x8000 imply no relaxation. */
+ unsigned long relax_value;
+
+ /* Instruction type. */
+ enum score_insn_type type;
+
+ /* Function to call to parse args. */
+ void (*parms) (char *);
+};
+
+enum insn_class
+{
+ INSN_CLASS_16,
+ INSN_CLASS_32,
+ INSN_CLASS_PCE,
+ INSN_CLASS_SYN
+};
+
+#endif
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * emulparams/scoreelf.sh: New file.
+ * emultempl/scoreelf.em: New file.
+ * Makefile.am: Add Score files.
+ * Makefile.in: Regenerate.
+ * configure.tgt: Add Score target.
+ * NEWS: Mention new target support.
+
2006-09-16 Nick Clifton <nickc@redhat.com>
Pedro Alves <pedro_alves@portugalmail.pt>
eppcpe.o \
eppclynx.o \
eriscix.o \
+ escoreelf.o \
esh.o \
eshelf32.o \
eshlelf32.o \
eriscix.c: $(srcdir)/emulparams/riscix.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
${GENSCRIPTS} riscix "$(tdir_riscix)"
+escoreelf.c: $(srcdir)/emulparams/scoreelf.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/scoreelf.em \
+ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} scoreelf "$(tdir_scoreelf)"
esh.c: $(srcdir)/emulparams/sh.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/sh.sc ${GEN_DEPENDS}
${GENSCRIPTS} sh "$(tdir_sh)"
eppcpe.o \
eppclynx.o \
eriscix.o \
+ escoreelf.o \
esh.o \
eshelf32.o \
eshlelf32.o \
eriscix.c: $(srcdir)/emulparams/riscix.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
${GENSCRIPTS} riscix "$(tdir_riscix)"
+escoreelf.c: $(srcdir)/emulparams/scoreelf.sh \
+ $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/scoreelf.em \
+ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} scoreelf "$(tdir_scoreelf)"
esh.c: $(srcdir)/emulparams/sh.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/sh.sc ${GEN_DEPENDS}
${GENSCRIPTS} sh "$(tdir_sh)"
-*- text -*-
+* Add support for Score target.
+
* ELF: Add --dynamic-list option to specify a list of global symbols
whose references shouldn't be bound to the definition within the
shared library, or a list of symbols which should be added to the
tdir_elf64_s390=`echo ${targ_alias} | sed -e 's/s390/s390x/'`
fi
;;
+score-*-elf) targ_emul=scoreelf ;;
sh-*-linux*) targ_emul=shlelf_linux
targ_extra_emuls=shelf_linux
targ_extra_libpath=shelf_linux ;;
--- /dev/null
+MACHINE=
+SCRIPT_NAME=elf
+TEMPLATE_NAME=elf32
+OUTPUT_FORMAT="elf32-bigscore"
+BIG_OUTPUT_FORMAT="elf32-bigscore"
+LITTLE_OUTPUT_FORMAT="elf32-littlescore"
+GROUP="-lm -lc -lglsim -lgcc -lstdc++"
+
+TEXT_START_ADDR=0x00000000
+MAXPAGESIZE=256
+NONPAGED_TEXT_START_ADDR=0x0400000
+SHLIB_TEXT_START_ADDR=0x5ffe0000
+OTHER_GOT_SYMBOLS='
+ _gp = ALIGN(16) + 0x3ff0;
+'
+
+OTHER_BSS_START_SYMBOLS='_bss_start__ = . + ALIGN(4);'
+OTHER_BSS_END_SYMBOLS='_bss_end__ = . ; __bss_end__ = . ; __end__ = . ;'
+DATA_START_SYMBOLS='_fdata = . ;'
+SDATA_START_SYMBOLS='_sdata_begin = . ;'
+OTHER_BSS_SYMBOLS='
+ _bss_start = ALIGN(4) ;
+'
+# This sets the stack to the top of the simulator memory (2^19 bytes).
+STACK_ADDR=0x8000000
+
+ARCH=score
+MACHINE=
+ENTRY=_start
+EMBEDDED=yes
+GENERATE_SHLIB_SCRIPT=yes
--- /dev/null
+# This shell script emits a C file. -*- C -*-
+# Copyright 2006 Free Software Foundation, Inc.
+# Contributed by:
+# Mei Ligang (ligang@sunnorth.com.cn)
+# Pei-Lin Tsai (pltsai@sunplus.com)
+
+# This file is part of GLD, the Gnu Linker.
+#
+# 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., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+
+# This file is sourced from elf32.em, and defines extra score-elf
+# specific routines.
+#
+cat >>e${EMULATION_NAME}.c <<EOF
+
+static void
+gld${EMULATION_NAME}_before_parse ()
+{
+#ifndef TARGET_ /* I.e., if not generic. */
+ ldfile_set_output_arch ("`echo ${ARCH}`");
+#endif /* not TARGET_ */
+ config.dynamic_link = ${DYNAMIC_LINK-true};
+ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+}
+
+static void
+score_elf_after_open (void)
+{
+ if (strstr (bfd_get_target (output_bfd), "score") == NULL)
+ {
+ /* The score backend needs special fields in the output hash structure.
+ These will only be created if the output format is an score format,
+ hence we do not support linking and changing output formats at the
+ same time. Use a link followed by objcopy to change output formats. */
+ einfo ("%F%X%P: error: cannot change output format whilst linking S+core binaries\n");
+ return;
+ }
+
+ /* Call the standard elf routine. */
+ gld${EMULATION_NAME}_after_open ();
+}
+
+EOF
+
+# Define some shell vars to insert bits of code into the standard elf
+# parse_args and list_options functions.
+#
+PARSE_AND_LIST_PROLOGUE=''
+PARSE_AND_LIST_SHORTOPTS=
+PARSE_AND_LIST_LONGOPTS=''
+PARSE_AND_LIST_OPTIONS=''
+PARSE_AND_LIST_ARGS_CASES=''
+
+# We have our own after_open and before_allocation functions, but they call
+# the standard routines, so give them a different name.
+LDEMUL_AFTER_OPEN=score_elf_after_open
+
+# Replace the elf before_parse function with our own.
+LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse
+
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * ld-elf/merge.d: Add special case for Score target.
+ * ld-elfcomm/elfcomm.exp: Likewise.
+ * ld-srec/srec.exp: Likewise.
+
2006-09-15 H.J. Lu <hongjiu.lu@intel.com>
* ld-scripts/overlay-size.t: Discard .reginfo sections.
#ld: -T merge.ld
#objdump: -s
#xfail: "arc-*-*" "avr-*-*" "bfin-*-*" "cris*-*-*" "crx-*-*" "d10v-*-*" "d30v-*-*"
-#xfail: "dlx-*-*" "fr30-*-*" "frv-*-*" "hppa*-*-*" "h8300-*-*"
+#xfail: "dlx-*-*" "fr30-*-*" "frv-*-*" "hppa*-*-*" "h8300-*-*" "score-*-*"
#xfail: "i370-*-*" "i860-*-*" "i960-*-*" "ip2k-*-*" "iq2000-*-*"
#xfail: "mcore-*-*" "mn102*-*-*" "mips*-*-*" "ms1-*-*" "msp430-*-*"
#xfail: "or32-*-*" "pj-*-*" "sparc*-*-*" "vax-*-*" "xstormy16-*-*" "xtensa-*-*"
# Expect script for common symbol tests
-# Copyright 2003, 2005 Free Software Foundation, Inc.
+# Copyright 2003, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
untested $test1c2
return
}
+if { [istarget score-*-*] } {
+ untested $test1w1
+ untested $test1w2
+ untested $test1c1
+ untested $test1c2
+ return
+}
proc dump_common1 { testname } {
global exec_output
# Test linking directly to S-records.
# By Ian Lance Taylor, Cygnus Support.
-# Copyright 1999, 2000, 2001, 2002, 2003
+# Copyright 1999, 2000, 2001, 2002, 2003, 2006
# Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# emulation tries to write pe-specific information to the PE headers
# in the output bfd, but it's not a PE bfd (it's an srec bfd)
setup_xfail "*-*-cygwin*" "*-*-mingw*" "*-*-pe*" "*-*-winnt*"
+setup_xfail "score-*-*"
run_srec_test $test1 "tmpdir/sr1.o tmpdir/sr2.o"
setup_xfail "hppa*-*-*"
setup_xfail "ia64-*-*"
setup_xfail "*-*-cygwin*" "*-*-mingw*" "*-*-pe*" "*-*-winnt*"
+setup_xfail "score-*-*"
run_srec_test $test2 "tmpdir/sr3.o"
+2006-09-17 Mei Ligang <ligang@sunnorth.com.cn>
+
+ * score-dis.c: New file.
+ * score-opc.h: New file.
+ * Makefile.am: Add Score files.
+ * Makefile.in: Regenerate.
+ * configure.in: Add support for Score target.
+ * configure: Regenerate.
+ * disassemble.c: Add support for Score target.
+
2006-09-16 Nick Clifton <nickc@redhat.com>
Pedro Alves <pedro_alves@portugalmail.pt>
mcore-opc.h \
mt-desc.h mt-opc.h \
openrisc-desc.h openrisc-opc.h \
+ score-opc.h \
sh-opc.h \
sh64-opc.h \
sysdep.h \
s390-mkopc.c \
s390-opc.c \
s390-dis.c \
+ score-dis.c \
sh-dis.c \
sh64-dis.c \
sh64-opc.c \
ppc-opc.lo \
s390-dis.lo \
s390-opc.lo \
+ score-dis.lo \
sh-dis.lo \
sh64-dis.lo \
sh64-opc.lo \
s390-dis.lo: s390-dis.c $(INCDIR)/ansidecl.h sysdep.h \
config.h $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h \
$(INCDIR)/opcode/s390.h
+score-dis.lo: score-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
+ $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h score-opc.h \
+ $(INCDIR)/bfdlink.h opintl.h $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h \
+ $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/elf/score.h \
+ $(INCDIR)/elf/reloc-macros.h
sh-dis.lo: sh-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
sh-opc.h $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/dis-asm.h
sh64-dis.lo: sh64-dis.c $(INCDIR)/dis-asm.h $(BFD_H) \
mcore-opc.h \
mt-desc.h mt-opc.h \
openrisc-desc.h openrisc-opc.h \
+ score-opc.h \
sh-opc.h \
sh64-opc.h \
sysdep.h \
s390-mkopc.c \
s390-opc.c \
s390-dis.c \
+ score-dis.c \
sh-dis.c \
sh64-dis.c \
sh64-opc.c \
ppc-opc.lo \
s390-dis.lo \
s390-opc.lo \
+ score-dis.lo \
sh-dis.lo \
sh64-dis.lo \
sh64-opc.lo \
s390-dis.lo: s390-dis.c $(INCDIR)/ansidecl.h sysdep.h \
config.h $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h \
$(INCDIR)/opcode/s390.h
+score-dis.lo: score-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
+ $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h score-opc.h \
+ $(INCDIR)/bfdlink.h opintl.h $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h \
+ $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/elf/score.h \
+ $(INCDIR)/elf/reloc-macros.h
sh-dis.lo: sh-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
sh-opc.h $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/dis-asm.h
sh64-dis.lo: sh64-dis.c $(INCDIR)/dis-asm.h $(BFD_H) \
XGETTEXT=
GMSGFMT=
POSUB=
-if test -f ../intl/config.intl; then
- . ../intl/config.intl
+
+if test -f ../intl/config.intl; then
+ . ../intl/config.intl
fi
echo "$as_me:$LINENO: checking whether NLS is requested" >&5
echo $ECHO_N "checking whether NLS is requested... $ECHO_C" >&6
bfd_romp_arch) ;;
bfd_rs6000_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_s390_arch) ta="$ta s390-dis.lo s390-opc.lo" ;;
+ bfd_score_arch) ta="$ta score-dis.lo" ;;
bfd_sh_arch)
# We can't decide what we want just from the CPU family.
# We want SH5 support unless a specific version of sh is
bfd_romp_arch) ;;
bfd_rs6000_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_s390_arch) ta="$ta s390-dis.lo s390-opc.lo" ;;
+ bfd_score_arch) ta="$ta score-dis.lo" ;;
bfd_sh_arch)
# We can't decide what we want just from the CPU family.
# We want SH5 support unless a specific version of sh is
/* Select disassembly routine for specified architecture.
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005 Free Software Foundation, Inc.
+ 2004, 2005, 2006 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
#define ARCH_powerpc
#define ARCH_rs6000
#define ARCH_s390
+#define ARCH_score
#define ARCH_sh
#define ARCH_sparc
#define ARCH_tic30
disassemble = print_insn_s390;
break;
#endif
+#ifdef ARCH_score
+ case bfd_arch_score:
+ if (bfd_big_endian (abfd))
+ disassemble = print_insn_big_score;
+ else
+ disassemble = print_insn_little_score;
+ break;
+#endif
#ifdef ARCH_sh
case bfd_arch_sh:
disassemble = print_insn_sh;
--- /dev/null
+/* Instruction printing code for Score
+ Copyright 2006 Free Software Foundation, Inc.
+ Contributed by:
+ Mei Ligang (ligang@sunnorth.com.cn)
+ Pei-Lin Tsai (pltsai@sunplus.com)
+
+ This file is part of libopcodes.
+
+ 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., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "dis-asm.h"
+#define DEFINE_TABLE
+#include "score-opc.h"
+#include "opintl.h"
+#include "bfd.h"
+
+/* FIXME: This shouldn't be done here. */
+#include "elf-bfd.h"
+#include "elf/internal.h"
+#include "elf/score.h"
+
+#ifndef streq
+#define streq(a,b) (strcmp ((a), (b)) == 0)
+#endif
+
+#ifndef strneq
+#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
+#endif
+
+#ifndef NUM_ELEM
+#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
+#endif
+
+typedef struct
+{
+ const char *name;
+ const char *description;
+ const char *reg_names[32];
+} score_regname;
+
+static score_regname regnames[] =
+{
+ {"gcc", "Select register names used by GCC",
+ {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20",
+ "r21", "r22", "r23", "r24", "r25", "r26", "r27", "gp", "r29", "r30", "r31"}},
+};
+
+static unsigned int regname_selected = 0;
+
+#define NUM_SCORE_REGNAMES NUM_ELEM (regnames)
+#define score_regnames regnames[regname_selected].reg_names
+
+/* Print one instruction from PC on INFO->STREAM.
+ Return the size of the instruction. */
+static int
+print_insn_score32 (bfd_vma pc, struct disassemble_info *info, long given)
+{
+ struct score_opcode *insn;
+ void *stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ for (insn = score_opcodes; insn->assembler; insn++)
+ {
+ if ((insn->mask & 0xffff0000) && (given & insn->mask) == insn->value)
+ {
+ char *c;
+
+ for (c = insn->assembler; *c; c++)
+ {
+ if (*c == '%')
+ {
+ switch (*++c)
+ {
+ case 'j':
+ {
+ int target;
+
+ if (info->flags & INSN_HAS_RELOC)
+ pc = 0;
+ target = (pc & 0xfe000000) | (given & 0x01fffffe);
+ (*info->print_address_func) (target, info);
+ }
+ break;
+ case 'b':
+ {
+ /* Sign-extend a 20-bit number. */
+#define SEXT20(x) ((((x) & 0xfffff) ^ (~ 0x7ffff)) + 0x80000)
+ int disp = ((given & 0x01ff8000) >> 5) | (given & 0x3fe);
+ int target = (pc + SEXT20 (disp));
+
+ (*info->print_address_func) (target, info);
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int bitstart = *c++ - '0';
+ int bitend = 0;
+
+ while (*c >= '0' && *c <= '9')
+ bitstart = (bitstart * 10) + *c++ - '0';
+
+ switch (*c)
+ {
+ case '-':
+ c++;
+ while (*c >= '0' && *c <= '9')
+ bitend = (bitend * 10) + *c++ - '0';
+
+ if (!bitend)
+ abort ();
+
+ switch (*c)
+ {
+ case 'r':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%s", score_regnames[reg]);
+ }
+ break;
+ case 'd':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%ld", reg);
+ }
+ break;
+ case 'i':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+ reg = ((reg ^ (1 << (bitend - bitstart))) -
+ (1 << (bitend - bitstart)));
+
+ if (((given & insn->mask) == 0x0c00000a) /* ldc1 */
+ || ((given & insn->mask) == 0x0c000012) /* ldc2 */
+ || ((given & insn->mask) == 0x0c00001c) /* ldc3 */
+ || ((given & insn->mask) == 0x0c00000b) /* stc1 */
+ || ((given & insn->mask) == 0x0c000013) /* stc2 */
+ || ((given & insn->mask) == 0x0c00001b)) /* stc3 */
+ reg <<= 2;
+
+ func (stream, "%ld", reg);
+ }
+ break;
+ case 'x':
+ {
+ long reg;
+
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+
+ func (stream, "%lx", reg);
+ }
+ break;
+ default:
+ abort ();
+ }
+ break;
+ case '`':
+ c++;
+ if ((given & (1 << bitstart)) == 0)
+ func (stream, "%c", *c);
+ break;
+ case '\'':
+ c++;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ }
+ else
+ func (stream, "%c", *c);
+ }
+ return 4;
+ }
+ }
+
+#if (SCORE_SIMULATOR_ACTIVE)
+ func (stream, _("<illegal instruction>"));
+ return 4;
+#endif
+
+ abort ();
+}
+
+static void
+print_insn_parallel_sym (struct disassemble_info *info)
+{
+ void *stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ /* 10: 0000 nop!
+ 4 space + 1 colon + 1 space + 1 tab + 8 opcode + 2 space + 1 tab.
+ FIXME: the space number is not accurate. */
+ func (stream, "%s", " ||\n \t \t");
+}
+
+/* Print one instruction from PC on INFO->STREAM.
+ Return the size of the instruction. */
+static int
+print_insn_score16 (bfd_vma pc, struct disassemble_info *info, long given)
+{
+ struct score_opcode *insn;
+ void *stream = info->stream;
+ fprintf_ftype func = info->fprintf_func;
+
+ given &= 0xffff;
+ for (insn = score_opcodes; insn->assembler; insn++)
+ {
+ if (!(insn->mask & 0xffff0000) && (given & insn->mask) == insn->value)
+ {
+ char *c = insn->assembler;
+
+ info->bytes_per_chunk = 2;
+ info->bytes_per_line = 4;
+ given &= 0xffff;
+
+ for (; *c; c++)
+ {
+ if (*c == '%')
+ {
+ switch (*++c)
+ {
+
+ case 'j':
+ {
+ int target;
+
+ if (info->flags & INSN_HAS_RELOC)
+ pc = 0;
+
+ target = (pc & 0xfffff000) | (given & 0x00000ffe);
+ (*info->print_address_func) (target, info);
+ }
+ break;
+ case 'b':
+ {
+ /* Sign-extend a 9-bit number. */
+#define SEXT9(x) ((((x) & 0x1ff) ^ (~ 0xff)) + 0x100)
+ int disp = (given & 0xff) << 1;
+ int target = (pc + SEXT9 (disp));
+
+ (*info->print_address_func) (target, info);
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int bitstart = *c++ - '0';
+ int bitend = 0;
+
+ while (*c >= '0' && *c <= '9')
+ bitstart = (bitstart * 10) + *c++ - '0';
+
+ switch (*c)
+ {
+ case '-':
+ {
+ long reg;
+
+ c++;
+ while (*c >= '0' && *c <= '9')
+ bitend = (bitend * 10) + *c++ - '0';
+ if (!bitend)
+ abort ();
+ reg = given >> bitstart;
+ reg &= (2 << (bitend - bitstart)) - 1;
+ switch (*c)
+ {
+ case 'R':
+ func (stream, "%s", score_regnames[reg + 16]);
+ break;
+ case 'r':
+ func (stream, "%s", score_regnames[reg]);
+ break;
+ case 'd':
+ if (*(c + 1) == '\0')
+ func (stream, "%ld", reg);
+ else
+ {
+ c++;
+ if (*c == '1')
+ func (stream, "%ld", reg << 1);
+ else if (*c == '2')
+ func (stream, "%ld", reg << 2);
+ }
+ break;
+
+ case 'x':
+ if (*(c + 1) == '\0')
+ func (stream, "%lx", reg);
+ else
+ {
+ c++;
+ if (*c == '1')
+ func (stream, "%lx", reg << 1);
+ else if (*c == '2')
+ func (stream, "%lx", reg << 2);
+ }
+ break;
+ case 'i':
+ reg = ((reg ^ (1 << bitend)) - (1 << bitend));
+ func (stream, "%ld", reg);
+ break;
+ default:
+ abort ();
+ }
+ }
+ break;
+
+ case '\'':
+ c++;
+ if ((given & (1 << bitstart)) != 0)
+ func (stream, "%c", *c);
+ break;
+ default:
+ abort ();
+ }
+ }
+ break;
+ default:
+ abort ();
+ }
+ }
+ else
+ func (stream, "%c", *c);
+ }
+
+ return 2;
+ }
+ }
+#if (SCORE_SIMULATOR_ACTIVE)
+ func (stream, _("<illegal instruction>"));
+ return 2;
+#endif
+ /* No match. */
+ abort ();
+}
+
+/* NOTE: There are no checks in these routines that
+ the relevant number of data bytes exist. */
+static int
+print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
+{
+ unsigned char b[4];
+ long given;
+ long ridparity;
+ int status;
+ bfd_boolean insn_pce_p = FALSE;
+ bfd_boolean insn_16_p = FALSE;
+
+ info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
+
+ if (pc & 0x2)
+ {
+ info->bytes_per_chunk = 2;
+ status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
+ b[3] = b[2] = 0;
+ insn_16_p = TRUE;
+ }
+ else
+ {
+ info->bytes_per_chunk = 4;
+ status = info->read_memory_func (pc, (bfd_byte *) & b[0], 4, info);
+ if (status != 0)
+ {
+ info->bytes_per_chunk = 2;
+ status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
+ b[3] = b[2] = 0;
+ insn_16_p = TRUE;
+ }
+ }
+
+ if (status != 0)
+ {
+ info->memory_error_func (status, pc, info);
+ return -1;
+ }
+
+ if (little)
+ {
+ given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
+ }
+ else
+ {
+ given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
+ }
+
+ if ((given & 0x80008000) == 0x80008000)
+ {
+ insn_pce_p = FALSE;
+ insn_16_p = FALSE;
+ }
+ else if ((given & 0x8000) == 0x8000)
+ {
+ insn_pce_p = TRUE;
+ }
+ else
+ {
+ insn_16_p = TRUE;
+ }
+
+ /* 16 bit instruction. */
+ if (insn_16_p)
+ {
+ if (little)
+ {
+ given = b[0] | (b[1] << 8);
+ }
+ else
+ {
+ given = (b[0] << 8) | b[1];
+ }
+
+ status = print_insn_score16 (pc, info, given);
+ }
+ /* pce instruction. */
+ else if (insn_pce_p)
+ {
+ long other;
+
+ given = (given & 0xFFFF0000) >> 16;
+ other = given & 0xFFFF;
+
+ status = print_insn_score16 (pc, info, given);
+ print_insn_parallel_sym (info);
+ status += print_insn_score16 (pc, info, other);
+ /* disassemble_bytes() will output 4 byte per chunk for pce instructio. */
+ info->bytes_per_chunk = 4;
+ }
+ /* 32 bit instruction. */
+ else
+ {
+ /* Get rid of parity. */
+ ridparity = (given & 0x7FFF);
+ ridparity |= (given & 0x7FFF0000) >> 1;
+ given = ridparity;
+ status = print_insn_score32 (pc, info, given);
+ }
+
+ return status;
+}
+
+int
+print_insn_big_score (bfd_vma pc, struct disassemble_info *info)
+{
+ return print_insn (pc, info, FALSE);
+}
+
+int
+print_insn_little_score (bfd_vma pc, struct disassemble_info *info)
+{
+ return print_insn (pc, info, TRUE);
+}
--- /dev/null
+/* Copyright 2006 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+struct score_opcode
+{
+ unsigned long value;
+ unsigned long mask; /* Recognise instruction if (op & mask) == value. */
+ char *assembler; /* Disassembly string. */
+};
+
+/* Note: There is a partial ordering in this table - it must be searched from
+ the top to obtain a correct match. */
+
+static struct score_opcode score_opcodes[] =
+{
+ /* Score Instructions. */
+ {0x3800000a, 0x3e007fff, "abs\t\t%20-24r, %15-19r"},
+ {0x3800004b, 0x3e007fff, "abs.s\t\t%20-24r, %15-19r"},
+ {0x00000010, 0x3e0003ff, "add\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000011, 0x3e0003ff, "add.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x38000048, 0x3e0003ff, "add.s\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000012, 0x3e0003ff, "addc\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000013, 0x3e0003ff, "addc.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x02000000, 0x3e0e0001, "addi\t\t%20-24r, %1-16i"},
+ {0x02000001, 0x3e0e0001, "addi.c\t\t%20-24r, %1-16i"},
+ {0x0a000000, 0x3e0e0001, "addis\t\t%20-24r, %1-16d(0x%1-16x)"},
+ {0x0a000001, 0x3e0e0001, "addis.c\t\t%20-24r, %1-16d(0x%1-16x)"},
+ {0x10000000, 0x3e000001, "addri\t\t%20-24r, %15-19r, %1-14i"},
+ {0x10000001, 0x3e000001, "addri.c\t\t%20-24r, %15-19r, %1-14i"},
+ {0x00000009, 0x0000700f, "addc!\t\t%8-11r, %4-7r"},
+ {0x00002000, 0x0000700f, "add!\t\t%8-11r, %4-7r"},
+ {0x00006000, 0x00007087, "addei!\t\t%8-11r, %3-6d"},
+ {0x00000020, 0x3e0003ff, "and\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000021, 0x3e0003ff, "and.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x02080000, 0x3e0e0001, "andi\t\t%20-24r, 0x%1-16x"},
+ {0x02080001, 0x3e0e0001, "andi.c\t\t%20-24r, 0x%1-16x"},
+ {0x0a080000, 0x3e0e0001, "andis\t\t%20-24r, 0x%1-16x"},
+ {0x0a080001, 0x3e0e0001, "andis.c\t\t%20-24r, 0x%1-16x"},
+ {0x18000000, 0x3e000001, "andri\t\t%20-24r, %15-19r, 0x%1-14x"},
+ {0x18000001, 0x3e000001, "andri.c\t\t%20-24r, %15-19r,0x%1-14x"},
+ {0x00002004, 0x0000700f, "and!\t\t%8-11r, %4-7r"},
+ {0x08000000, 0x3e007c01, "bcs\t\t0x%b" },
+ {0x08000400, 0x3e007c01, "bcc\t\t0x%b" },
+ {0x08003800, 0x3e007c01, "bcnz\t\t0x%b" },
+ {0x08000001, 0x3e007c01, "bcsl\t\t0x%b" },
+ {0x08000401, 0x3e007c01, "bccl\t\t0x%b" },
+ {0x08003801, 0x3e007c01, "bcnzl\t\t0x%b" },
+ {0x00004000, 0x00007f00, "bcs!\t\t0x%b" },
+ {0x00004100, 0x00007f00, "bcc!\t\t0x%b" },
+ {0x00004e00, 0x00007f00, "bcnz!\t\t0x%b" },
+ {0x08001000, 0x3e007c01, "beq\t\t0x%b" },
+ {0x08001001, 0x3e007c01, "beql\t\t0x%b" },
+ {0x00004400, 0x00007f00, "beq!\t\t0x%b" },
+ {0x08000800, 0x3e007c01, "bgtu\t\t0x%b" },
+ {0x08001800, 0x3e007c01, "bgt\t\t0x%b" },
+ {0x08002000, 0x3e007c01, "bge\t\t0x%b" },
+ {0x08000801, 0x3e007c01, "bgtul\t\t0x%b" },
+ {0x08001801, 0x3e007c01, "bgtl\t\t0x%b" },
+ {0x08002001, 0x3e007c01, "bgel\t\t0x%b" },
+ {0x00004200, 0x00007f00, "bgtu!\t\t0x%b" },
+ {0x00004600, 0x00007f00, "bgt!\t\t0x%b" },
+ {0x00004800, 0x00007f00, "bge!\t\t0x%b" },
+ {0x00000029, 0x3e0003ff, "bitclr.c\t%20-24r, %15-19r, 0x%10-14x"},
+ {0x0000002b, 0x3e0003ff, "bitset.c\t%20-24r, %15-19r, 0x%10-14x"},
+ {0x0000002d, 0x3e0003ff, "bittst.c\t%15-19r, 0x%10-14x"},
+ {0x0000002f, 0x3e0003ff, "bittgl.c\t%20-24r, %15-19r, 0x%10-14x"},
+ {0x00006004, 0x00007007, "bitclr!\t\t%8-11r, 0x%3-7x"},
+ {0x3800000c, 0x3e0003ff, "bitrev\t\t%20-24r, %15-19r,%10-14r"},
+ {0x00006005, 0x00007007, "bitset!\t\t%8-11r, 0x%3-7x"},
+ {0x00006006, 0x00007007, "bittst!\t\t%8-11r, 0x%3-7x"},
+ {0x00006007, 0x00007007, "bittgl!\t\t%8-11r, 0x%3-7x"},
+ {0x08000c00, 0x3e007c01, "bleu\t\t0x%b" },
+ {0x08001c00, 0x3e007c01, "ble\t\t0x%b" },
+ {0x08002400, 0x3e007c01, "blt\t\t0x%b" },
+ {0x08000c01, 0x3e007c01, "bleul\t\t0x%b" },
+ {0x08001c01, 0x3e007c01, "blel\t\t0x%b" },
+ {0x08002401, 0x3e007c01, "bltl\t\t0x%b" },
+ {0x08003c01, 0x3e007c01, "bl\t\t0x%b" },
+ {0x00004300, 0x00007f00, "bleu!\t\t0x%b" },
+ {0x00004700, 0x00007f00, "ble!\t\t0x%b" },
+ {0x00004900, 0x00007f00, "blt!\t\t0x%b" },
+ {0x08002800, 0x3e007c01, "bmi\t\t0x%b" },
+ {0x08002801, 0x3e007c01, "bmil\t\t0x%b" },
+ {0x00004a00, 0x00007f00, "bmi!\t\t0x%b" },
+ {0x08001400, 0x3e007c01, "bne\t\t0x%b" },
+ {0x08001401, 0x3e007c01, "bnel\t\t0x%b" },
+ {0x00004500, 0x00007f00, "bne!\t\t0x%b" },
+ {0x08002c00, 0x3e007c01, "bpl\t\t0x%b" },
+ {0x08002c01, 0x3e007c01, "bpll\t\t0x%b" },
+ {0x00004b00, 0x00007f00, "bpl!\t\t0x%b" },
+ {0x00000008, 0x3e007fff, "brcs\t\t%15-19r" },
+ {0x00000408, 0x3e007fff, "brcc\t\t%15-19r" },
+ {0x00000808, 0x3e007fff, "brgtu\t\t%15-19r" },
+ {0x00000c08, 0x3e007fff, "brleu\t\t%15-19r" },
+ {0x00001008, 0x3e007fff, "breq\t\t%15-19r" },
+ {0x00001408, 0x3e007fff, "brne\t\t%15-19r" },
+ {0x00001808, 0x3e007fff, "brgt\t\t%15-19r" },
+ {0x00001c08, 0x3e007fff, "brle\t\t%15-19r" },
+ {0x00002008, 0x3e007fff, "brge\t\t%15-19r" },
+ {0x00002408, 0x3e007fff, "brlt\t\t%15-19r" },
+ {0x00002808, 0x3e007fff, "brmi\t\t%15-19r" },
+ {0x00002c08, 0x3e007fff, "brpl\t\t%15-19r" },
+ {0x00003008, 0x3e007fff, "brvs\t\t%15-19r" },
+ {0x00003408, 0x3e007fff, "brvc\t\t%15-19r" },
+ {0x00003808, 0x3e007fff, "brcnz\t\t%15-19r" },
+ {0x00003c08, 0x3e007fff, "br\t\t%15-19r" },
+ {0x00000009, 0x3e007fff, "brcsl\t\t%15-19r" },
+ {0x00000409, 0x3e007fff, "brccl\t\t%15-19r" },
+ {0x00000809, 0x3e007fff, "brgtul\t\t%15-19r" },
+ {0x00000c09, 0x3e007fff, "brleul\t\t%15-19r" },
+ {0x00001009, 0x3e007fff, "breql\t\t%15-19r" },
+ {0x00001409, 0x3e007fff, "brnel\t\t%15-19r" },
+ {0x00001809, 0x3e007fff, "brgtl\t\t%15-19r" },
+ {0x00001c09, 0x3e007fff, "brlel\t\t%15-19r" },
+ {0x00002009, 0x3e007fff, "brgel\t\t%15-19r" },
+ {0x00002409, 0x3e007fff, "brltl\t\t%15-19r" },
+ {0x00002809, 0x3e007fff, "brmil\t\t%15-19r" },
+ {0x00002c09, 0x3e007fff, "brpll\t\t%15-19r" },
+ {0x00003009, 0x3e007fff, "brvsl\t\t%15-19r" },
+ {0x00003409, 0x3e007fff, "brvcl\t\t%15-19r" },
+ {0x00003809, 0x3e007fff, "brcnzl\t\t%15-19r" },
+ {0x00003c09, 0x3e007fff, "brl\t\t%15-19r" },
+ {0x00000004, 0x00007f0f, "brcs!\t\t%4-7r" },
+ {0x00000104, 0x00007f0f, "brcc!\t\t%4-7r" },
+ {0x00000204, 0x00007f0f, "brgtu!\t\t%4-7r" },
+ {0x00000304, 0x00007f0f, "brleu!\t\t%4-7r" },
+ {0x00000404, 0x00007f0f, "breq!\t\t%4-7r" },
+ {0x00000504, 0x00007f0f, "brne!\t\t%4-7r" },
+ {0x00000604, 0x00007f0f, "brgt!\t\t%4-7r" },
+ {0x00000704, 0x00007f0f, "brle!\t\t%4-7r" },
+ {0x00000804, 0x00007f0f, "brge!\t\t%4-7r" },
+ {0x00000904, 0x00007f0f, "brlt!\t\t%4-7r" },
+ {0x00000a04, 0x00007f0f, "brmi!\t\t%4-7r" },
+ {0x00000b04, 0x00007f0f, "brpl!\t\t%4-7r" },
+ {0x00000c04, 0x00007f0f, "brvs!\t\t%4-7r" },
+ {0x00000d04, 0x00007f0f, "brvc!\t\t%4-7r" },
+ {0x00000e04, 0x00007f0f, "brcnz!\t\t%4-7r" },
+ {0x00000f04, 0x00007f0f, "br!\t\t%4-7r" },
+ {0x0000000c, 0x00007f0f, "brcsl!\t\t%4-7r" },
+ {0x0000010c, 0x00007f0f, "brccl!\t\t%4-7r" },
+ {0x0000020c, 0x00007f0f, "brgtul!\t\t%4-7r" },
+ {0x0000030c, 0x00007f0f, "brleul!\t\t%4-7r" },
+ {0x0000040c, 0x00007f0f, "breql!\t\t%4-7r" },
+ {0x0000050c, 0x00007f0f, "brnel!\t\t%4-7r" },
+ {0x0000060c, 0x00007f0f, "brgtl!\t\t%4-7r" },
+ {0x0000070c, 0x00007f0f, "brlel!\t\t%4-7r" },
+ {0x0000080c, 0x00007f0f, "brgel!\t\t%4-7r" },
+ {0x0000090c, 0x00007f0f, "brltl!\t\t%4-7r" },
+ {0x00000a0c, 0x00007f0f, "brmil!\t\t%4-7r" },
+ {0x00000b0c, 0x00007f0f, "brpll!\t\t%4-7r" },
+ {0x00000c0c, 0x00007f0f, "brvsl!\t\t%4-7r" },
+ {0x00000d0c, 0x00007f0f, "brvcl!\t\t%4-7r" },
+ {0x00000e0c, 0x00007f0f, "brcnzl!\t\t%4-7r" },
+ {0x00000f0c, 0x00007f0f, "brl!\t\t%4-7r" },
+ {0x08003000, 0x3e007c01, "bvs\t\t0x%b" },
+ {0x08003400, 0x3e007c01, "bvc\t\t0x%b" },
+ {0x08003001, 0x3e007c01, "bvsl\t\t0x%b" },
+ {0x08003401, 0x3e007c01, "bvcl\t\t0x%b" },
+ {0x00004c00, 0x00007f00, "bvs!\t\t0x%b" },
+ {0x00004d00, 0x00007f00, "bvc!\t\t0x%b" },
+ {0x00004f00, 0x00007f00, "b!\t\t0x%b" },
+ {0x08003c00, 0x3e007c01, "b\t\t0x%b" },
+ {0x30000000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30100000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30200000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30300000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30400000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30800000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30900000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30a00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30b00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30c00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30d00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x30e00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31000000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31100000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31800000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31a00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31b00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31c00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31d00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31e00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x31f00000, 0x3ff00000, "cache\t\t%20-24d, [%15-19r, %0-14i]"},
+ {0x38000000, 0x3ff003ff, "mad\t\t%15-19r, %10-14r"},
+ {0x38000020, 0x3ff003ff, "madu\t\t%15-19r, %10-14r"},
+ {0x38000080, 0x3ff003ff, "mad.f\t\t%15-19r, %10-14r"},
+ {0x38000001, 0x3ff003ff, "msb\t\t%15-19r, %10-14r"},
+ {0x38000021, 0x3ff003ff, "msbu\t\t%15-19r, %10-14r"},
+ {0x38000081, 0x3ff003ff, "msb.f\t\t%15-19r, %10-14r"},
+ {0x38000102, 0x3ff003ff, "mazl\t\t%15-19r, %10-14r"},
+ {0x38000182, 0x3ff003ff, "mazl.f\t\t%15-19r, %10-14r"},
+ {0x38000002, 0x3ff003ff, "madl\t\t%15-19r, %10-14r"},
+ {0x380000c2, 0x3ff003ff, "madl.fs\t\t%15-19r, %10-14r"},
+ {0x38000303, 0x3ff003ff, "mazh\t\t%15-19r, %10-14r"},
+ {0x38000383, 0x3ff003ff, "mazh.f\t\t%15-19r, %10-14r"},
+ {0x38000203, 0x3ff003ff, "madh\t\t%15-19r, %10-14r"},
+ {0x380002c3, 0x3ff003ff, "madh.fs\t\t%15-19r, %10-14r"},
+ {0x38000007, 0x3e0003ff, "max\t\t%20-24r, %15-19r, %10-14r"},
+ {0x38000006, 0x3e0003ff, "min\t\t%20-24r, %15-19r, %10-14r"},
+ {0x38000104, 0x3ff003ff, "mszl\t\t%15-19r, %10-14r"},
+ {0x38000184, 0x3ff003ff, "mszl.f\t\t%15-19r, %10-14r"},
+ {0x38000004, 0x3ff003ff, "msbl\t\t%15-19r, %10-14r"},
+ {0x380000c4, 0x3ff003ff, "msbl.fs\t\t%15-19r, %10-14r"},
+ {0x38000305, 0x3ff003ff, "mszh\t\t%15-19r, %10-14r"},
+ {0x38000385, 0x3ff003ff, "mszh.f\t\t%15-19r, %10-14r"},
+ {0x38000205, 0x3ff003ff, "msbh\t\t%15-19r, %10-14r"},
+ {0x380002c5, 0x3ff003ff, "msbh.fs\t\t%15-19r, %10-14r"},
+ {0x3800004e, 0x3e0003ff, "sll.s\t\t%20-24r, %15-19r, %10-14r"},
+ {0x38000049, 0x3e0003ff, "sub.s\t\t%20-24r, %15-19r, %10-14r"},
+ {0x3800000d, 0x3e007fff, "clz\t\t%20-24r, %15-19r"},
+ {0x38000000, 0x3e000000, "ceinst\t\t%20-24d, %15-19r, %10-14r, %5-9d, %0-4d"},
+ {0x00000019, 0x3ff003ff, "cmpteq.c\t\t%15-19r, %10-14r"},
+ {0x00100019, 0x3ff003ff, "cmptmi.c\t\t%15-19r, %10-14r"},
+ {0x00300019, 0x3ff003ff, "cmp.c\t\t%15-19r, %10-14r"},
+ {0x0000001b, 0x3ff07fff, "cmpzteq.c\t%15-19r"},
+ {0x0010001b, 0x3ff07fff, "cmpztmi.c\t%15-19r"},
+ {0x0030001b, 0x3ff07fff, "cmpz.c\t\t%15-19r"},
+ {0x02040001, 0x3e0e0001, "cmpi.c\t\t%20-24r, %1-16i"},
+ {0x00002003, 0x0000700f, "cmp!\t\t%8-11r, %4-7r"},
+ {0x0c00000c, 0x3e00001f, "cop1\t\tc%20-24r, c%15-19r, c%10-14r, %5-9d"},
+ {0x0c000014, 0x3e00001f, "cop2\t\tc%20-24r, c%15-19r, c%10-14r, %5-9d"},
+ {0x0c00001c, 0x3e00001f, "cop3\t\tc%20-24r, c%15-19r, c%10-14r, %5-9d"},
+ {0x00000044, 0x3e0003ff, "div\t\t%15-19r, %10-14r"},
+ {0x00000046, 0x3e0003ff, "divu\t\t%15-19r, %10-14r"},
+ {0x0c0000a4, 0x3e0003ff, "drte" },
+ {0x00000058, 0x3e0003ff, "extsb\t\t%20-24r, %15-19r"},
+ {0x00000059, 0x3e0003ff, "extsb.c\t\t%20-24r, %15-19r"},
+ {0x0000005a, 0x3e0003ff, "extsh\t\t%20-24r, %15-19r"},
+ {0x0000005b, 0x3e0003ff, "extsh.c\t\t%20-24r, %15-19r"},
+ {0x0000005c, 0x3e0003ff, "extzb\t\t%20-24r, %15-19r"},
+ {0x0000005d, 0x3e0003ff, "extzb.c\t\t%20-24r, %15-19r"},
+ {0x0000005e, 0x3e0003ff, "extzh\t\t%20-24r, %15-19r"},
+ {0x0000005f, 0x3e0003ff, "extzh.c\t\t%20-24r, %15-19r"},
+ {0x04000001, 0x3e000001, "jl\t\t0x%j"},
+ {0x00003001, 0x00007001, "jl!\t\t0x%j" },
+ {0x00003000, 0x00007001, "j!\t\t0x%j" },
+ {0x04000000, 0x3e000001, "j\t\t0x%j"},
+ {0x26000000, 0x3e000000, "lb\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x2c000000, 0x3e000000, "lbu\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000003, 0x3e000007, "lb\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x06000006, 0x3e000007, "lbu\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000003, 0x3e000007, "lb\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0e000006, 0x3e000007, "lbu\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0000200b, 0x0000700f, "lbu!\t\t%8-11r, [%4-7r]"},
+ {0x00007003, 0x00007007, "lbup!\t\t%8-11r, %3-7d"},
+ {0x00000060, 0x3e0003ff, "lcb\t\t[%15-19r]+"},
+ {0x00000062, 0x3e0003ff, "lcw\t\t%20-24r, [%15-19r]+"},
+ {0x00000066, 0x3e0003ff, "lce\t\t%20-24r, [%15-19r]+"},
+ {0x0c00000a, 0x3e00001f, "ldc1\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x0c000012, 0x3e00001f, "ldc2\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x0c00001a, 0x3e00001f, "ldc3\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x22000000, 0x3e000000, "lh\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x24000000, 0x3e000000, "lhu\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000001, 0x3e000007, "lh\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x06000002, 0x3e000007, "lhu\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000001, 0x3e000007, "lh\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0e000002, 0x3e000007, "lhu\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x00002009, 0x0000700f, "lh!\t\t%8-11r, [%4-7r]"},
+ {0x00007001, 0x00007007, "lhp!\t\t%8-11r, %3-7d1"},
+ {0x020c0000, 0x3e0e0000, "ldi\t\t%20-24r, 0x%1-16x(%1-16i)"},
+ {0x0a0c0000, 0x3e0e0000, "ldis\t\t%20-24r, 0x%1-16x(%1-16i)"},
+ {0x00005000, 0x00007000, "ldiu!\t\t%8-11r, %0-7d"},
+ {0x0000000c, 0x3e0003ff, "alw\t\t%20-24r, [%15-19r]"},
+ {0x20000000, 0x3e000000, "lw\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000000, 0x3e000007, "lw\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000000, 0x3e000007, "lw\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x00002008, 0x0000700f, "lw!\t\t%8-11r, [%4-7r]"},
+ {0x00007000, 0x00007007, "lwp!\t\t%8-11r, %3-7d2"},
+ {0x0000100b, 0x0000700f, "madh.fs!\t\t%8-11r, %4-7r"},
+ {0x0000100a, 0x0000700f, "madl.fs!\t\t%8-11r, %4-7r"},
+ {0x00001005, 0x0000700f, "madu!\t\t%8-11r, %4-7r"},
+ {0x00001004, 0x0000700f, "mad.f!\t\t%8-11r, %4-7r"},
+ {0x00001009, 0x0000700f, "mazh.f!\t\t%8-11r, %4-7r"},
+ {0x00001008, 0x0000700f, "mazl.f!\t\t%8-11r, %4-7r"},
+ {0x00000448, 0x3e007fff, "mfcel\t\t%20-24r"},
+ {0x00001001, 0x00007f0f, "mfcel!\t\t%4-7r"},
+ {0x00000848, 0x3e007fff, "mfceh\t\t%20-24r"},
+ {0x00001101, 0x00007f0f, "mfceh!\t\t%4-7r"},
+ {0x00000c48, 0x3e007fff, "mfcehl\t\t%20-24r, %15-19r"},
+ {0x00000048, 0x3e0003ff, "mfce\t\t%20-24r, er%10-14d"},
+ {0x00000050, 0x3e0003ff, "mfsr\t\t%20-24r, sr%10-14d"},
+ {0x0c000001, 0x3e00001f, "mfcr\t\t%20-24r, c%15-19r"},
+ {0x0c000009, 0x3e00001f, "mfc1\t\t%20-24r, c%15-19r"},
+ {0x0c000011, 0x3e00001f, "mfc2\t\t%20-24r, c%15-19r"},
+ {0x0c000019, 0x3e00001f, "mfc3\t\t%20-24r, c%15-19r"},
+ {0x0c00000f, 0x3e00001f, "mfcc1\t\t%20-24r, c%15-19r"},
+ {0x0c000017, 0x3e00001f, "mfcc2\t\t%20-24r, c%15-19r"},
+ {0x0c00001f, 0x3e00001f, "mfcc3\t\t%20-24r, c%15-19r"},
+ {0x00000002, 0x0000700f, "mhfl!\t\t%8-11R, %4-7r"},
+ {0x00000001, 0x0000700f, "mlfh!\t\t%8-11r, %4-7R"},
+ {0x00001006, 0x0000700f, "msb.f!\t\t%8-11r, %4-7r"},
+ {0x0000100f, 0x0000700f, "msbh.fs!\t\t%8-11r, %4-7r"},
+ {0x0000100e, 0x0000700f, "msbl.fs!\t\t%8-11r, %4-7r"},
+ {0x00001007, 0x0000700f, "msbu!\t\t%8-11r, %4-7r"},
+ {0x0000100d, 0x0000700f, "mszh.f!\t\t%8-11r, %4-7r"},
+ {0x0000100c, 0x0000700f, "mszl.f!\t\t%8-11r, %4-7r"},
+ {0x0000044a, 0x3e007fff, "mtcel\t\t%20-24r"},
+ {0x00001000, 0x00007f0f, "mtcel!\t\t%4-7r"},
+ {0x0000084a, 0x3e007fff, "mtceh\t\t%20-24r"},
+ {0x00001100, 0x00007f0f, "mtceh!\t\t%4-7r"},
+ {0x00000c4a, 0x3e007fff, "mtcehl\t\t%20-24r, %15-19r"},
+ {0x0000004a, 0x3e0003ff, "mtce\t\t%20-24r, er%10-14d"},
+ {0x00000052, 0x3e0003ff, "mtsr\t\t%15-19r, sr%10-14d"},
+ {0x0c000000, 0x3e00001f, "mtcr\t\t%20-24r, c%15-19r"},
+ {0x0c000008, 0x3e00001f, "mtc1\t\t%20-24r, c%15-19r"},
+ {0x0c000010, 0x3e00001f, "mtc2\t\t%20-24r, c%15-19r"},
+ {0x0c000018, 0x3e00001f, "mtc3\t\t%20-24r, c%15-19r"},
+ {0x0c00000e, 0x3e00001f, "mtcc1\t\t%20-24r, c%15-19r"},
+ {0x0c000016, 0x3e00001f, "mtcc2\t\t%20-24r, c%15-19r"},
+ {0x0c00001e, 0x3e00001f, "mtcc3\t\t%20-24r, c%15-19r"},
+ {0x00000040, 0x3e0003ff, "mul\t\t%15-19r, %10-14r"},
+ {0x00000040, 0x3e0003ff, "maz\t\t%15-19r, %10-14r"},
+ {0x00000041, 0x3e0003ff, "mul.f\t\t%15-19r, %10-14r"},
+ {0x00000041, 0x3e0003ff, "maz.f\t\t%15-19r, %10-14r"},
+ {0x00001002, 0x0000700f, "mul.f!\t\t%8-11r, %4-7r"},
+ {0x00000042, 0x3e0003ff, "mulu\t\t%15-19r, %10-14r"},
+ {0x00000042, 0x3e0003ff, "mazu\t\t%15-19r, %10-14r"},
+ {0x00001003, 0x0000700f, "mulu!\t\t%8-11r, %4-7r"},
+ {0x00000056, 0x3e007fff, "mvcs\t\t%20-24r, %15-19r"},
+ {0x00000456, 0x3e007fff, "mvcc\t\t%20-24r, %15-19r"},
+ {0x00000856, 0x3e007fff, "mvgtu\t\t%20-24r, %15-19r"},
+ {0x00000c56, 0x3e007fff, "mvleu\t\t%20-24r, %15-19r"},
+ {0x00001056, 0x3e007fff, "mveq\t\t%20-24r, %15-19r"},
+ {0x00001456, 0x3e007fff, "mvne\t\t%20-24r, %15-19r"},
+ {0x00001856, 0x3e007fff, "mvgt\t\t%20-24r, %15-19r"},
+ {0x00001c56, 0x3e007fff, "mvle\t\t%20-24r, %15-19r"},
+ {0x00002056, 0x3e007fff, "mvge\t\t%20-24r, %15-19r"},
+ {0x00002456, 0x3e007fff, "mvlt\t\t%20-24r, %15-19r"},
+ {0x00002856, 0x3e007fff, "mvmi\t\t%20-24r, %15-19r"},
+ {0x00002c56, 0x3e007fff, "mvpl\t\t%20-24r, %15-19r"},
+ {0x00003056, 0x3e007fff, "mvvs\t\t%20-24r, %15-19r"},
+ {0x00003456, 0x3e007fff, "mvvc\t\t%20-24r, %15-19r"},
+ {0x00003c56, 0x3e007fff, "mv\t\t%20-24r, %15-19r"},
+ {0x00000003, 0x0000700f, "mv!\t\t%8-11r, %4-7r"},
+ {0x0000001e, 0x3e0003ff, "neg\t\t%20-24r, %10-14r" },
+ {0x0000001f, 0x3e0003ff, "neg.c\t\t%20-24r, %10-14r" },
+ {0x00002002, 0x0000700f, "neg!\t\t%8-11r, %4-7r"},
+ {0x00000000, 0x3e0003ff, "nop" },
+ {0x00000024, 0x3e0003ff, "not\t\t%20-24r, %15-19r" },
+ {0x00000025, 0x3e0003ff, "not.c\t\t%20-24r, %15-19r" },
+ {0x00000000, 0x0000700f, "nop!" },
+ {0x00002006, 0x0000700f, "not!\t\t%8-11r, %4-7r"},
+ {0x00000022, 0x3e0003ff, "or\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000023, 0x3e0003ff, "or.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x020a0000, 0x3e0e0001, "ori\t\t%20-24r, 0x%1-16x"},
+ {0x020a0001, 0x3e0e0001, "ori.c\t\t%20-24r, 0x%1-16x"},
+ {0x0a0a0000, 0x3e0e0001, "oris\t\t%20-24r, 0x%1-16x"},
+ {0x0a0a0001, 0x3e0e0001, "oris.c\t\t%20-24r, 0x%1-16x"},
+ {0x1a000000, 0x3e000001, "orri\t\t%20-24r, %15-19r, 0x%1-14x"},
+ {0x1a000001, 0x3e000001, "orri.c\t\t%20-24r, %15-19r, 0x%1-14x"},
+ {0x00002005, 0x0000700f, "or!\t\t%8-11r, %4-7r"},
+ {0x0000000a, 0x3e0003ff, "pflush"},
+ {0x0000208a, 0x0000708f, "pop!\t\t%8-11R, [%4-6r]"},
+ {0x0000200a, 0x0000700f, "pop!\t\t%8-11r, [%4-7r]"},
+ {0x0000208e, 0x0000708f, "push!\t\t%8-11R, [%4-6r]"},
+ {0x0000200e, 0x0000700f, "push!\t\t%8-11r, [%4-7r]"},
+ {0x00000038, 0x3e0003ff, "ror\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000039, 0x3e0003ff, "ror.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x0000003b, 0x3e0003ff, "rorc.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x0000003c, 0x3e0003ff, "rol\t\t%20-24r, %15-19r, %10-14r"},
+ {0x0000003d, 0x3e0003ff, "rol.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x0000003f, 0x3e0003ff, "rolc.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000078, 0x3e0003ff, "rori\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000079, 0x3e0003ff, "rori.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0000007b, 0x3e0003ff, "roric.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0000007c, 0x3e0003ff, "roli\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0000007d, 0x3e0003ff, "roli.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0000007f, 0x3e0003ff, "rolic.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0c000084, 0x3e0003ff, "rte" },
+ {0x2e000000, 0x3e000000, "sb\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000007, 0x3e000007, "sb\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000007, 0x3e000007, "sb\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0000200f, 0x0000700f, "sb!\t\t%8-11r, [%4-7r]"},
+ {0x00007007, 0x00007007, "sbp!\t\t%8-11r, %3-7d"},
+ {0x0000000e, 0x3e0003ff, "asw\t\t%20-24r, [%15-19r]"},
+ {0x00000068, 0x3e0003ff, "scb\t\t%20-24r, [%15-19r]+"},
+ {0x0000006a, 0x3e0003ff, "scw\t\t%20-24r, [%15-19r]+"},
+ {0x0000006e, 0x3e0003ff, "sce\t\t[%15-19r]+"},
+ {0x00000006, 0x3e0003ff, "sdbbp\t\t%15-19d"},
+ {0x00006002, 0x00007007, "sdbbp!\t\t%3-7d"},
+ {0x2a000000, 0x3e000000, "sh\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000005, 0x3e000007, "sh\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000005, 0x3e000007, "sh\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0000200d, 0x0000700f, "sh!\t\t%8-11r, [%4-7r]"},
+ {0x00007005, 0x00007007, "shp!\t\t%8-11r, %3-7d1"},
+ {0x0c0000c4, 0x3e0003ff, "sleep" },
+ {0x00000030, 0x3e0003ff, "sll\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000031, 0x3e0003ff, "sll.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000070, 0x3e0003ff, "slli\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000071, 0x3e0003ff, "slli.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000008, 0x0000700f, "sll!\t\t%8-11r, %4-7r"},
+ {0x00006001, 0x00007007, "slli!\t\t%8-11r, %3-7d"},
+ {0x00000034, 0x3e0003ff, "srl\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000035, 0x3e0003ff, "srl.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000036, 0x3e0003ff, "sra\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000037, 0x3e0003ff, "sra.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000074, 0x3e0003ff, "srli\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000075, 0x3e0003ff, "srli.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000076, 0x3e0003ff, "srai\t\t%20-24r, %15-19r, %10-14d"},
+ {0x00000077, 0x3e0003ff, "srai.c\t\t%20-24r, %15-19r, %10-14d"},
+ {0x0000000a, 0x0000700f, "srl!\t\t%8-11r, %4-7r"},
+ {0x00006003, 0x00007007, "srli!\t\t%8-11r, %3-7d"},
+ {0x0000000b, 0x0000700f, "sra!\t\t%8-11r, %4-7r"},
+ {0x0c00000b, 0x3e00001f, "stc1\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x0c000013, 0x3e00001f, "stc2\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x0c00001b, 0x3e00001f, "stc3\t\tc%15-19r, [%20-24r, %5-14i]"},
+ {0x00000014, 0x3e0003ff, "sub\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000015, 0x3e0003ff, "sub.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000016, 0x3e0003ff, "subc\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000017, 0x3e0003ff, "subc.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00002001, 0x0000700f, "sub!\t\t%8-11r, %4-7r"},
+ {0x00006080, 0x00007087, "subei!\t\t%8-11r, %3-6d"},
+ {0x28000000, 0x3e000000, "sw\t\t%20-24r, [%15-19r, %0-14i]"},
+ {0x06000004, 0x3e000007, "sw\t\t%20-24r, [%15-19r, %3-14i]+"},
+ {0x0e000004, 0x3e000007, "sw\t\t%20-24r, [%15-19r]+, %3-14i"},
+ {0x0000200c, 0x0000700f, "sw!\t\t%8-11r, [%4-7r]"},
+ {0x00007004, 0x00007007, "swp!\t\t%8-11r, %3-7d2"},
+ {0x00000002, 0x3e0003ff, "syscall\t\t%10-24d"},
+ {0x00000054, 0x3e007fff, "tcs" },
+ {0x00000454, 0x3e007fff, "tcc" },
+ {0x00003854, 0x3e007fff, "tcnz" },
+ {0x00000005, 0x00007f0f, "tcs!" },
+ {0x00000105, 0x00007f0f, "tcc!" },
+ {0x00000e05, 0x00007f0f, "tcnz!" },
+ {0x00001054, 0x3e007fff, "teq" },
+ {0x00000405, 0x00007f0f, "teq!" },
+ {0x00000854, 0x3e007fff, "tgtu" },
+ {0x00001854, 0x3e007fff, "tgt" },
+ {0x00002054, 0x3e007fff, "tge" },
+ {0x00000205, 0x00007f0f, "tgtu!" },
+ {0x00000605, 0x00007f0f, "tgt!" },
+ {0x00000805, 0x00007f0f, "tge!" },
+ {0x00000c54, 0x3e007fff, "tleu" },
+ {0x00001c54, 0x3e007fff, "tle" },
+ {0x00002454, 0x3e007fff, "tlt" },
+ {0x0c000004, 0x3e0003ff, "stlb" },
+ {0x0c000024, 0x3e0003ff, "mftlb" },
+ {0x0c000044, 0x3e0003ff, "mtptlb" },
+ {0x0c000064, 0x3e0003ff, "mtrtlb" },
+ {0x00000305, 0x00007f0f, "tleu!" },
+ {0x00000705, 0x00007f0f, "tle!" },
+ {0x00000905, 0x00007f0f, "tlt!" },
+ {0x00002854, 0x3e007fff, "tmi" },
+ {0x00000a05, 0x00007f0f, "tmi!" },
+ {0x00001454, 0x3e007fff, "tne" },
+ {0x00000505, 0x00007f0f, "tne!" },
+ {0x00002c54, 0x3e007fff, "tpl" },
+ {0x00000b05, 0x00007f0f, "tpl!" },
+ {0x00000004, 0x3e007fff, "trapcs\t\t%15-19d"},
+ {0x00000404, 0x3e007fff, "trapcc\t\t%15-19d"},
+ {0x00000804, 0x3e007fff, "trapgtu\t\t%15-19d"},
+ {0x00000c04, 0x3e007fff, "trapleu\t\t%15-19d"},
+ {0x00001004, 0x3e007fff, "trapeq\t\t%15-19d"},
+ {0x00001404, 0x3e007fff, "trapne\t\t%15-19d"},
+ {0x00001804, 0x3e007fff, "trapgt\t\t%15-19d"},
+ {0x00001c04, 0x3e007fff, "traple\t\t%15-19d"},
+ {0x00002004, 0x3e007fff, "trapge\t\t%15-19d"},
+ {0x00002404, 0x3e007fff, "traplt\t\t%15-19d"},
+ {0x00002804, 0x3e007fff, "trapmi\t\t%15-19d"},
+ {0x00002c04, 0x3e007fff, "trappl\t\t%15-19d"},
+ {0x00003004, 0x3e007fff, "trapvs\t\t%15-19d"},
+ {0x00003404, 0x3e007fff, "trapvc\t\t%15-19d"},
+ {0x00003c04, 0x3e007fff, "trap\t\t%15-19d"},
+ {0x00003c54, 0x3e007fff, "tset" },
+ {0x00000f05, 0x00007f0f, "tset!" },
+ {0x00003054, 0x3e007fff, "tvs" },
+ {0x00003454, 0x3e007fff, "tvc" },
+ {0x00000c05, 0x00007f0f, "tvs!" },
+ {0x00000d05, 0x00007f0f, "tvc!" },
+ {0x00000026, 0x3e0003ff, "xor\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00000027, 0x3e0003ff, "xor.c\t\t%20-24r, %15-19r, %10-14r"},
+ {0x00002007, 0x0000700f, "xor!\t\t%8-11r, %4-7r"}
+};