OSDN Git Service

Add support for Score target.
authorNick Clifton <nickc@redhat.com>
Sat, 16 Sep 2006 23:51:50 +0000 (23:51 +0000)
committerNick Clifton <nickc@redhat.com>
Sat, 16 Sep 2006 23:51:50 +0000 (23:51 +0000)
54 files changed:
bfd/ChangeLog
bfd/Makefile.am
bfd/Makefile.in
bfd/archures.c
bfd/bfd-in2.h
bfd/config.bfd
bfd/configure
bfd/configure.in
bfd/cpu-score.c [new file with mode: 0644]
bfd/elf32-score.c [new file with mode: 0644]
bfd/libbfd.h
bfd/reloc.c
bfd/targets.c
binutils/ChangeLog
binutils/Makefile.am
binutils/Makefile.in
binutils/readelf.c
gas/ChangeLog
gas/Makefile.am
gas/Makefile.in
gas/NEWS
gas/config/tc-score.c [new file with mode: 0644]
gas/config/tc-score.h [new file with mode: 0644]
gas/configure.tgt
gas/testsuite/ChangeLog
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/elf/section2.e-score [new file with mode: 0644]
include/ChangeLog
include/dis-asm.h
include/elf/ChangeLog
include/elf/common.h
include/elf/score.h [new file with mode: 0644]
include/opcode/ChangeLog
include/opcode/score-datadep.h [new file with mode: 0644]
include/opcode/score-inst.h [new file with mode: 0644]
ld/ChangeLog
ld/Makefile.am
ld/Makefile.in
ld/NEWS
ld/configure.tgt
ld/emulparams/scoreelf.sh [new file with mode: 0644]
ld/emultempl/scoreelf.em [new file with mode: 0644]
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/merge.d
ld/testsuite/ld-elfcomm/elfcomm.exp
ld/testsuite/ld-srec/srec.exp
opcodes/ChangeLog
opcodes/Makefile.am
opcodes/Makefile.in
opcodes/configure
opcodes/configure.in
opcodes/disassemble.c
opcodes/score-dis.c [new file with mode: 0644]
opcodes/score-opc.h [new file with mode: 0644]

index fa9e137..023b241 100644 (file)
@@ -1,3 +1,18 @@
+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>
 
index 27c2c06..175820e 100644 (file)
@@ -103,6 +103,7 @@ ALL_MACHINES = \
        cpu-powerpc.lo \
        cpu-rs6000.lo \
        cpu-s390.lo \
+       cpu-score.lo \
        cpu-sh.lo \
        cpu-sparc.lo \
        cpu-tic30.lo \
@@ -165,6 +166,7 @@ ALL_MACHINES_CFILES = \
        cpu-powerpc.c \
        cpu-rs6000.c \
        cpu-s390.c \
+       cpu-score.c \
        cpu-sh.c \
        cpu-sparc.c \
        cpu-tic30.c \
@@ -271,6 +273,7 @@ BFD32_BACKENDS = \
        elf32-pj.lo \
        elf32-ppc.lo \
        elf32-s390.lo \
+       elf32-score.lo \
        elf32-sh.lo \
        elf32-sh-symbian.lo \
        elf32-sh64.lo \
@@ -447,6 +450,7 @@ BFD32_BACKENDS_CFILES = \
        elf32-sh64.c \
        elf32-sh64-com.c \
        elf32-s390.c \
+       elf32-score.c \
        elf32-sh.c \
        elf32-sh-symbian.c \
        elfxx-sparc.c \
@@ -1058,6 +1062,7 @@ cpu-pj.lo: cpu-pj.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
 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
@@ -1436,6 +1441,10 @@ elf32-sh64-com.lo: elf32-sh64-com.c $(INCDIR)/filenames.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 \
index 46673b6..8a15b44 100644 (file)
@@ -334,6 +334,7 @@ ALL_MACHINES = \
        cpu-powerpc.lo \
        cpu-rs6000.lo \
        cpu-s390.lo \
+       cpu-score.lo \
        cpu-sh.lo \
        cpu-sparc.lo \
        cpu-tic30.lo \
@@ -396,6 +397,7 @@ ALL_MACHINES_CFILES = \
        cpu-powerpc.c \
        cpu-rs6000.c \
        cpu-s390.c \
+       cpu-score.c \
        cpu-sh.c \
        cpu-sparc.c \
        cpu-tic30.c \
@@ -503,6 +505,7 @@ BFD32_BACKENDS = \
        elf32-pj.lo \
        elf32-ppc.lo \
        elf32-s390.lo \
+       elf32-score.lo \
        elf32-sh.lo \
        elf32-sh-symbian.lo \
        elf32-sh64.lo \
@@ -679,6 +682,7 @@ BFD32_BACKENDS_CFILES = \
        elf32-sh64.c \
        elf32-sh64-com.c \
        elf32-s390.c \
+       elf32-score.c \
        elf32-sh.c \
        elf32-sh-symbian.c \
        elfxx-sparc.c \
@@ -1619,6 +1623,7 @@ cpu-pj.lo: cpu-pj.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h
 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
@@ -1997,6 +2002,10 @@ elf32-sh64-com.lo: elf32-sh64-com.c $(INCDIR)/filenames.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 \
index 9776c44..0440cce 100644 (file)
@@ -348,6 +348,7 @@ DESCRIPTION
 .  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,
@@ -466,6 +467,7 @@ extern const bfd_arch_info_type bfd_powerpc_archs[];
 #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;
@@ -531,6 +533,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
     &bfd_powerpc_arch,
     &bfd_rs6000_arch,
     &bfd_s390_arch,
+    &bfd_score_arch,
     &bfd_sh_arch,
     &bfd_sparc_arch,
     &bfd_tic30_arch,
index 841cc46..33ecf25 100644 (file)
@@ -1968,6 +1968,7 @@ enum bfd_architecture
   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,
@@ -3760,6 +3761,31 @@ instructions  */
   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,
 
index 22a7a11..0d0212a 100644 (file)
@@ -1143,6 +1143,11 @@ case "${targ}" in
     ;;
 #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
index c7d5a43..ea3c356 100755 (executable)
@@ -10873,6 +10873,8 @@ do
     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.
index 95b126a..9af534a 100644 (file)
@@ -663,6 +663,8 @@ do
     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.
diff --git a/bfd/cpu-score.c b/bfd/cpu-score.c
new file mode 100644 (file)
index 0000000..c910817
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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.  */
+};
diff --git a/bfd/elf32-score.c b/bfd/elf32-score.c
new file mode 100644 (file)
index 0000000..c84763a
--- /dev/null
@@ -0,0 +1,3883 @@
+/* 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"
index 0aa7046..40e9182 100644 (file)
@@ -1610,6 +1610,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "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",
index 60ebf36..56eebcf 100644 (file)
@@ -3966,6 +3966,43 @@ 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
   Scenix IP2K - 9-bit register number / data address
index 3471c25..489d0ce 100644 (file)
@@ -624,6 +624,8 @@ extern const bfd_target bfd_elf32_powerpc_vec;
 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;
@@ -944,6 +946,8 @@ static const bfd_target * const _bfd_target_vector[] = {
        &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,
index 23f0a81..cadf2b8 100644 (file)
@@ -1,3 +1,9 @@
+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>
 
index d10d88a..db53117 100644 (file)
@@ -540,7 +540,7 @@ readelf.o: readelf.c dwarf.h ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   $(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 \
index c758823..c82787d 100644 (file)
@@ -235,7 +235,6 @@ EXEEXT = @EXEEXT@
 EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
 GENCAT = @GENCAT@
 GMSGFMT = @GMSGFMT@
-GREP = @GREP@
 HDEFINES = @HDEFINES@
 INCINTL = @INCINTL@
 INSTALL_DATA = @INSTALL_DATA@
@@ -282,8 +281,9 @@ VERSION = @VERSION@
 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@
@@ -300,7 +300,6 @@ build_vendor = @build_vendor@
 datadir = @datadir@
 datarootdir = @datarootdir@
 docdir = @docdir@
-dvidir = @dvidir@
 exec_prefix = @exec_prefix@
 host = @host@
 host_alias = @host_alias@
@@ -313,15 +312,12 @@ infodir = @infodir@
 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@
@@ -333,6 +329,7 @@ target_vendor = @target_vendor@
 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
@@ -1263,7 +1260,7 @@ readelf.o: readelf.c dwarf.h ../bfd/bfd.h $(INCDIR)/ansidecl.h \
   $(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 \
index 6d0e66c..b1f3fc6 100644 (file)
@@ -73,6 +73,7 @@
 #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"
@@ -86,6 +87,7 @@
 #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"
@@ -566,6 +567,7 @@ guess_is_rela (unsigned long e_machine)
     case EM_CYGNUS_D10V:
     case EM_MIPS:
     case EM_MIPS_RS3_LE:
+    case EM_SCORE:
       return FALSE;
 
       /* Targets that use RELA relocations.  */
@@ -1099,6 +1101,10 @@ dump_relocations (FILE *file,
          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;
@@ -1432,6 +1438,23 @@ get_alpha_dynamic_type (unsigned long type)
 }
 
 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)
 {
   static char buff[64];
@@ -1539,6 +1562,9 @@ 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;
@@ -1693,6 +1719,7 @@ get_machine_name (unsigned e_machine)
     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";
index 5ea2728..64b3470 100644 (file)
@@ -1,3 +1,12 @@
+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.
index dbf3dee..2a4f5a3 100644 (file)
@@ -77,6 +77,7 @@ CPU_TYPES = \
        pj \
        ppc \
        s390 \
+       score \
        sh \
        sh64 \
        sparc \
@@ -264,6 +265,7 @@ TARGET_CPU_CFILES = \
        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 \
@@ -315,6 +317,7 @@ TARGET_CPU_HFILES = \
        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 \
@@ -1281,6 +1284,13 @@ DEPTC_s390_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.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 \
index dd07dc6..2d53f12 100644 (file)
@@ -306,6 +306,7 @@ CPU_TYPES = \
        pj \
        ppc \
        s390 \
+       score \
        sh \
        sh64 \
        sparc \
@@ -491,6 +492,7 @@ TARGET_CPU_CFILES = \
        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 \
@@ -542,6 +544,7 @@ TARGET_CPU_HFILES = \
        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 \
@@ -1081,6 +1084,14 @@ DEPTC_s390_elf = $(srcdir)/config/obj-elf.h $(BFDDIR)/elf-bfd.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 \
index 4b4d029..23ae48d 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,4 +1,5 @@
 -*- text -*-
+* Add support for Score target.
 
 * Support for the Infineon XC16X has been added by KPIT Cummins Infosystems.
 
diff --git a/gas/config/tc-score.c b/gas/config/tc-score.c
new file mode 100644 (file)
index 0000000..05c0c0b
--- /dev/null
@@ -0,0 +1,6634 @@
+/* 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}
+};
+
diff --git a/gas/config/tc-score.h b/gas/config/tc-score.h
new file mode 100644 (file)
index 0000000..2cd4039
--- /dev/null
@@ -0,0 +1,83 @@
+/* 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 */
index edcfc34..e7c7e23 100644 (file)
@@ -62,6 +62,8 @@ case ${cpu} in
   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 ;;
@@ -315,6 +317,8 @@ case ${generic_target} in
   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 ;;
index 506b705..072cfb2 100644 (file)
@@ -1,3 +1,9 @@
+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.
index 43265d0..2acecbf 100644 (file)
@@ -50,6 +50,9 @@ if { ([istarget "*-*-*elf*"]
     if {[istarget m32r*-*-*]} then {
        set target_machine -m32r
     }
+    if {[istarget "score-*-*"]} then {
+       set target_machine -score
+    }
     if { ([istarget "*arm*-*-*"]
          || [istarget "xscale*-*-*"])
        && ([istarget "*-*-*eabi"]
diff --git a/gas/testsuite/gas/elf/section2.e-score b/gas/testsuite/gas/elf/section2.e-score
new file mode 100644 (file)
index 0000000..6f30cba
--- /dev/null
@@ -0,0 +1,9 @@
+
+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 
index b072b52..6c09101 100644 (file)
@@ -1,3 +1,7 @@
+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.
index bdbf9f8..d6f0374 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
@@ -37,7 +37,8 @@ extern "C" {
 
 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 */
@@ -58,7 +59,8 @@ enum dis_insn_type {
    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;
@@ -201,59 +203,63 @@ typedef struct disassemble_info {
    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 *);
@@ -261,14 +267,12 @@ extern int print_insn_tic80               (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 *);
@@ -277,9 +281,9 @@ extern void print_mips_disassembler_options (FILE *);
 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.  */
index f1c15b5..c9914d9 100644 (file)
@@ -1,3 +1,8 @@
+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.
index 0380a8f..f041ecb 100644 (file)
 #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
diff --git a/include/elf/score.h b/include/elf/score.h
new file mode 100644 (file)
index 0000000..8eb69a7
--- /dev/null
@@ -0,0 +1,124 @@
+/* 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 */
index 5170514..26df6fe 100644 (file)
@@ -1,3 +1,8 @@
+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,
diff --git a/include/opcode/score-datadep.h b/include/opcode/score-datadep.h
new file mode 100644 (file)
index 0000000..8ef35ad
--- /dev/null
@@ -0,0 +1,282 @@
+/* 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
diff --git a/include/opcode/score-inst.h b/include/opcode/score-inst.h
new file mode 100644 (file)
index 0000000..56ceca4
--- /dev/null
@@ -0,0 +1,506 @@
+/* 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
index 99cc477..281fb56 100644 (file)
@@ -1,3 +1,12 @@
+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>
 
index 3fad390..34c56ef 100644 (file)
@@ -340,6 +340,7 @@ ALL_EMULATIONS = \
        eppcpe.o \
        eppclynx.o \
        eriscix.o \
+       escoreelf.o \
        esh.o \
        eshelf32.o \
        eshlelf32.o \
@@ -1466,6 +1467,10 @@ eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \
 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)"
index 53aed95..1ac8661 100644 (file)
@@ -564,6 +564,7 @@ ALL_EMULATIONS = \
        eppcpe.o \
        eppclynx.o \
        eriscix.o \
+       escoreelf.o \
        esh.o \
        eshelf32.o \
        eshlelf32.o \
@@ -2277,6 +2278,10 @@ eppclynx.c: $(srcdir)/emulparams/ppclynx.sh \
 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)"
diff --git a/ld/NEWS b/ld/NEWS
index 7856bf8..c879293 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,4 +1,6 @@
 -*- 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
index 81ad816..632db8d 100644 (file)
@@ -445,6 +445,7 @@ s390-*-linux*)          targ_emul=elf_s390
                          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 ;;
diff --git a/ld/emulparams/scoreelf.sh b/ld/emulparams/scoreelf.sh
new file mode 100644 (file)
index 0000000..e138de2
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/ld/emultempl/scoreelf.em b/ld/emultempl/scoreelf.em
new file mode 100644 (file)
index 0000000..a529a1b
--- /dev/null
@@ -0,0 +1,74 @@
+# 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
+
index 468c2bd..10cb5f2 100644 (file)
@@ -1,3 +1,9 @@
+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.
index 12b8458..bc5a7b2 100644 (file)
@@ -2,7 +2,7 @@
 #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-*-*"
index ebcebf1..9b4edb4 100644 (file)
@@ -1,5 +1,5 @@
 # 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
@@ -38,6 +38,13 @@ if { [which $CC] == 0 } {
     untested $test1c2
     return
 }
+if { [istarget score-*-*] } {
+    untested $test1w1
+    untested $test1w2
+    untested $test1c1
+    untested $test1c2
+    return
+}
 
 proc dump_common1 { testname } {
     global exec_output
index 74e76e6..d98b926 100644 (file)
@@ -1,6 +1,6 @@
 # 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
@@ -391,6 +391,7 @@ setup_xfail "ia64-*-*"
 # 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"
 
@@ -422,5 +423,6 @@ setup_xfail "alpha*-*-netbsd*"
 setup_xfail "hppa*-*-*"
 setup_xfail "ia64-*-*"
 setup_xfail "*-*-cygwin*" "*-*-mingw*" "*-*-pe*" "*-*-winnt*"
+setup_xfail "score-*-*"
 
 run_srec_test $test2 "tmpdir/sr3.o"
index e87e62a..b48077d 100644 (file)
@@ -1,3 +1,13 @@
+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>
 
index e54a829..3bf38e9 100644 (file)
@@ -41,6 +41,7 @@ HFILES = \
        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 \
@@ -162,6 +163,7 @@ CFILES = \
        s390-mkopc.c \
        s390-opc.c \
        s390-dis.c \
+       score-dis.c \
        sh-dis.c \
        sh64-dis.c \
        sh64-opc.c \
@@ -293,6 +295,7 @@ ALL_MACHINES = \
        ppc-opc.lo \
        s390-dis.lo \
        s390-opc.lo \
+       score-dis.lo \
        sh-dis.lo \
        sh64-dis.lo \
        sh64-opc.lo \
@@ -936,6 +939,11 @@ s390-opc.lo: s390-opc.c $(INCDIR)/ansidecl.h $(INCDIR)/opcode/s390.h \
 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) \
index bcbd41e..6d3275f 100644 (file)
@@ -254,6 +254,7 @@ HFILES = \
        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 \
@@ -376,6 +377,7 @@ CFILES = \
        s390-mkopc.c \
        s390-opc.c \
        s390-dis.c \
+       score-dis.c \
        sh-dis.c \
        sh64-dis.c \
        sh64-opc.c \
@@ -507,6 +509,7 @@ ALL_MACHINES = \
        ppc-opc.lo \
        s390-dis.lo \
        s390-opc.lo \
+       score-dis.lo \
        sh-dis.lo \
        sh64-dis.lo \
        sh64-opc.lo \
@@ -1473,6 +1476,11 @@ s390-opc.lo: s390-opc.c $(INCDIR)/ansidecl.h $(INCDIR)/opcode/s390.h \
 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) \
index db0fdf4..b8d01e6 100755 (executable)
@@ -5230,8 +5230,9 @@ INCINTL=
 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
@@ -6571,6 +6572,7 @@ if test x${all_targets} = xfalse ; then
        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
index 46da039..ef8463a 100644 (file)
@@ -201,6 +201,7 @@ if test x${all_targets} = xfalse ; then
        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
index 3ea4583..14f6d37 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
@@ -64,6 +64,7 @@
 #define ARCH_powerpc
 #define ARCH_rs6000
 #define ARCH_s390
+#define ARCH_score
 #define ARCH_sh
 #define ARCH_sparc
 #define ARCH_tic30
@@ -326,6 +327,14 @@ disassembler (abfd)
       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;
diff --git a/opcodes/score-dis.c b/opcodes/score-dis.c
new file mode 100644 (file)
index 0000000..0a4f67c
--- /dev/null
@@ -0,0 +1,504 @@
+/* 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);
+}
diff --git a/opcodes/score-opc.h b/opcodes/score-opc.h
new file mode 100644 (file)
index 0000000..e6e672d
--- /dev/null
@@ -0,0 +1,487 @@
+/* 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"}
+};