gdb/fortran: Support for single/double type modifiers
[deliverable/binutils-gdb.git] / gas / config / tc-nds32.c
index 94479bac3ae9e1debdda681e50a7d8888d640058..a75dd9ada9c89c3bc9ab89a5356db2d125f2a56c 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-nds32.c -- Assemble for the nds32
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
    Contributed by Andes Technology Corporation.
 
    This file is part of GAS, the GNU Assembler.
 #include "hash.h"
 #include "sb.h"
 #include "macro.h"
-#include "struc-symbol.h"
 #include "opcode/nds32.h"
 
 #include <stdio.h>
+#include <errno.h>
+#include <limits.h>
 
 /* GAS definitions.  */
 
@@ -55,23 +56,27 @@ static int enable_16bit = 1;
    expanded from the pseudo instruction.  */
 static bfd_boolean pseudo_opcode = FALSE;
 static struct nds32_relocs_pattern *relocs_list = NULL;
+/* Save instruction relation to inserting relaxation relocation.  */
 struct nds32_relocs_pattern
 {
   segT seg;
   fragS *frag;
   frchainS *frchain;
   symbolS *sym;
-  int reloc;
-  unsigned int insn;
-  unsigned int size;
+  fixS* fixP;
+  struct nds32_opcode *opcode;
   char *where;
   struct nds32_relocs_pattern *next;
+  /* Assembled instruction bytes.  */
+  uint32_t insn;
+};
+
+/* Suffix name and relocation.  */
+struct suffix_name
+{
+  const char *suffix;
+  short unsigned int reloc;
 };
-/*
-static int relax_jal_bound = 3;
-static int multi_call_relax;
-static int pltgot_call_relax;
-*/
 static int vec_size = 0;
 /* If the assembly code is generated by compiler, it is supposed to have
    ".flag verbatim" at beginning of the content.  We have
@@ -79,1785 +84,2222 @@ static int vec_size = 0;
 static int verbatim = 0;
 static struct hash_control *nds32_gprs_hash;
 static struct hash_control *nds32_hint_hash;
+#define TLS_REG "$r27"
+#define GOT_NAME "_GLOBAL_OFFSET_TABLE_"
 
 /* Generate relocation for relax or not, and the default is true.  */
 static int enable_relax_relocs = 1;
-/* The value will be used in RELAX_ENTRY.  */
-static int enable_relax_ex9 = 0;
-/* The value will be used in RELAX_ENTRY.  */
-static int enable_relax_ifc = 0;
-/* Save option -O for perfomance.  */
+/* Save option -O for performance.  */
 static int optimize = 0;
 /* Save option -Os for code size.  */
 static int optimize_for_space = 0;
-
-struct nds32_keyword nds32_fsrs[] =
-{
-  /* Standard names.  */
-  {"$fs0", 0, 0}, {"$fs1", 1, 0}, {"$fs2", 2, 0}, {"$fs3", 3, 0},
-  {"$fs4", 4, 0}, {"$fs5", 5, 0}, {"$fs6", 6, 0}, {"$fs7", 7, 0},
-  {"$fs8", 8, 0}, {"$fs9", 9, 0}, {"$fs10", 10, 0}, {"$fs11", 11, 0},
-  {"$fs12", 12, 0}, {"$fs13", 13, 0}, {"$fs14", 14, 0}, {"$fs15", 15, 0},
-  {"$fs16", 16, 0}, {"$fs17", 17, 0}, {"$fs18", 18, 0}, {"$fs19", 19, 0},
-  {"$fs20", 20, 0}, {"$fs21", 21, 0}, {"$fs22", 22, 0}, {"$fs23", 23, 0},
-  {"$fs24", 24, 0}, {"$fs25", 25, 0}, {"$fs26", 26, 0}, {"$fs27", 27, 0},
-  {"$fs28", 28, 0}, {"$fs29", 29, 0}, {"$fs30", 30, 0}, {"$fs31", 31, 0},
-  {NULL, 0, 0}
-};
-
-struct nds32_keyword nds32_fdrs[] =
-{
-  /* Standard names.  */
-  {"$fd0", 0, 0}, {"$fd1", 1, 0}, {"$fd2", 2, 0}, {"$fd3", 3, 0},
-  {"$fd4", 4, 0}, {"$fd5", 5, 0}, {"$fd6", 6, 0}, {"$fd7", 7, 0},
-  {"$fd8", 8, 0}, {"$fd9", 9, 0}, {"$fd10", 10, 0}, {"$fd11", 11, 0},
-  {"$fd12", 12, 0}, {"$fd13", 13, 0}, {"$fd14", 14, 0}, {"$fd15", 15, 0},
-  {"$fd16", 16, 0}, {"$fd17", 17, 0}, {"$fd18", 18, 0}, {"$fd19", 19, 0},
-  {"$fd20", 20, 0}, {"$fd21", 21, 0}, {"$fd22", 22, 0}, {"$fd23", 23, 0},
-  {"$fd24", 24, 0}, {"$fd25", 25, 0}, {"$fd26", 26, 0}, {"$fd27", 27, 0},
-  {"$fd28", 28, 0}, {"$fd29", 29, 0}, {"$fd30", 30, 0}, {"$fd31", 31, 0},
-  {NULL, 0, 0}
+/* Flag to save label exist.  */
+static int label_exist = 0;
+/* Flag to save state in omit_fp region.  */
+static int in_omit_fp = 0;
+extern struct nds32_keyword keyword_gpr[];
+/* Tag there is relax relocation having to link.  */
+static bfd_boolean relaxing = FALSE;
+/* ICT model.  */
+enum ict_option {
+  ICT_NONE = 0,
+  ICT_SMALL,
+  ICT_LARGE
 };
-
-struct nds32_keyword nds32_gprs[] =
-{
-  /* Standard names.  */
-  {"$r0", 0, 0}, {"$r1", 1, 0}, {"$r2", 2, 0}, {"$r3", 3, 0},
-  {"$r4", 4, 0}, {"$r5", 5, 0}, {"$r6", 6, 0}, {"$r7", 7, 0},
-  {"$r8", 8, 0}, {"$r9", 9, 0}, {"$r10", 10, 0}, {"$r11", 11, 0},
-  {"$r12", 12, 0}, {"$r13", 13, 0}, {"$r14", 14, 0}, {"$r15", 15, 0},
-  {"$r16", 16, 0}, {"$r17", 17, 0}, {"$r18", 18, 0}, {"$r19", 19, 0},
-  {"$r20", 20, 0}, {"$r21", 21, 0}, {"$r22", 22, 0}, {"$r23", 23, 0},
-  {"$r24", 24, 0}, {"$r25", 25, 0}, {"$r26", 26, 0}, {"$r27", 27, 0},
-  {"$r28", 28, 0}, {"$r29", 29, 0}, {"$r30", 30, 0}, {"$r31", 31, 0},
-  /* Names for parameter passing.  */
-  {"$a0", 0, 0}, {"$a1", 1, 0}, {"$a2", 2, 0}, {"$a3", 3, 0},
-  {"$a4", 4, 0}, {"$a5", 5, 0},
-  /* Names reserved for 5-bit addressing only.  */
-  {"$s0", 6, 0}, {"$s1", 7, 0}, {"$s2", 8, 0}, {"$s3", 9, 0},
-  {"$s4", 10, 0}, {"$s5", 11, 0}, {"$s6", 12, 0}, {"$s7", 13, 0},
-  {"$s8", 14, 0}, {"$s9", 28, 0},
-  {"$ta", 15, 0},
-  {"$t0", 16, 0}, {"$t1", 17, 0}, {"$t2", 18, 0}, {"$t3", 19, 0},
-  {"$t4", 20, 0}, {"$t5", 21, 0}, {"$t6", 22, 0}, {"$t7", 23, 0},
-  {"$t8", 24, 0}, {"$t9", 25, 0},
-  {"$p0", 26, 0}, {"$p1", 27, 0},
-  {"$fp", 28, 0}, {"$gp", 29, 0}, {"$lp", 30, 0}, {"$sp", 31, 0},
-  /* Names reserved for 4-bit addressing only.  */
-  {"$h0", 0, 0}, {"$h1", 1, 0}, {"$h2", 2, 0}, {"$h3", 3, 0},
-  {"$h4", 4, 0}, {"$h5", 5, 0}, {"$h6", 6, 0}, {"$h7", 7, 0},
-  {"$h8", 8, 0}, {"$h9", 9, 0}, {"$h10", 10, 0}, {"$h11", 11, 0},
-  {"$h12", 16, 0}, {"$h13", 17, 0}, {"$h14", 18, 0}, {"$h15", 19, 0},
-  /* Names reserved for 3-bit addressing only.  */
-  {"$o0", 0, 0}, {"$o1", 1, 0}, {"$o2", 2, 0}, {"$o3", 3, 0},
-  {"$o4", 4, 0}, {"$o5", 5, 0}, {"$o6", 6, 0}, {"$o7", 7, 0},
-  {NULL, 0, 0}
-};
-
+static enum ict_option ict_flag = ICT_NONE;
 \f
+
 static struct hash_control *nds32_relax_info_hash;
+
+/* Branch patterns.  */
 static relax_info_t relax_table[] =
 {
   {
-    "jal",                                     /* opcode */
-    BR_RANGE_S16M,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
-    {
-      {
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JRAL_TA
-      }, /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {{0, 0, 0}}, /* BR_RANGE_S256 */
-      {{0, 0, 0}}, /* BR_RANGE_S16K */
-      {{0, 0, 0}}, /* BR_RANGE_S64K */
-      {{0, 0, 0}}, /* BR_RANGE_S16M */
-      {{0, 0, 0}} /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 4, 12},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_HI20},
-        {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL1},
-        {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {8, 4, NDS32_ORIGIN, 0},
-        {8, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bltzal",                                  /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BLTZAL /* bltzal $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BLTZAL /* bltzal $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BLTZAL /* bltzal $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-       INSN_BGEZ,  /* bgez $rt, $1 */
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S16M */
-      {
-       INSN_BGEZ,  /* bgez $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JRAL_TA /* jral $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bgezal",                                  /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BGEZAL /* bgezal $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BGEZAL /* bgezal $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BGEZAL /* bgezal $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BLTZ,  /* bltz $rt, $1 */
-        INSN_JAL /* jal label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BLTZ,  /* bltz $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JRAL_TA /* jral $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "j",                                       /* opcode */
-    BR_RANGE_S16M,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
-    {
-      {
-        (INSN_J8 << 16) /* j8 label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      }, /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {{0, 0, 0}}, /* BR_RANGE_S256 */
-      {{0, 0, 0}}, /* BR_RANGE_S16K */
-      {{0, 0, 0}}, /* BR_RANGE_S64K */
-      {{0, 0, 0}}, /* BR_RANGE_S16M */
-      {{0, 0, 0}} /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {2, 4, 4, 4, 12},                          /* relax_code_size */
-    {2, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 2, 0, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_HI20},
-        {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1},
-        {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {8, 4, NDS32_ORIGIN, 0},
-        {8, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "j8",                                      /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
-    {
-      {
-        (INSN_J8 << 16) /* j8 label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      }, /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {{0, 0, 0}}, /* BR_RANGE_S256 */
-      {{0, 0, 0}}, /* BR_RANGE_S16K */
-      {{0, 0, 0}}, /* BR_RANGE_S64K */
-      {{0, 0, 0}}, /* BR_RANGE_S16M */
-      {{0, 0, 0}} /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {2, 4, 4, 4, 12},                          /* relax_code_size */
-    {2, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 2, 0, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_HI20},
-        {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1},
-        {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {8, 4, NDS32_ORIGIN, 0},
-        {8, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "beqz",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                 /* cond_field */
-    {
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNEZ,  /* bnez $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNEZ,  /* bnez $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bgez",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BGEZ /* bgez $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BGEZ /* bgez $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BGEZ /* bgez $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BLTZ,  /* bltz $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BLTZ,  /* bltz $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bnez",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQZ,  /* beqz $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQZ,  /* beqz $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bgtz",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BGTZ /* bgtz $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BGTZ /* bgtz $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BGTZ /* bgtz $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BLEZ,  /* blez $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BLEZ,  /* blez $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "blez",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BLEZ /* blez $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BLEZ /* blez $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BLEZ /* blez $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BGTZ,  /* bgtz $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BGTZ,  /* bgtz $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "bltz",                                    /* opcode */
-    BR_RANGE_S64K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BLTZ /* bltz $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BLTZ /* bltz $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BLTZ /* bltz $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BGEZ,  /* bgez $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BGEZ,  /* bgez $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
-  },
-  {
-    "beq",                                     /* opcode */
-    BR_RANGE_S16K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      {0, 15, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BEQ /* beq $rt, $ra, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BEQ /* beq $rt, $ra, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNE, /* bne $rt, $ra, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNE, /* bne $rt, $ra, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNE, /* bne $rt, $ra, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "jal",
+    .br_range = BR_RANGE_S16M,
+    .cond_field =
+      {
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_size[BR_RANGE_S16M] = 4,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JRAL_TA    /* jral $ta */
+      },
+    .relax_code_size[BR_RANGE_U4G] = 12,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, 0, BFD_RELOC_NDS32_HI20},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL4},
+       {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "bne",                                     /* opcode */
-    BR_RANGE_S16K,                             /* br_range */
-    {
-      {0, 20, 0x1F},
-      {0, 15, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BNE /* bne $rt, $ra, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNE /* bne $rt, $ra, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BEQ, /* beq $rt, $ra, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQ, /* beq $rt, $ra, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQ, /* beq $rt, $ra, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "bgezal",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+         INSN_BGEZAL   /* bgezal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BGEZAL     /* bgezal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BGEZAL     /* bgezal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BLTZ,      /* bltz $rt, $1 */
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BLTZ,      /* bltz $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JRAL_TA    /* jral $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "beqz38",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BEQZ /* beqz $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNEZ,  /* bnez $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNEZ, /* bnez $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "bltzal",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+         INSN_BLTZAL   /* bltzal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BLTZAL     /* bltzal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BLTZAL     /* bltzal $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BGEZ,      /* bgez $rt, $1 */
+       INSN_JAL        /* jal label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BGEZ,      /* bgez $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JRAL_TA    /* jral $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "bnez38",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQZ,  /* beqz $rt, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQZ, /* beqz $rt, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "j",
+    .br_range = BR_RANGE_S16M,
+    .cond_field =
+      {
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       (INSN_J8 << 16) /* j8 label */
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_J          /* j label */
+      },
+    . relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S16M] = 4,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_size[BR_RANGE_U4G] = 12,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, 0, BFD_RELOC_NDS32_HI20},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4},
+       {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "beqzs8",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                                       /* cond_field */
-    {
-      {
-        INSN_BEQZ_TA /* beqz $r15, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNEZ /* bnez $rt, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNEZ_TA,  /* bnez $r15, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNEZ_TA, /* bnez $r15, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {{0, 0, 0}}, /* BR_RANGE_S256 */
-      {{0, 0, 0}}, /* BR_RANGE_S16K */
-      {{0, 0, 0}}, /* BR_RANGE_S64K */
-      {{0, 0, 0}}, /* BR_RANGE_S16M */
-      {{0, 0, 0}} /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "j8",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       (INSN_J8 << 16) /* j8 label */
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S16M] = 4,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_size[BR_RANGE_U4G] = 12,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, 0, BFD_RELOC_NDS32_HI20},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4},
+       {4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "bnezs8",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                                       /* cond_field */
-    {
-      {
-        INSN_BNEZ_TA /* bnez $r15, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNEZ_TA /* bnez $r15, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNEZ_TA /* bnez $r15, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQZ_TA,  /* beqz $r15, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQZ_TA,  /* beqz $r15, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {{0, 0, 0}}, /* BR_RANGE_S256 */
-      {{0, 0, 0}}, /* BR_RANGE_S16K */
-      {{0, 0, 0}}, /* BR_RANGE_S64K */
-      {{0, 0, 0}}, /* BR_RANGE_S16M */
-      {{0, 0, 0}} /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_17_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "beqz",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    /* We do not use beqz38 and beqzs8 here directly because we
+       don't want to check register number for specail condition.  */
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+         INSN_BEQZ     /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BEQZ       /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQZ       /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNEZ,      /* bnez $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       /* bnez range is 17 pcrel, but it use 15 pcrel here since link time
+          relaxtion.  If 17 pcrel can reach, it do not have to use S16M.
+          Therefore, 15 pcrel is just for linker to distinguish LONGJUMP5
+          and LONGJUMP6.  */
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNEZ,      /* bnez $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "bnes38",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BNE_R5 /* bne $rt, $r5, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BNE_R5 /* bne $rt, $r5, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "bgez",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BGEZ       /* bgez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BGEZ       /* bgez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BGEZ       /* bgez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BLTZ,      /* bltz $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BLTZ,      /* bltz $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "beqs38",                                  /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BEQ_R5 /* beq $rt, $r5, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_BEQ_R5 /* beq $rt, $r5, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL},
-        {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL},
-        {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL},
-        {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "bnez",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BNEZ       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BNEZ       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNEZ       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQZ,      /* beqz $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQZ,      /* beqz $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bgtz",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BGTZ       /* bgtz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BGTZ       /* bgtz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BGTZ       /* bgtz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BLEZ,      /* blez $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BLEZ,      /* blez $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "blez",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BLEZ       /* blez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BLEZ       /* blez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BLEZ       /* blez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BGTZ,      /* bgtz $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BGTZ,      /* bgtz $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bltz",
+    .br_range = BR_RANGE_S64K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BLTZ       /* bltz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BLTZ       /* bltz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BLTZ       /* bltz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BGEZ,      /* bgez $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BGEZ,      /* bgez $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE},
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "beq",
+    .br_range = BR_RANGE_S16K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BEQ        /* beq $rt, $ra, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BEQ        /* beq $rt, $ra, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNE,       /* bne $rt, $ra, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNE,       /* bne $rt, $ra, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNE,       /* bne $rt, $ra, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bne",
+    .br_range = BR_RANGE_S16K,
+    .cond_field =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BNE        /* bne $rt, $ra, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BNE        /* bne $rt, $ra, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQ,       /* beq $rt, $ra, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQ,       /* beq $rt, $ra, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQ,       /* beq $rt, $ra, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 15, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "beqz38",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BEQZ38 << 16       /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BEQZ       /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQZ       /* beqz $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNEZ,      /* bnez $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNEZ,      /* bnez $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bnez38",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BNEZ38 << 16       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BNEZ       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNEZ       /* bnez $rt, label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQZ,      /* beqz $rt, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQZ,      /* beqz $rt, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "beqzs8",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BEQZS8 << 16       /* beqz $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BEQZ_TA    /* beqz $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQZ_TA    /* beqz $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNEZ_TA,   /* bnez $r15, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNEZ_TA,   /* bnez $r15, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bnezs8",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BNEZS8 << 16       /* bnez $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BNEZ_TA    /* bnez $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNEZ_TA    /* bnez $r15, label */
+      },
+    .relax_code_size[BR_RANGE_S64K] = 4,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQZ_TA,   /* beqz $r15, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQZ_TA,   /* beqz $r15, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "bnes38",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BNES38 << 16       /* bne $rt, $r5, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BNE_R5     /* bne $rt, $r5, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQ_R5,    /* beq $rt, $r5, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQ_R5,    /* beq $rt, $r5, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQ_R5,    /* beq $rt, $r5, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+  },
+  {
+    .opcode = "beqs38",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BEQS38 << 16       /* beq $rt, $r5, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 2,
+    .relax_branch_isize[BR_RANGE_S256] = 2,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_BEQ_R5     /* beq $rt, $r5, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 4,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNE_R5,    /* bne $rt, $r5, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNE_R5,    /* bne $rt, $r5, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNE_R5,    /* bne $rt, $r5, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI},
+       {8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY},
+       {12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "beqc",                                    /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7FF},
-      {0, 20, 0x1F},
-      {0, 0, 0}
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BEQC /* beqc $rt, imm11s, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
-        INSN_BEQ_TA /* beq $rt, $ta, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
-        INSN_BEQ_TA /* beq $rt, $ta, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BNEC,  /* bnec $rt, imm11s, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BNEC,  /* bnec $rt, imm11s, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 8, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "beqc",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7FF, TRUE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+       INSN_BEQC       /* beqc $rt, imm11s, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_MOVI_TA,   /* movi $ta, imm11s */
+       INSN_BEQ_TA     /* beq $rt, $ta, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 0, 0xFFFFF, FALSE},
+       {4, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 8,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BNEC,      /* bnec $rt, imm11s, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BNEC,      /* bnec $rt, imm11s, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BNEC,      /* bnec $rt, imm11s, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
+       {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    "bnec",                                    /* opcode */
-    BR_RANGE_S256,                             /* br_range */
-    {
-      {0, 8, 0x7FF},
-      {0, 20, 0x1F},
-      {0, 0, 0}
-    },                                         /* cond_field */
-    {
-      {
-        INSN_BNEC /* bnec $rt, imm11s, label */
-      }, /* BR_RANGE_S256 */
-      {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
-        INSN_BNE_TA /* bne $rt, $ta, label */
-      }, /* BR_RANGE_S16K */
-      {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
-        INSN_BNE_TA /* bne $rt, $ta, label */
-      }, /* BR_RANGE_S64K */
-      {
-        INSN_BEQC,  /* beqc $rt, imm11s, $1 */
-        INSN_J /* j label */
-      }, /* BR_RANGE_S16M */
-      {
-        INSN_BEQC,  /* beqc $rt, imm11s, $1 */
-        INSN_SETHI_TA, /* sethi $ta, label */
-        INSN_ORI_TA, /* ori $ta, $ta, label */
-        INSN_JR_TA /* jr $ta */
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
-    {
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
-      } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 8, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
-    {
-      {
-        {0, 4, 0, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S256 */
-      {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16K */
-      {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S64K */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
-        {0, 0, 0, 0}
-      }, /* BR_RANGE_S16M */
-      {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
-        {4, 4, 0, BFD_RELOC_NDS32_HI20},
-        {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
-        {12, 4, NDS32_ORIGIN, 0},
-        {12, 2, NDS32_CONVERT, 0},
-        {0, 0, 0, 0}
-      } /* BR_RANGE_U4G */
-    }                                          /* relax_fixup */
+    .opcode = "bnec",
+    .br_range = BR_RANGE_S256,
+    .cond_field =
+      {
+       {0, 8, 0x7FF, TRUE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_seq[BR_RANGE_S256] =
+      {
+         INSN_BNEC     /* bnec $rt, imm11s, label */
+      },
+    .relax_code_condition[BR_RANGE_S256] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S256] = 4,
+    .relax_branch_isize[BR_RANGE_S256] = 4,
+    .relax_fixup[BR_RANGE_S256] =
+      {
+       {0, 4, NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16K] =
+      {
+       INSN_MOVI_TA,   /* movi $ta, imm11s */
+       INSN_BNE_TA     /* bne $rt, $ta, label */
+      },
+    .relax_code_condition[BR_RANGE_S16K] =
+      {
+       {0, 0, 0xFFFFF, FALSE},
+       {4, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16K] = 8,
+    .relax_branch_isize[BR_RANGE_S16K] = 4,
+    .relax_fixup[BR_RANGE_S16K] =
+      {
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S64K] =
+      {
+       INSN_BEQC,      /* beqc $rt, imm11s, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S64K] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S64K] = 8,
+    .relax_branch_isize[BR_RANGE_S64K] = 4,
+    .relax_fixup[BR_RANGE_S64K] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_S16M] =
+      {
+       INSN_BEQC,      /* beqc $rt, imm11s, $1 */
+       INSN_J          /* j label */
+      },
+    .relax_code_condition[BR_RANGE_S16M] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_S16M] = 8,
+    .relax_branch_isize[BR_RANGE_S16M] = 4,
+    .relax_fixup[BR_RANGE_S16M] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL},
+       {0, 0, 0, 0}
+      },
+
+    .relax_code_seq[BR_RANGE_U4G] =
+      {
+       INSN_BEQC,      /* beqc $rt, imm11s, $1 */
+       INSN_SETHI_TA,  /* sethi $ta, label */
+       INSN_ORI_TA,    /* ori $ta, $ta, label */
+       INSN_JR_TA      /* jr $ta */
+      },
+    .relax_code_condition[BR_RANGE_U4G] =
+      {
+       {0, 8, 0x7FF, FALSE},
+       {0, 20, 0x1F, FALSE},
+       {0, 0, 0, FALSE}
+      },
+    .relax_code_size[BR_RANGE_U4G] = 16,
+    .relax_branch_isize[BR_RANGE_U4G] = 4,
+    .relax_fixup[BR_RANGE_U4G] =
+      {
+       {0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL},
+       {4, 4, 0, BFD_RELOC_NDS32_HI20},
+       {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
+       {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      },
   },
   {
-    NULL,                              /* opcode */
-    0,                                 /* br_range */
-    {{0, 0, 0}},                       /* cond_field */
-    {{0}},                             /* relax_code_seq */
-    {{{0, 0, 0}}},                     /* relax_code_condition */
-    {0},                               /* relax_code_size */
-    {0},                               /* relax_branch_isize */
-    {{{0, 0, 0, 0}}},                  /* relax_fixup */
+    .opcode = NULL,
   },
 };
-
 \f
+
 /* GAS definitions for command-line options.  */
 enum options
 {
@@ -1872,7 +2314,7 @@ enum options
   OPTION_OPTIMIZE_SPACE
 };
 
-const char *md_shortopts = "m:G:O";
+const char *md_shortopts = "m:O:";
 struct option md_longopts[] =
 {
   {"O1", no_argument, NULL, OPTION_OPTIMIZE},
@@ -1884,6 +2326,7 @@ struct option md_longopts[] =
   {"meb", no_argument, NULL, OPTION_BIG},
   {"mel", no_argument, NULL, OPTION_LITTLE},
   {"mall-ext", no_argument, NULL, OPTION_TURBO},
+  {"mext-all", no_argument, NULL, OPTION_TURBO},
   {"mpic", no_argument, NULL, OPTION_PIC},
   /* Relaxation related options.  */
   {"mno-fp-as-gp-relax", no_argument, NULL, OPTION_RELAX_FP_AS_GP_OFF},
@@ -1897,16 +2340,16 @@ size_t md_longopts_size = sizeof (md_longopts);
 struct nds32_parse_option_table
 {
   const char *name;            /* Option string.  */
-  char *help;                  /* Help description.  */
-  int (*func) (char *arg);     /* How to parse it.  */
+  const char *help;                    /* Help description.  */
+  int (*func) (const char *arg);       /* How to parse it.  */
 };
 
 
 /* The value `-1' represents this option has *NOT* been set.  */
 #ifdef NDS32_DEFAULT_ARCH_NAME
-static char* nds32_arch_name = NDS32_DEFAULT_ARCH_NAME;
+static const char* nds32_arch_name = NDS32_DEFAULT_ARCH_NAME;
 #else
-static char* nds32_arch_name = "v3";
+static const char* nds32_arch_name = "v3";
 #endif
 static int nds32_baseline = -1;
 static int nds32_gpr16 = -1;
@@ -1919,10 +2362,13 @@ static int nds32_abi = -1;
 static int nds32_elf_flags = 0;
 static int nds32_fpu_com = 0;
 
-static int nds32_parse_arch (char *str);
-static int nds32_parse_baseline (char *str);
-static int nds32_parse_freg (char *str);
-static int nds32_parse_abi (char *str);
+static int nds32_parse_arch (const char *str);
+static int nds32_parse_baseline (const char *str);
+static int nds32_parse_freg (const char *str);
+static int nds32_parse_abi (const char *str);
+static void add_mapping_symbol (enum mstate state,
+                               unsigned int padding_byte,
+                               unsigned int align);
 
 static struct nds32_parse_option_table parse_opts [] =
 {
@@ -1947,11 +2393,13 @@ static struct nds32_parse_option_table parse_opts [] =
 static int nds32_mac = 1;
 static int nds32_div = 1;
 static int nds32_16bit_ext = 1;
-static int nds32_dx_regs = 1;
-static int nds32_perf_ext = 1;
-static int nds32_perf_ext2 = 1;
-static int nds32_string_ext = 1;
-static int nds32_audio_ext = 1;
+static int nds32_dx_regs = NDS32_DEFAULT_DX_REGS;
+static int nds32_perf_ext = NDS32_DEFAULT_PERF_EXT;
+static int nds32_perf_ext2 = NDS32_DEFAULT_PERF_EXT2;
+static int nds32_string_ext = NDS32_DEFAULT_STRING_EXT;
+static int nds32_audio_ext = NDS32_DEFAULT_AUDIO_EXT;
+static int nds32_dsp_ext = NDS32_DEFAULT_DSP_EXT;
+static int nds32_zol_ext = NDS32_DEFAULT_ZOL_EXT;
 static int nds32_fpu_fma = 0;
 static int nds32_pic = 0;
 static int nds32_relax_fp_as_gp = 1;
@@ -1960,7 +2408,7 @@ static int nds32_relax_all = 1;
 struct nds32_set_option_table
 {
   const char *name;            /* Option string.  */
-  char *help;                  /* Help description.  */
+  const char *help;                    /* Help description.  */
   int *var;                    /* Variable to be set.  */
   int value;                   /* Value to set.  */
 };
@@ -1982,6 +2430,8 @@ static struct nds32_set_option_table toggle_opts [] =
   {"fpu-sp-ext", N_("FPU SP extension"), &nds32_fpu_sp_ext, 1},
   {"fpu-dp-ext", N_("FPU DP extension"), &nds32_fpu_dp_ext, 1},
   {"fpu-fma", N_("FPU fused-multiply-add instructions"), &nds32_fpu_fma, 1},
+  {"dsp-ext", N_("DSP extension"), &nds32_dsp_ext, 1},
+  {"zol-ext", N_("hardware loop extension"), &nds32_zol_ext, 1},
   {NULL, NULL, NULL, 0}
 };
 
@@ -1995,7 +2445,7 @@ nds32_asm_parse_operand (struct nds32_asm_desc *pdesc,
                         char **pstr, int64_t *value);
 
 \f
-struct nds32_asm_desc asm_desc;
+static struct nds32_asm_desc asm_desc;
 
 /* md_after_parse_args ()
 
@@ -2085,13 +2535,13 @@ nds32_start_line_hook (void)
  * Pseudo opcodes
  */
 
-typedef void (*nds32_pseudo_opcode_func) (int argc, char *argv[], int pv);
+typedef void (*nds32_pseudo_opcode_func) (int argc, char *argv[], unsigned int pv);
 struct nds32_pseudo_opcode
 {
   const char *opcode;
   int argc;
   nds32_pseudo_opcode_func proc;
-  int pseudo_val;
+  unsigned int pseudo_val;
 
   /* Some instructions are not pseudo opcode, but they might still be
      expanded or changed with other instruction combination for some
@@ -2124,14 +2574,18 @@ static struct hash_control *nds32_pseudo_opcode_hash = NULL;
 static int
 builtin_isreg (const char *s, const char *x ATTRIBUTE_UNUSED)
 {
-  return s[0] == '$';
+  if (s [0] == '$' && hash_find (nds32_gprs_hash, (s + 1)))
+    return 1;
+  return 0;
 }
 
 static int
 builtin_regnum (const char *s, const char *x ATTRIBUTE_UNUSED)
 {
   struct nds32_keyword *k;
-
+  if (*s != '$')
+    return -1;
+  s++;
   k = hash_find (nds32_gprs_hash, s);
 
   if (k == NULL)
@@ -2155,7 +2609,7 @@ builtin_addend (const char *s, char *x ATTRIBUTE_UNUSED)
 }
 
 static void
-md_assemblef (char *format, ...)
+md_assemblef (const char *format, ...)
 {
   /* FIXME: hope this is long enough.  */
   char line[1024];
@@ -2170,49 +2624,54 @@ md_assemblef (char *format, ...)
 }
 
 /* Some prototypes here, since some op may use another op.  */
-static void do_pseudo_li_internal (char *rt, int imm32s);
+static void do_pseudo_li_internal (const char *rt, int imm32s);
 static void do_pseudo_move_reg_internal (char *dst, char *src);
 
 static void
-do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], 
+            unsigned int pv ATTRIBUTE_UNUSED)
 {
   char *arg_label = argv[0];
+  relaxing = TRUE;
   /* b   label */
-  if (nds32_pic
-      && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT")))
+  if (nds32_pic)
     {
       md_assemblef ("sethi $ta,hi20(%s)", arg_label);
       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label);
-      md_assemble  ("add $ta,$ta,$gp");
-      md_assemble  ("jr $ta");
+      md_assemble  ((char *) "add $ta,$ta,$gp");
+      md_assemble  ((char *) "jr $ta");
     }
   else
     {
       md_assemblef ("j %s", arg_label);
     }
+  relaxing = FALSE;
 }
 
 static void
-do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   char *arg_label = argv[0];
+  relaxing = TRUE;
   /* bal|call  label */
-  if (nds32_pic
-      && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT")))
+  if (nds32_pic)
     {
       md_assemblef ("sethi $ta,hi20(%s)", arg_label);
       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label);
-      md_assemble  ("add $ta,$ta,$gp");
-      md_assemble ("jral $ta");
+      md_assemble ((char *) "add $ta,$ta,$gp");
+      md_assemble ((char *) "jral $ta");
     }
   else
     {
       md_assemblef ("jal %s", arg_label);
     }
+  relaxing = FALSE;
 }
 
 static void
-do_pseudo_bge (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bge (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* rt5, ra5, label */
   md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]);
@@ -2220,7 +2679,8 @@ do_pseudo_bge (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_bges (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bges (int argc ATTRIBUTE_UNUSED, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* rt5, ra5, label */
   md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]);
@@ -2228,7 +2688,8 @@ do_pseudo_bges (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED
 }
 
 static void
-do_pseudo_bgt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bgt (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* bgt rt5, ra5, label */
   md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]);
@@ -2236,7 +2697,8 @@ do_pseudo_bgt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_bgts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bgts (int argc ATTRIBUTE_UNUSED, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* bgt rt5, ra5, label */
   md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]);
@@ -2244,7 +2706,8 @@ do_pseudo_bgts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED
 }
 
 static void
-do_pseudo_ble (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_ble (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* bgt rt5, ra5, label */
   md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]);
@@ -2252,7 +2715,8 @@ do_pseudo_ble (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_bles (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bles (int argc ATTRIBUTE_UNUSED, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* bgt rt5, ra5, label */
   md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]);
@@ -2260,7 +2724,8 @@ do_pseudo_bles (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED
 }
 
 static void
-do_pseudo_blt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_blt (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* rt5, ra5, label */
   md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]);
@@ -2268,7 +2733,8 @@ do_pseudo_blt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_blts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_blts (int argc ATTRIBUTE_UNUSED, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* rt5, ra5, label */
   md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]);
@@ -2276,13 +2742,15 @@ do_pseudo_blts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED
 }
 
 static void
-do_pseudo_br (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_br (int argc ATTRIBUTE_UNUSED, char *argv[], 
+             unsigned int pv ATTRIBUTE_UNUSED)
 {
   md_assemblef ("jr %s", argv[0]);
 }
 
 static void
-do_pseudo_bral (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_bral (int argc, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
   if (argc == 1)
     md_assemblef ("jral $lp,%s", argv[0]);
@@ -2291,21 +2759,47 @@ do_pseudo_bral (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_la_internal (const char *arg_reg, const char *arg_label, const char *line)
+do_pseudo_la_internal (const char *arg_reg, char *arg_label,
+                      const char *line)
 {
+  expressionS exp;
+
+  parse_expression (arg_label, &exp);
+  if (exp.X_op != O_symbol)
+    {
+      as_bad (_("la must use with symbol. '%s'"), line);
+      return;
+    }
+
+  relaxing = TRUE;
   /* rt, label */
-  if (!nds32_pic)
+  if (!nds32_pic && !strstr (arg_label, "@"))
     {
       md_assemblef ("sethi %s,hi20(%s)", arg_reg, arg_label);
       md_assemblef ("ori %s,%s,lo12(%s)", arg_reg, arg_reg, arg_label);
     }
-  else if ((strstr (arg_label, "@PLT") || strstr (arg_label, "@GOTOFF")))
+  else if (strstr (arg_label, "@TPOFF"))
+    {
+      /* la $rt, sym@TPOFF  */
+      md_assemblef ("sethi $ta,hi20(%s)", arg_label);
+      md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label);
+      md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG);
+    }
+  else if (strstr(arg_label, "@GOTTPOFF"))
+    {
+      /* la $rt, sym@GOTTPOFF*/
+      md_assemblef ("sethi $ta,hi20(%s)", arg_label);
+      md_assemblef ("lwi $ta,[$ta+lo12(%s)]", arg_label);
+      md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG);
+    }
+  else if (nds32_pic && ((strstr (arg_label, "@PLT")
+                         || strstr (arg_label, "@GOTOFF"))))
     {
       md_assemblef ("sethi $ta,hi20(%s)", arg_label);
       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label);
       md_assemblef ("add %s,$ta,$gp", arg_reg);
     }
-  else if (strstr (arg_label, "@GOT"))
+  else if (nds32_pic && strstr (arg_label, "@GOT"))
     {
       long addend = builtin_addend (arg_label, NULL);
 
@@ -2327,16 +2821,18 @@ do_pseudo_la_internal (const char *arg_reg, const char *arg_label, const char *l
     }
    else
       as_bad (_("need PIC qualifier with symbol. '%s'"), line);
+  relaxing = FALSE;
 }
 
 static void
-do_pseudo_la (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_la (int argc ATTRIBUTE_UNUSED, char *argv[], 
+             unsigned int pv ATTRIBUTE_UNUSED)
 {
   do_pseudo_la_internal (argv[0], argv[1], argv[argc]);
 }
 
 static void
-do_pseudo_li_internal (char *rt, int imm32s)
+do_pseudo_li_internal (const char *rt, int imm32s)
 {
   if (enable_16bit && imm32s <= 0xf && imm32s >= -0x10)
     md_assemblef ("movi55 %s,%d", rt, imm32s);
@@ -2352,7 +2848,8 @@ do_pseudo_li_internal (char *rt, int imm32s)
 }
 
 static void
-do_pseudo_li (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_li (int argc ATTRIBUTE_UNUSED, char *argv[], 
+             unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* Validate argv[1] for constant expression.  */
   expressionS exp;
@@ -2368,7 +2865,8 @@ do_pseudo_li (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
+do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], 
+                 unsigned int pv)
 {
   char ls = 'r';
   char size = 'x';
@@ -2390,16 +2888,36 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
   if (builtin_isreg (argv[1], NULL))
     {
       /* lwi */
-      md_assemblef ("%c%c%si %s,[%s]", ls, size, argv[0], argv[1]);
+      md_assemblef ("%c%ci %s,[%s]", ls, size, argv[0], argv[1]);
     }
   else if (!nds32_pic)
     {
-      /* lwi */
-      md_assemblef ("sethi $ta,hi20(%s)", argv[1]);
-      md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]);
+      relaxing = TRUE;
+      if (strstr (argv[1], "@TPOFF"))
+       {
+         /* ls.w $rt, sym@TPOFF  */
+         md_assemblef ("sethi $ta,hi20(%s)", argv[1]);
+         md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]);
+         md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG);
+       }
+      else if (strstr (argv[1], "@GOTTPOFF"))
+       {
+         /* ls.w $rt, sym@GOTTPOFF  */
+         md_assemblef ("sethi $ta,hi20(%s)", argv[1]);
+         md_assemblef ("lwi $ta,[$ta+lo12(%s)]", argv[1]);
+         md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG);
+       }
+      else
+       {
+         /* lwi */
+         md_assemblef ("sethi $ta,hi20(%s)", argv[1]);
+         md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]);
+       }
+      relaxing = FALSE;
     }
   else
     {
+      relaxing = TRUE;
       /* PIC code.  */
       if (strstr (argv[1], "@GOTOFF"))
        {
@@ -2414,7 +2932,7 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
          /* lw */
          md_assemblef ("sethi $ta,hi20(%s)", argv[1]);
          md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]);
-         md_assemble ("lw $ta,[$gp+$ta]");     /* Load address word.  */
+         md_assemble ((char *) "lw $ta,[$gp+$ta]");    /* Load address word.  */
          if (addend < 0x10000 && addend >= -0x10000)
            {
              md_assemblef ("%c%c%si %s,[$ta+(%d)]", ls, size, sign, argv[0], addend);
@@ -2430,11 +2948,13 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
        {
          as_bad (_("needs @GOT or @GOTOFF. %s"), argv[argc]);
        }
+      relaxing = FALSE;
     }
 }
 
 static void
-do_pseudo_ls_bhwp (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
+do_pseudo_ls_bhwp (int argc ATTRIBUTE_UNUSED, char *argv[], 
+                  unsigned int pv)
 {
   char *arg_rt = argv[0];
   char *arg_label = argv[1];
@@ -2461,10 +2981,11 @@ do_pseudo_ls_bhwp (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
 }
 
 static void
-do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
+do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[],
+                   unsigned int pv)
 {
   char *arg_rt = argv[0];
-  char *arg_inc = argv[2];
+  char *arg_inc = argv[1];
   char ls = 'r';
   char size = 'x';
   const char *sign = "";
@@ -2486,7 +3007,8 @@ do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
 }
 
 static void
-do_pseudo_ls_bhwi (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
+do_pseudo_ls_bhwi (int argc ATTRIBUTE_UNUSED, char *argv[], 
+                  unsigned int pv)
 {
   char ls = 'r';
   char size = 'x';
@@ -2519,36 +3041,49 @@ do_pseudo_move_reg_internal (char *dst, char *src)
 }
 
 static void
-do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[], 
+               unsigned int pv ATTRIBUTE_UNUSED)
 {
+  expressionS exp;
+
   if (builtin_isreg (argv[1], NULL))
     do_pseudo_move_reg_internal (argv[0], argv[1]);
   else
-    /* move $rt, imm  -> li $rt, imm */
-    do_pseudo_li (argc, argv, PV_DONT_CARE);
+    {
+      parse_expression (argv[1], &exp);
+      if (exp.X_op == O_constant)
+       /* move $rt, imm  -> li $rt, imm  */
+       do_pseudo_li_internal (argv[0], exp.X_add_number);
+      else
+       /* l.w $rt, var  -> l.w $rt, var  */
+       do_pseudo_ls_bhw (argc, argv, 2);
+    }
 }
 
 static void
-do_pseudo_neg (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_neg (int argc ATTRIBUTE_UNUSED, char *argv[], 
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
-  md_assemble ("movi $ta,0");
-  md_assemblef ("sub %s,$ta,%s", argv[0], argv[1]);
+  /* Instead of "subri".  */
+  md_assemblef ("subri %s,%s,0", argv[0], argv[1]);
 }
 
 static void
-do_pseudo_not (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_not (int argc ATTRIBUTE_UNUSED, char *argv[],
+              unsigned int pv ATTRIBUTE_UNUSED)
 {
   md_assemblef ("nor %s,%s,%s", argv[0], argv[1], argv[1]);
 }
 
 static void
-do_pseudo_pushpopm (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_pushpopm (int argc, char *argv[],
+                   unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* posh/pop $ra, $rb */
   /* SMW.{b | a}{i | d}{m?} Rb, [Ra], Re, Enable4 */
   int rb, re, ra, en4;
   int i;
-  char *opc = "pushpopm";
+  const char *opc = "pushpopm";
 
   if (argc == 3)
     as_bad ("'pushm/popm $ra5, $rb5, $label' is deprecated.  "
@@ -2586,14 +3121,26 @@ do_pseudo_pushpopm (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
   /* Adjust $re, $rb.  */
   if (rb >= 28)
     rb = re = 31;
-  else if (re >= 28)
+  else if (nds32_gpr16 != 1 && re >= 28)
     re = 27;
 
-  md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4);
+  /* Reduce register.  */
+  if (nds32_gpr16 && re > 10 && !(rb == 31 && re == 31))
+    {
+      if (re >= 15 && strstr (opc, "smw") != NULL)
+       md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4);
+      if (rb <= 10)
+       md_assemblef ("%s $r%d,[$sp],$r10, 0x0", opc, rb);
+      if (re >= 15 && strstr (opc, "lmw") != NULL)
+       md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4);
+    }
+  else
+    md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4);
 }
 
 static void
-do_pseudo_pushpop (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_pushpop (int argc, char *argv[],
+                  unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* push/pop $ra5, $label=$sp */
   char *argvm[3];
@@ -2609,13 +3156,15 @@ do_pseudo_pushpop (int argc, char *argv[], int pv ATTRIBUTE_UNUSED)
 }
 
 static void
-do_pseudo_v3push (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_v3push (int argc ATTRIBUTE_UNUSED, char *argv[],
+                 unsigned int pv ATTRIBUTE_UNUSED)
 {
   md_assemblef ("push25 %s,%s", argv[0], argv[1]);
 }
 
 static void
-do_pseudo_v3pop (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_v3pop (int argc ATTRIBUTE_UNUSED, char *argv[], 
+                unsigned int pv ATTRIBUTE_UNUSED)
 {
   md_assemblef ("pop25 %s,%s", argv[0], argv[1]);
 }
@@ -2624,7 +3173,8 @@ do_pseudo_v3pop (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSE
    pv != 0, parsing "pop.s" pseudo instruction operands.  */
 
 static void
-do_pseudo_pushpop_stack (int argc, char *argv[], int pv)
+do_pseudo_pushpop_stack (int argc, char *argv[],
+                        unsigned int pv)
 {
   /* push.s Rb,Re,{$fp $gp $lp $sp}  ==>  smw.adm Rb,[$sp],Re,Eable4  */
   /* pop.s Rb,Re,{$fp $gp $lp $sp}   ==>  lmw.bim Rb,[$sp],Re,Eable4  */
@@ -2632,7 +3182,7 @@ do_pseudo_pushpop_stack (int argc, char *argv[], int pv)
   int rb, re;
   int en4;
   int last_arg_index;
-  char *opc = (pv == 0) ? "smw.adm" : "lmw.bim";
+  const char *opc = (pv == 0) ? "smw.adm" : "lmw.bim";
 
   rb = re = 0;
 
@@ -2688,7 +3238,8 @@ do_pseudo_pushpop_stack (int argc, char *argv[], int pv)
 }
 
 static void
-do_pseudo_push_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_push_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[],
+                    unsigned int pv ATTRIBUTE_UNUSED)
 {
   char size = 'x';
   /* If users omit push location, use $sp as default value.  */
@@ -2719,7 +3270,8 @@ do_pseudo_push_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_U
 }
 
 static void
-do_pseudo_pop_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_pop_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[],
+                   unsigned int pv ATTRIBUTE_UNUSED)
 {
   char size = 'x';
   /* If users omit pop location, use $sp as default value.  */
@@ -2750,7 +3302,8 @@ do_pseudo_pop_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UN
 }
 
 static void
-do_pseudo_pusha (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_pusha (int argc ATTRIBUTE_UNUSED, char *argv[],
+                unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* If users omit push location, use $sp as default value.  */
   char location[8] = "$sp";  /* 8 is enough for register name.  */
@@ -2766,7 +3319,8 @@ do_pseudo_pusha (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSE
 }
 
 static void
-do_pseudo_pushi (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
+do_pseudo_pushi (int argc ATTRIBUTE_UNUSED, char *argv[],
+                unsigned int pv ATTRIBUTE_UNUSED)
 {
   /* If users omit push location, use $sp as default value.  */
   char location[8] = "$sp";  /* 8 is enough for register name.  */
@@ -2781,7 +3335,7 @@ do_pseudo_pushi (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSE
   md_assemblef ("smw.adm $ta,[%s],$ta", location);
 }
 
-struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] =
+static struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] =
 {
   {"b",      1, do_pseudo_b,      0, 0},
   {"bal",    1, do_pseudo_bal,    0, 0},
@@ -2842,7 +3396,7 @@ struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] =
   {"swi.p",  3, do_pseudo_ls_bhwi, 2 | 0x80000000, 0},
   {"lbsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0},
   {"lhsi.p", 3, do_pseudo_ls_bhwi, 1 | 0x10, 0},
-  {"lwsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0},
+  {"lwsi.p", 3, do_pseudo_ls_bhwi, 2 | 0x10, 0},
 
   {"move",   2, do_pseudo_move, 0, 0},
   {"neg",    2, do_pseudo_neg,  0, 0},
@@ -2857,8 +3411,8 @@ struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] =
   {"v3pop",  2, do_pseudo_v3pop,  0, 0},
 
   /* Support pseudo instructions of pushing/poping registers into/from stack
-       push.s  Rb, Re, { $fp $gp $lp $sp }  ==>  smw.adm  Rb,[$sp],Re,Enable4
-       pop.s   Rb, Re, { $fp $gp $lp $sp }  ==>  lmw.bim  Rb,[$sp],Re,Enable4 */
+     push.s  Rb, Re, { $fp $gp $lp $sp }  ==>  smw.adm  Rb,[$sp],Re,Enable4
+     pop.s   Rb, Re, { $fp $gp $lp $sp }  ==>  lmw.bim  Rb,[$sp],Re,Enable4 */
   { "push.s", 3, do_pseudo_pushpop_stack, 0, 0 },
   { "pop.s", 3, do_pseudo_pushpop_stack, 1, 0 },
   { "push.b", 2, do_pseudo_push_bhwd, 0, 0 },
@@ -2896,24 +3450,25 @@ nds32_init_nds32_pseudo_opcodes (void)
 }
 
 static struct nds32_pseudo_opcode *
-nds32_lookup_pseudo_opcode (char *str)
+nds32_lookup_pseudo_opcode (const char *str)
 {
+  struct nds32_pseudo_opcode *result;
   int i = 0;
-  /* Assume pseudo-opcode are less than 16-char in length.  */
-  char op[16] = {0};
 
-  for (i = 0; i < (int)ARRAY_SIZE (op); i++)
+  /* (*op) is the first word of current source line (*str)  */
+  int maxlen = strlen (str);
+  char *op = xmalloc (maxlen + 1);
+
+  for (i = 0; i < maxlen; i++)
     {
       if (ISSPACE (op[i] = str[i]))
        break;
     }
-
-  if (i >= (int)ARRAY_SIZE (op))
-    return NULL;
-
   op[i] = '\0';
 
-  return hash_find (nds32_pseudo_opcode_hash, op);
+  result = hash_find (nds32_pseudo_opcode_hash, op);
+  free (op);
+  return result;
 }
 
 static void
@@ -2957,7 +3512,7 @@ end:
    Thus, if the value of option has been set, keep the value the way it is.  */
 
 static int
-nds32_parse_arch (char *str)
+nds32_parse_arch (const char *str)
 {
   static const struct nds32_arch
   {
@@ -3007,7 +3562,7 @@ nds32_parse_arch (char *str)
 /* This function parses "baseline" specified.  */
 
 static int
-nds32_parse_baseline (char *str)
+nds32_parse_baseline (const char *str)
 {
   if (strcmp (str, "v3") == 0)
     nds32_baseline = ISA_V3;
@@ -3028,7 +3583,7 @@ nds32_parse_baseline (char *str)
 /* This function parses "fpu-freg" specified.  */
 
 static int
-nds32_parse_freg (char *str)
+nds32_parse_freg (const char *str)
 {
   if (strcmp (str, "2") == 0)
     nds32_freg = E_NDS32_FPU_REG_32SP_16DP;
@@ -3051,7 +3606,7 @@ nds32_parse_freg (char *str)
 /* This function parse "abi=" specified.  */
 
 static int
-nds32_parse_abi (char *str)
+nds32_parse_abi (const char *str)
 {
   if (strcmp (str, "v2") == 0)
     nds32_abi = E_NDS_ABI_AABI;
@@ -3088,6 +3643,10 @@ nds32_all_ext (void)
   nds32_fpu_fma = 1;
   nds32_fpu_sp_ext = 1;
   nds32_fpu_dp_ext = 1;
+  nds32_dsp_ext = 1;
+  nds32_zol_ext = 1;
+  /* Turn off reduced register.  */
+  nds32_gpr16 = 0;
 
   return 1;
 }
@@ -3099,11 +3658,11 @@ nds32_all_ext (void)
    recognized.  This will be handled by the generic code.  */
 
 int
-nds32_parse_option (int c, char *arg)
+nds32_parse_option (int c, const char *arg)
 {
   struct nds32_parse_option_table *coarse_tune;
   struct nds32_set_option_table *fine_tune;
-  char *ptr_arg = NULL;
+  const char *ptr_arg = NULL;
 
   switch (c)
     {
@@ -3138,7 +3697,11 @@ nds32_parse_option (int c, char *arg)
       break;
     default:
       /* Determination of which option table to search for to save time.  */
+      if (!arg)
+       return 0;
+
       ptr_arg = strchr (arg, '=');
+
       if (ptr_arg)
        {
          /* Find the value after '='.  */
@@ -3155,17 +3718,17 @@ nds32_parse_option (int c, char *arg)
        }
       else
        {
-         for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++)
-           {
-             int disable = 0;
+         int disable = 0;
 
-             /* Filter out the Disable option first.  */
-             if (strncmp (arg, "no-", 3) == 0)
-               {
-                 disable = 1;
-                 arg += 3;
-               }
+         /* Filter out the Disable option first.  */
+         if (strncmp (arg, "no-", 3) == 0)
+           {
+             disable = 1;
+             arg += 3;
+           }
 
+         for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++)
+           {
              if (strcmp (arg, fine_tune->name) == 0)
                {
                  if (fine_tune->var != NULL)
@@ -3278,7 +3841,7 @@ do_nds32_seg (int i, subsegT sub)
       seg->s = subseg_new (seg->name, sub);
       if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
        {
-         bfd_set_section_flags (stdoutput, seg->s, seg->flags);
+         bfd_set_section_flags (seg->s, seg->flags);
          if ((seg->flags & SEC_LOAD) == 0)
            seg_info (seg->s)->bss = 1;
        }
@@ -3295,24 +3858,39 @@ nds32_seg (int i)
 }
 
 /* Set if label adjustment is needed.  I should not adjust .xbyte in dwarf.  */
-static symbolS *nds32_last_label;      /* Last label for aligment.  */
+static symbolS *nds32_last_label;      /* Last label for alignment.  */
+
+static void
+add_mapping_symbol_for_align (int shift, valueT addr, int is_data_align)
+{
+  if ((shift > 1) && (addr & 1))
+    {
+      int n = (1 << shift) - 1;
+      if (!is_data_align)
+       add_mapping_symbol (MAP_CODE, 1, 0);
+      else if ((int) (addr & n) != n)
+       add_mapping_symbol (MAP_CODE, 1, 0);
+    }
+  else if ((shift > 1) && ((int) (addr & 1) == 0))
+    add_mapping_symbol (MAP_CODE, 0, 0);
+}
 
-/* This code is referred from D30V for adjust label to be with pedning
-   aligment.  For example,
+/* This code is referred from D30V for adjust label to be with pending
+   alignment.  For example,
      LBYTE: .byte      0x12
      LHALF: .half      0x12
      LWORD: .word      0x12
-   Without this, the above label will not attatch to incoming data.  */
+   Without this, the above label will not attach to incoming data.  */
 
 static void
 nds32_adjust_label (int n)
 {
-  /* FIXME: I think adjust lable and alignment is
-     the programmer's obligation.  Saddly, VLSI team doesn't
+  /* FIXME: I think adjust label and alignment is
+     the programmer's obligation.  Sadly, VLSI team doesn't
      properly use .align for their test cases.
      So I re-implement cons_align and auto adjust labels, again.
 
-     I think d30v's implmentation is simple and good enough.  */
+     I think d30v's implementation is simple and good enough.  */
 
   symbolS *label = nds32_last_label;
   nds32_last_label = NULL;
@@ -3330,7 +3908,10 @@ nds32_adjust_label (int n)
   if (frag_now_fix () & ((1 << n) -1 ))
     {
       if (subseg_text_p (now_seg))
-       frag_align_code (n, 0);
+       {
+         add_mapping_symbol_for_align (n, frag_now_fix (), 1);
+         frag_align_code (n, 0);
+       }
       else
        frag_align (n, 0, 0);
 
@@ -3379,7 +3960,7 @@ nds32_cons_align (int size ATTRIBUTE_UNUSED)
 
      There are two things should be done for auto-adjust-label.
      1. Align data/instructions and adjust label to be attached to them.
-     2. Clear auto-adjust state, so incommng data/instructions will not
+     2. Clear auto-adjust state, so incoming data/instructions will not
        adjust the label.
 
      For example,
@@ -3395,26 +3976,76 @@ nds32_cons_align (int size ATTRIBUTE_UNUSED)
      I think we should just adjust label in `nds32_aligned_X_cons' instead of here.  */
 }
 
+static void
+make_mapping_symbol (enum mstate state, valueT value, fragS * frag, unsigned int align)
+{
+  symbolS *symbol_p = NULL;
+  const char *symbol_name = NULL;
+  switch (state)
+    {
+    case MAP_DATA:
+      if (align == 0)
+       symbol_name = "$d0";
+      else if (align == 1)
+       symbol_name = "$d1";
+      else if (align == 2)
+       symbol_name = "$d2";
+      else if (align == 3)
+       symbol_name = "$d3";
+      else if (align == 4)
+       symbol_name = "$d4";
+      break;
+    case MAP_CODE:
+      symbol_name = "$c";
+      break;
+    default:
+      abort ();
+    }
+
+  symbol_p = symbol_new (symbol_name, now_seg, value, frag);
+  /* local scope attribute  */
+  symbol_get_bfdsym (symbol_p)->flags |= BSF_NO_FLAGS | BSF_LOCAL;
+}
+
+static void
+add_mapping_symbol (enum mstate state, unsigned int padding_byte,
+                   unsigned int align)
+{
+  enum mstate current_mapping_state =
+    seg_info (now_seg)->tc_segment_info_data.mapstate;
+
+  if (state == MAP_CODE
+      && current_mapping_state == state)
+    return;
+
+  if (!SEG_NORMAL (now_seg)
+      || !subseg_text_p (now_seg))
+    return;
+
+  /* start adding mapping symbol  */
+  seg_info (now_seg)->tc_segment_info_data.mapstate = state;
+  make_mapping_symbol (state, (valueT) frag_now_fix () + padding_byte,
+                      frag_now, align);
+}
+
 static void
 nds32_aligned_cons (int idx)
 {
   nds32_adjust_label (idx);
+  add_mapping_symbol (MAP_DATA, 0, idx);
   /* Call default handler.  */
   cons (1 << idx);
   if (now_seg->flags & SEC_CODE
       && now_seg->flags & SEC_ALLOC && now_seg->flags & SEC_RELOC)
     {
-      /* Use BFD_RELOC_NDS32_DATA to avoid EX9 optimization replacing data.  */
+      /* Use BFD_RELOC_NDS32_DATA to avoid linker
+        optimization replacing data.  */
       expressionS exp;
 
       exp.X_add_number = 0;
       exp.X_op = O_constant;
-      fix_new_exp (frag_now,
-                  frag_now_fix () - (1 << idx),
-                  1 << idx,
-                  &exp,
-                  0,
-                  BFD_RELOC_NDS32_DATA);
+      fix_new_exp (frag_now, frag_now_fix () - (1 << idx), 1 << idx,
+                  &exp, 0, BFD_RELOC_NDS32_DATA);
     }
 }
 
@@ -3467,8 +4098,8 @@ nds32_relax_relocs (int relax)
   char saved_char;
   char *name;
   int i;
-  char *subtype_relax[] =
-    {"", "", "ex9", "ifc"};
+  const char *subtype_relax[] =
+    {"", "",};
 
   name = input_line_pointer;
   while (*input_line_pointer && !ISSPACE (*input_line_pointer))
@@ -3485,14 +4116,6 @@ nds32_relax_relocs (int relax)
            case 0:
            case 1:
              enable_relax_relocs = relax & enable_relax_relocs;
-             enable_relax_ex9 = relax & enable_relax_ex9;
-             enable_relax_ifc = relax & enable_relax_ifc;
-             break;
-           case 2:
-             enable_relax_ex9 = relax;
-             break;
-           case 3:
-             enable_relax_ifc = relax;
              break;
            default:
              break;
@@ -3528,43 +4151,20 @@ nds32_omit_fp_begin (int mode)
   exp.X_add_symbol = abs_section_sym;
   if (mode == 1)
     {
+      in_omit_fp = 1;
       exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0,
                   BFD_RELOC_NDS32_RELAX_REGION_BEGIN);
     }
   else
     {
+      in_omit_fp = 0;
       exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0,
                   BFD_RELOC_NDS32_RELAX_REGION_END);
     }
 }
 
-/* Insert relocations to mark the begin and end of ex9 region,
-   for further relaxation use.
-   bit[i] for $ri */
-
-static void
-nds32_no_ex9_begin (int mode)
-{
-  expressionS exp;
-
-  exp.X_op = O_symbol;
-  exp.X_add_symbol = abs_section_sym;
-  if (mode == 1)
-    {
-      exp.X_add_number = R_NDS32_RELAX_REGION_NO_EX9_FLAG;
-      fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0,
-                  BFD_RELOC_NDS32_RELAX_REGION_BEGIN);
-    }
-  else
-    {
-      exp.X_add_number = R_NDS32_RELAX_REGION_NO_EX9_FLAG;
-      fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0,
-                  BFD_RELOC_NDS32_RELAX_REGION_END);
-    }
-}
-
 static void
 nds32_loop_begin (int mode)
 {
@@ -3594,16 +4194,49 @@ struct nds32_relocs_group
 };
 
 static struct nds32_relocs_group *nds32_relax_hint_current = NULL;
+/* Used to reorder the id for ".relax_hint id".  */
+static int relax_hint_bias = 0;
+/* Record current relax hint id.  */
+static int relax_hint_id_current = -1;
+int reset_bias = 0;
+/* If ".relax_hint begin" is triggered?  */
+int relax_hint_begin = 0;
+
+/* Record the reordered relax hint id.  */
+
+struct relax_hint_id
+{
+  int old_id;
+  int new_id;
+  struct relax_hint_id *next;
+};
+
+/* FIXME: Need to find somewhere to free the list.  */
+struct relax_hint_id *record_id_head = NULL;
+
+/* Is the buffer large enough?  */
+#define MAX_BUFFER 12
+
+static char *nds_itoa (int n);
+
+static char *
+nds_itoa (int n)
+{
+  char *buf = xmalloc (MAX_BUFFER * sizeof (char));
+  snprintf (buf, MAX_BUFFER, "%d", n);
+  return buf;
+}
 
 /* Insert a relax hint.  */
 
 static void
 nds32_relax_hint (int mode ATTRIBUTE_UNUSED)
 {
-  char *name;
+  char *name = NULL;
   char saved_char;
   struct nds32_relocs_pattern *relocs = NULL;
   struct nds32_relocs_group *group, *new;
+  struct relax_hint_id *record_id;
 
   name = input_line_pointer;
   while (*input_line_pointer && !ISSPACE (*input_line_pointer))
@@ -3612,20 +4245,66 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED)
   *input_line_pointer = 0;
   name = strdup (name);
 
+  if (name && strcmp (name, "begin") == 0)
+    {
+      if (relax_hint_id_current == -1)
+       reset_bias = 1;
+      relax_hint_bias++;
+      relax_hint_id_current++;
+      relax_hint_begin = 1;
+    }
+
+  /* Original case ".relax_hint id".  It's id may need to be reordered. */
+  if (!relax_hint_begin)
+    {
+      int tmp = strtol (name, NULL, 10);
+      record_id = record_id_head;
+      while (record_id)
+       {
+         if (record_id->old_id == tmp)
+           {
+             name = nds_itoa (record_id->new_id);
+             goto reordered_id;
+           }
+         record_id = record_id->next;
+       }
+      if (reset_bias)
+       {
+         relax_hint_bias = relax_hint_id_current - atoi (name) + 1;
+         reset_bias = 0;
+       }
+      relax_hint_id_current = tmp + relax_hint_bias;
+
+      /* Insert the element to the head of the link list.  */
+      struct relax_hint_id *tmp_id = malloc (sizeof (struct relax_hint_id));
+      tmp_id->old_id = tmp;
+      tmp_id->new_id = relax_hint_id_current;
+      tmp_id->next = record_id_head;
+      record_id_head = tmp_id;
+    }
+
+  if (name && strcmp (name, "end") == 0)
+    relax_hint_begin = 0;
+  name = nds_itoa (relax_hint_id_current);
+
+reordered_id:
+
   /* Find relax hint entry for next instruction, and all member will be
      initialized at that time.  */
   relocs = hash_find (nds32_hint_hash, name);
   if (relocs == NULL)
     {
-      relocs = malloc (sizeof (struct nds32_relocs_pattern));
+      relocs = XNEW (struct nds32_relocs_pattern);
+      memset (relocs, 0, sizeof (struct nds32_relocs_pattern));
       hash_insert (nds32_hint_hash, name, relocs);
     }
   else
     {
       while (relocs->next)
        relocs=relocs->next;
-      relocs->next = malloc (sizeof (struct nds32_relocs_pattern));
+      relocs->next = XNEW (struct nds32_relocs_pattern);
       relocs = relocs->next;
+      memset (relocs, 0, sizeof (struct nds32_relocs_pattern));
     }
 
   relocs->next = NULL;
@@ -3637,7 +4316,8 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED)
   /* It has to build this list because there are maybe more than one
      instructions relative to the same instruction.  It to connect to
      next instruction after md_assemble.  */
-  new = malloc (sizeof (struct nds32_relocs_group));
+  new = XNEW (struct nds32_relocs_group);
+  memset (new, 0, sizeof (struct nds32_relocs_group));
   new->pattern = relocs;
   new->next = NULL;
   group = nds32_relax_hint_current;
@@ -3649,6 +4329,7 @@ nds32_relax_hint (int mode ATTRIBUTE_UNUSED)
        group = group->next;
       group->next = new;
     }
+  relaxing = TRUE;
 }
 
 /* Decide the size of vector entries, only accepts 4 or 16 now.  */
@@ -3679,18 +4360,55 @@ nds32_vec_size (int ignore ATTRIBUTE_UNUSED)
     as_warn (_("Argument of .vec_size is not a constant."));
 }
 
-/* The behavior of ".flag" directive varies depending on the target.
-   In nds32 target, we use it to recognize whether this assembly content is
-   generated by compiler.  Other features can also be added in this function
-   in the future.  */
-
+/* The behavior of ".flag" directive varies depending on the target.
+   In nds32 target, we use it to recognize whether this assembly content is
+   generated by compiler.  Other features can also be added in this function
+   in the future.  */
+
+static void
+nds32_flag (int ignore ATTRIBUTE_UNUSED)
+{
+  char *name;
+  char saved_char;
+  int i;
+  const char *possible_flags[] = { "verbatim" };
+
+  /* Skip whitespaces.  */
+  name = input_line_pointer;
+  while (*input_line_pointer && !ISSPACE (*input_line_pointer))
+    input_line_pointer++;
+  saved_char = *input_line_pointer;
+  *input_line_pointer = 0;
+
+  for (i = 0; i < (int) ARRAY_SIZE (possible_flags); i++)
+    {
+      if (strcmp (name, possible_flags[i]) == 0)
+       {
+         switch (i)
+           {
+           case 0:
+             /* flag: verbatim */
+             verbatim = 1;
+             break;
+           default:
+             break;
+           }
+         /* Already found the flag, no need to continue next loop.   */
+         break;
+       }
+    }
+
+  *input_line_pointer = saved_char;
+  ignore_rest_of_line ();
+}
+
 static void
-nds32_flag (int ignore ATTRIBUTE_UNUSED)
+ict_model (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   char saved_char;
   int i;
-  char *possible_flags[] = { "verbatim" };
+  const char *possible_flags[] = { "small", "large" };
 
   /* Skip whitespaces.  */
   name = input_line_pointer;
@@ -3706,8 +4424,11 @@ nds32_flag (int ignore ATTRIBUTE_UNUSED)
          switch (i)
            {
            case 0:
-             /* flag: verbatim */
-             verbatim = 1;
+             /* flag: verbatim  */
+             ict_flag = ICT_SMALL;
+             break;
+           case 1:
+             ict_flag = ICT_LARGE;
              break;
            default:
              break;
@@ -3781,13 +4502,12 @@ const pseudo_typeS md_pseudo_table[] =
   {"hint_func_args", nds32_set_hint_func_args, 0}, /* Abandon??  */
   {"omit_fp_begin", nds32_omit_fp_begin, 1},
   {"omit_fp_end", nds32_omit_fp_begin, 0},
-  {"no_ex9_begin", nds32_no_ex9_begin, 1},
-  {"no_ex9_end", nds32_no_ex9_begin, 0},
   {"vec_size", nds32_vec_size, 0},
   {"flag", nds32_flag, 0},
   {"innermost_loop_begin", nds32_loop_begin, 1},
   {"innermost_loop_end", nds32_loop_begin, 0},
   {"relax_hint", nds32_relax_hint, 0},
+  {"ict_model", ict_model, 0},
   {NULL, NULL, 0}
 };
 
@@ -3795,12 +4515,25 @@ void
 nds32_pre_do_align (int n, char *fill, int len, int max)
 {
   /* Only make a frag if we HAVE to...  */
+  fragS *fragP;
   if (n != 0 && !need_pass_2)
     {
       if (fill == NULL)
        {
          if (subseg_text_p (now_seg))
-           frag_align_code (n, max);
+           {
+             dwarf2_emit_insn (0);
+             fragP = frag_now;
+             add_mapping_symbol_for_align (n, frag_now_fix (), 0);
+             frag_align_code (n, max);
+
+             /* Tag this alignment when there is a label before it.  */
+             if (label_exist)
+               {
+                 fragP->tc_frag_data.flag = NDS32_FRAG_LABEL;
+                 label_exist = 0;
+               }
+           }
          else
            frag_align (n, 0, max);
        }
@@ -3879,16 +4612,19 @@ md_begin (void)
 {
   struct nds32_keyword *k;
   relax_info_t *relax_info;
+  int flags = 0;
 
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, nds32_baseline);
 
   nds32_init_nds32_pseudo_opcodes ();
   asm_desc.parse_operand = nds32_asm_parse_operand;
-  nds32_asm_init (&asm_desc, 0);
+  if (nds32_gpr16)
+    flags |= NASM_OPEN_REDUCED_REG;
+  nds32_asm_init (&asm_desc, flags);
 
-  /* Initial general pupose registers hash table.  */
+  /* Initial general purpose registers hash table.  */
   nds32_gprs_hash = hash_new ();
-  for (k = nds32_gprs; k->name; k++)
+  for (k = keyword_gpr; k->name; k++)
     hash_insert (nds32_gprs_hash, k->name, k);
 
   /* Initial branch hash table.  */
@@ -3898,6 +4634,7 @@ md_begin (void)
 
   /* Initial relax hint hash table.  */
   nds32_hint_hash = hash_new ();
+  enable_16bit = nds32_16bit_ext;
 }
 
 /* HANDLE_ALIGN in write.c.  */
@@ -3965,6 +4702,8 @@ nds32_frob_label (symbolS *label)
 int
 nds32_start_label (int asmdone ATTRIBUTE_UNUSED, int secdone ATTRIBUTE_UNUSED)
 {
+  if (optimize && subseg_text_p (now_seg))
+    label_exist = 1;
   return 1;
 }
 
@@ -4009,108 +4748,144 @@ get_range_type (const struct nds32_field *field)
 /* Save pseudo instruction relocation list.  */
 
 static struct nds32_relocs_pattern*
-nds32_elf_save_pseudo_pattern (int reloc, struct nds32_asm_insn *insn,
+nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_asm_insn *insn,
                               char *out, symbolS *sym,
-                              struct nds32_relocs_pattern *reloc_ptr)
+                              struct nds32_relocs_pattern *reloc_ptr,
+                              fragS *fragP)
 {
+  struct nds32_opcode *opcode = insn->opcode;
   if (!reloc_ptr)
-    reloc_ptr = malloc (sizeof (struct nds32_relocs_pattern));
+    reloc_ptr = XNEW (struct nds32_relocs_pattern);
   reloc_ptr->seg = now_seg;
   reloc_ptr->sym = sym;
-  reloc_ptr->frag = frag_now;
+  reloc_ptr->frag = fragP;
   reloc_ptr->frchain = frchain_now;
-  reloc_ptr->reloc = reloc;
-  reloc_ptr->insn = insn->opcode->value;
-  reloc_ptr->size = insn->opcode->isize;
+  reloc_ptr->fixP = fixP;
+  reloc_ptr->opcode = opcode;
   reloc_ptr->where = out;
+  reloc_ptr->insn = insn->insn;
   reloc_ptr->next = NULL;
   return reloc_ptr;
 }
 
 /* Check X_md to transform relocation.  */
 
-static void
-nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld,
+static fixS*
+nds32_elf_record_fixup_exp (fragS *fragP, const char *str,
+                           const struct nds32_field *fld,
                            expressionS *pexp, char* out,
                            struct nds32_asm_insn *insn)
 {
   int reloc = -1;
-  symbolS *sym = NULL;
-  struct nds32_relocs_group *group;
-  struct nds32_relocs_pattern *reloc_ptr;
+  expressionS exp;
+  fixS *fixP = NULL;
 
   /* Handle instruction relocation.  */
   if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_HI20))
     {
       /* Relocation for hi20 modifier.  */
-      sym = pexp->X_add_symbol;
       switch (pexp->X_md)
        {
-       case BFD_RELOC_NDS32_GOTOFF:
-         /* @GOTOFF  */
+       case BFD_RELOC_NDS32_GOTOFF:    /* @GOTOFF */
          reloc = BFD_RELOC_NDS32_GOTOFF_HI20;
          break;
-       case BFD_RELOC_NDS32_GOT20:
-         /* @GOT  */
+       case BFD_RELOC_NDS32_GOT20:     /* @GOT */
          reloc = BFD_RELOC_NDS32_GOT_HI20;
          break;
-       case BFD_RELOC_NDS32_25_PLTREL:
-         /* @PLT  */
+       case BFD_RELOC_NDS32_25_PLTREL: /* @PLT */
          if (!nds32_pic)
            as_bad (_("Invalid PIC expression."));
          else
            reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20;
          break;
-       default:
-         /* No suffix.  */
-         reloc = BFD_RELOC_NDS32_HI20;
+       case BFD_RELOC_NDS32_GOTPC20:   /* _GLOBAL_OFFSET_TABLE_ */
+         reloc = BFD_RELOC_NDS32_GOTPC_HI20;
+         break;
+       case BFD_RELOC_NDS32_TPOFF:     /* @TPOFF */
+         reloc = BFD_RELOC_NDS32_TLS_LE_HI20;
+         break;
+       case BFD_RELOC_NDS32_GOTTPOFF:  /* @GOTTPOFF */
+         reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_HI20 : BFD_RELOC_NDS32_TLS_IE_HI20;
+         break;
+       case BFD_RELOC_NDS32_TLS_DESC:  /* @TLSDESC */
+         reloc = BFD_RELOC_NDS32_TLS_DESC_HI20;
+         break;
+       default:        /* No suffix */
+         if (nds32_pic)
+           /* When the file is pic, the address must be offset to gp.
+              It may define another relocation or use GOTOFF.  */
+           reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20;
+         else
+           reloc = BFD_RELOC_NDS32_HI20;
          break;
        }
-
-      fix_new_exp (frag_now, out - frag_now->fr_literal,
-                  insn->opcode->isize, insn->info, 0 /* pcrel */,
-                  reloc);
+      fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize,
+                         insn->info, 0 /* pcrel */, reloc);
     }
   else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_LO12))
     {
       /* Relocation for lo12 modifier.  */
       if (fld->bitsize == 15 && fld->shift == 0)
        {
+         /* [ls]bi || ori */
          switch (pexp->X_md)
            {
-           case BFD_RELOC_NDS32_GOTOFF:
-             /* @GOTOFF  */
+           case BFD_RELOC_NDS32_GOTOFF:        /* @GOTOFF */
              reloc = BFD_RELOC_NDS32_GOTOFF_LO12;
              break;
-           case BFD_RELOC_NDS32_GOT20:
-             /* @GOT  */
+           case BFD_RELOC_NDS32_GOT20:         /* @GOT */
              reloc = BFD_RELOC_NDS32_GOT_LO12;
              break;
-           case BFD_RELOC_NDS32_25_PLTREL:
-             /* @PLT  */
+           case BFD_RELOC_NDS32_25_PLTREL:     /* @PLT */
              if (!nds32_pic)
                as_bad (_("Invalid PIC expression."));
              else
                reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12;
              break;
-           default:
-             /* No suffix.  */
-             reloc = BFD_RELOC_NDS32_LO12S0;           /* [ls]bi || ori  */
+           case BFD_RELOC_NDS32_GOTPC20:       /* _GLOBAL_OFFSET_TABLE_ */
+             reloc = BFD_RELOC_NDS32_GOTPC_LO12;
+             break;
+           case BFD_RELOC_NDS32_TPOFF:         /* @TPOFF */
+             reloc = BFD_RELOC_NDS32_TLS_LE_LO12;
+             break;
+           case BFD_RELOC_NDS32_GOTTPOFF:      /* @GOTTPOFF */
+             reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_LO12 : BFD_RELOC_NDS32_TLS_IE_LO12;
+             break;
+           case BFD_RELOC_NDS32_TLS_DESC:      /* @TLSDESC */
+             reloc = BFD_RELOC_NDS32_TLS_DESC_LO12;
+             break;
+           default:    /* No suffix */
+             if (nds32_pic)
+               /* When the file is pic, the address must be offset to gp.
+                  It may define another relocation or use GOTOFF.  */
+               reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12;
+             else
+               reloc = BFD_RELOC_NDS32_LO12S0;
              break;
            }
        }
       else if (fld->bitsize == 15 && fld->shift == 1)
        reloc = BFD_RELOC_NDS32_LO12S1;         /* [ls]hi */
       else if (fld->bitsize == 15 && fld->shift == 2)
-       reloc = BFD_RELOC_NDS32_LO12S2;         /* [ls]wi */
+       {
+         /* [ls]wi */
+         switch (pexp->X_md)
+           {
+           case BFD_RELOC_NDS32_GOTTPOFF:      /* @GOTTPOFF */
+             reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_LO12S2 : BFD_RELOC_NDS32_TLS_IE_LO12S2;
+             break;
+           default:    /* No suffix */
+             reloc = BFD_RELOC_NDS32_LO12S2;
+             break;
+           }
+       }
       else if (fld->bitsize == 15 && fld->shift == 3)
        reloc = BFD_RELOC_NDS32_LO12S3;         /* [ls]di */
       else if (fld->bitsize == 12 && fld->shift == 2)
-       reloc = BFD_RELOC_NDS32_LO12S2;         /* f[ls][sd]i */
+       reloc = BFD_RELOC_NDS32_LO12S2_SP;      /* f[ls][sd]i */
 
-      fix_new_exp (frag_now, out - frag_now->fr_literal,
-                  insn->opcode->isize, insn->info, 0 /* pcrel */,
-                  reloc);
+      fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize,
+                         insn->info, 0 /* pcrel */, reloc);
     }
   else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4
           && (insn->attr & NASM_ATTR_PCREL))
@@ -4127,9 +4902,8 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld,
       else
        abort ();
 
-      fix_new_exp (frag_now, out - frag_now->fr_literal,
-                  insn->opcode->isize, insn->info, 1 /* pcrel */,
-                  reloc);
+      fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize,
+                  insn->info, 1 /* pcrel */, reloc);
     }
   else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4
           && (insn->attr & NASM_ATTR_GPREL))
@@ -4142,489 +4916,1405 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld,
       else if (fld->bitsize == 17 && fld->shift == 2)
        reloc = BFD_RELOC_NDS32_SDA17S2;
       else
-       abort ();
-
-      fix_new_exp (frag_now, out - frag_now->fr_literal,
-                  insn->opcode->isize, insn->info, 0 /* pcrel */,
-                  reloc);
+       abort ();
+
+      fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize,
+                  insn->info, 0 /* pcrel */, reloc);
+      /* Insert INSN16 for converting fp_as_gp.  */
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = abs_section_sym;
+      exp.X_add_number = 0;
+      if (in_omit_fp && reloc == BFD_RELOC_NDS32_SDA17S2)
+       fix_new_exp (fragP, out - fragP->fr_literal,
+                    insn->opcode->isize, &exp, 0 /* pcrel */,
+                    BFD_RELOC_NDS32_INSN16);
+    }
+  else if (fld && fld->bitpos == 0 && insn->opcode->isize == 2
+          && (insn->attr & NASM_ATTR_PCREL))
+    {
+      /* Relocation for 16-bit branch instructions.  */
+      if (fld->bitsize == 8 && fld->shift == 1)
+       reloc = BFD_RELOC_NDS32_9_PCREL;
+      else
+       abort ();
+
+      fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize,
+                  insn->info, 1 /* pcrel */, reloc);
+    }
+  else if (fld)
+    as_bad (_("Don't know how to handle this field. %s"), str);
+
+  return fixP;
+}
+
+/* Build instruction pattern to relax.  There are two type group pattern
+   including pseudo instruction and relax hint.  */
+
+static void
+nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out,
+                               struct nds32_asm_insn *insn, fragS *fragP,
+                               const struct nds32_field *fld,
+                               bfd_boolean pseudo_hint)
+{
+  struct nds32_relocs_pattern *reloc_ptr;
+  struct nds32_relocs_group *group;
+  symbolS *sym = NULL;
+
+  /* The expression may be used uninitialized.  */
+  if (fld)
+    sym = pexp->X_add_symbol;
+
+  if (pseudo_hint)
+    {
+      /* We cannot know how many instructions will be expanded for
+        the pseudo instruction here.  The first expanded instruction fills
+        the memory created by relax_hint.  The follower will created and link
+        here.  */
+      group = nds32_relax_hint_current;
+      while (group)
+       {
+         if (group->pattern->opcode == NULL)
+           nds32_elf_save_pseudo_pattern (fixP, insn, out, sym,
+                                          group->pattern, fragP);
+         else
+           {
+             group->pattern->next =
+               nds32_elf_save_pseudo_pattern (fixP, insn, out, sym,
+                                              NULL, fragP);
+             group->pattern = group->pattern->next;
+           }
+         group = group->next;
+       }
+    }
+  else if (pseudo_opcode)
+    {
+      /* Save instruction relation for pseudo instruction expanding pattern.  */
+      reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, insn, out, sym,
+                                                NULL, fragP);
+      if (!relocs_list)
+       relocs_list = reloc_ptr;
+      else
+       {
+         struct nds32_relocs_pattern *temp = relocs_list;
+         while (temp->next)
+           temp = temp->next;
+         temp->next = reloc_ptr;
+       }
+    }
+  else if (nds32_relax_hint_current)
+    {
+      /* Save instruction relation by relax hint.  */
+      group = nds32_relax_hint_current;
+      while (group)
+       {
+         nds32_elf_save_pseudo_pattern (fixP, insn, out, sym,
+                                        group->pattern, fragP);
+         group = group->next;
+         free (nds32_relax_hint_current);
+         nds32_relax_hint_current = group;
+       }
+    }
+
+  /* Set relaxing false only for relax_hint trigger it.  */
+  if (!pseudo_opcode)
+    relaxing = FALSE;
+}
+
+#define N32_MEM_EXT(insn) ((N32_OP6_MEM << 25) | insn)
+
+/* Relax pattern for link time relaxation.  */
+/* Relaxation types only! relocation types are not necessary.  */
+/* Refer to nds32_elf_record_fixup_exp ().  */
+
+static struct nds32_relax_hint_table relax_ls_table[] =
+{
+  {
+    /* LA and Floating LSI.  */
+    .main_type = NDS32_RELAX_HINT_LA_FLSI,
+    .relax_code_size = 12,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (LBI),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR},
+       {4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_LSI},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* Load Address / Load-Store (LALS).  */
+    .main_type = NDS32_RELAX_HINT_LALS,
+    .relax_code_size = 12,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (LBI),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {8, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* B(AL) symbol@PLT  */
+    .main_type = NDS32_RELAX_HINT_LA_PLT,
+    .relax_code_size = 16,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (ALU1),
+       OP6 (JREG),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR},
+       {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PLT_GOT_SUFF},
+       {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* LA (@GOT).  */
+    .main_type = NDS32_RELAX_HINT_LA_GOT,
+    .relax_code_size = 12,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (MEM),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOT_SUFF},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* LA (@GOTOFF).  */
+    .main_type = NDS32_RELAX_HINT_LA_GOTOFF,
+    .relax_code_size = 16,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (ALU1),
+       OP6 (MEM),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF},
+       {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* TLS LE LS|LA */
+    .main_type = NDS32_RELAX_HINT_TLS_LE_LS,
+    .relax_code_size = 16,
+    .relax_code_seq =
+      {
+       OP6(SETHI),
+       OP6(ORI),
+       OP6(MEM),
+       OP6(ALU1),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR_MULTIPLE, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_LE_LS},
+       {12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {12, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_LE_ADD},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* TLS IE LA */
+    .main_type = NDS32_RELAX_HINT_TLS_IE_LA,
+    .relax_code_size = 8,
+    .relax_code_seq =
+      {
+       OP6(SETHI),
+       OP6(LBI),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* TLS IEGP LA */
+    .main_type = NDS32_RELAX_HINT_TLS_IEGP_LA,
+    .relax_code_size = 12,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (MEM),
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR_PATTERN, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_IEGP_LW},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    /* TLS DESC LS:  */
+    .main_type = NDS32_RELAX_HINT_TLS_DESC_LS,
+    .relax_code_size = 24,
+    .relax_code_seq =
+      {
+       OP6 (SETHI),
+       OP6 (ORI),
+       OP6 (ALU1),
+       OP6 (LBI),      /* load argument */
+       OP6 (JREG),
+       OP6 (MEM),      /* load/store variable or load argument */
+      },
+    .relax_fixup =
+      {
+       {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+       {4, 4, NDS32_HINT | NDS32_PTR_PATTERN, BFD_RELOC_NDS32_PTR},
+       {8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED},
+       {8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_ADD},
+       {12, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_FUNC},
+       {16, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_CALL},
+       {20, 4, NDS32_HINT | NDS32_SYM_DESC_MEM, BFD_RELOC_NDS32_TLS_DESC_MEM},
+       {0, 0, 0, 0}
+      }
+  },
+  {
+    .main_type = 0,
+    .relax_code_seq = {0},
+    .relax_fixup = {{0, 0 , 0, 0}}
+  }
+};
+
+/* Since sethi loadstore relocation has to using next instruction to determine
+   elimination itself or not, we have to return the next instruction range.  */
+
+static int
+nds32_elf_sethi_range (struct nds32_relocs_pattern *pattern)
+{
+  int range = 0;
+  while (pattern)
+    {
+      switch (pattern->opcode->value)
+       {
+       case INSN_LBI:
+       case INSN_SBI:
+       case INSN_LBSI:
+       case N32_MEM_EXT (N32_MEM_LB):
+       case N32_MEM_EXT (N32_MEM_LBS):
+       case N32_MEM_EXT (N32_MEM_SB):
+         range = NDS32_LOADSTORE_BYTE;
+         break;
+       case INSN_LHI:
+       case INSN_SHI:
+       case INSN_LHSI:
+       case N32_MEM_EXT (N32_MEM_LH):
+       case N32_MEM_EXT (N32_MEM_LHS):
+       case N32_MEM_EXT (N32_MEM_SH):
+         range = NDS32_LOADSTORE_HALF;
+         break;
+       case INSN_LWI:
+       case INSN_SWI:
+       case N32_MEM_EXT (N32_MEM_LW):
+       case N32_MEM_EXT (N32_MEM_SW):
+         range = NDS32_LOADSTORE_WORD;
+         break;
+       case INSN_FLSI:
+       case INSN_FSSI:
+         range = NDS32_LOADSTORE_FLOAT_S;
+         break;
+       case INSN_FLDI:
+       case INSN_FSDI:
+         range = NDS32_LOADSTORE_FLOAT_D;
+         break;
+       case INSN_ORI:
+         range = NDS32_LOADSTORE_IMM;
+         break;
+       default:
+         range = NDS32_LOADSTORE_NONE;
+         break;
+       }
+      if (range != NDS32_LOADSTORE_NONE)
+       break;
+      pattern = pattern->next;
+    }
+  return range;
+}
+
+/* The args means: instruction size, the 1st instruction is converted to 16 or
+   not, optimize option, 16 bit instruction is enable.  */
+
+#define SET_ADDEND(size, convertible, optimize, insn16_on) \
+  (((size) & 0xff) | ((convertible) ? 1 << 31 : 0) \
+   | ((optimize) ? 1<< 30 : 0) | (insn16_on ? 1 << 29 : 0))
+#define MAC_COMBO (E_NDS32_HAS_FPU_MAC_INST|E_NDS32_HAS_MAC_DX_INST)
+
+static void
+nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn)
+{
+  static int skip_flags = NASM_ATTR_FPU_FMA
+    | NASM_ATTR_BRANCH | NASM_ATTR_SATURATION_EXT
+    | NASM_ATTR_GPREL | NASM_ATTR_DXREG
+    | NASM_ATTR_ISA_V1 | NASM_ATTR_ISA_V2
+    | NASM_ATTR_ISA_V3 | NASM_ATTR_ISA_V3M
+    | NASM_ATTR_PCREL;
+
+  int new_flags = insn->opcode->attr & ~skip_flags;
+  while (new_flags)
+    {
+      int next = 1 << (ffs (new_flags) - 1);
+      new_flags &= ~next;
+      switch (next)
+       {
+       case NASM_ATTR_PERF_EXT:
+         {
+           if (nds32_perf_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_EXT_INST;
+               skip_flags |= NASM_ATTR_PERF_EXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling performance "
+                       "extension"), insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_PERF2_EXT:
+         {
+           if (nds32_perf_ext2)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_EXT2_INST;
+               skip_flags |= NASM_ATTR_PERF2_EXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling performance "
+                       "extension II"), insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_AUDIO_ISAEXT:
+         {
+           if (nds32_audio_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_AUDIO_INST;
+               skip_flags |= NASM_ATTR_AUDIO_ISAEXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling AUDIO extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_STR_EXT:
+         {
+           if (nds32_string_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_STRING_INST;
+               skip_flags |= NASM_ATTR_STR_EXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling STRING extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_DIV:
+         {
+           if (insn->opcode->attr & NASM_ATTR_DXREG)
+             {
+               if (nds32_div && nds32_dx_regs)
+                 {
+                   nds32_elf_flags |= E_NDS32_HAS_DIV_DX_INST;
+                   skip_flags |= NASM_ATTR_DIV;
+                 }
+               else
+                 as_bad (_("instruction %s requires enabling DIV & DX_REGS "
+                           "extension"), insn->opcode->opcode);
+             }
+         }
+         break;
+       case NASM_ATTR_FPU:
+         {
+           if (nds32_fpu_sp_ext || nds32_fpu_dp_ext)
+             {
+               if (!(nds32_elf_flags
+                     & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST)))
+                 nds32_fpu_com = 1;
+               skip_flags |= NASM_ATTR_FPU;
+             }
+           else
+             as_bad (_("instruction %s requires enabling FPU extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_FPU_SP_EXT:
+         {
+           if (nds32_fpu_sp_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_FPU_INST;
+               skip_flags |= NASM_ATTR_FPU_SP_EXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling FPU_SP extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_FPU_DP_EXT:
+         {
+           if (nds32_fpu_dp_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST;
+               skip_flags |= NASM_ATTR_FPU_DP_EXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling FPU_DP extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_MAC:
+         {
+           if (insn->opcode->attr & NASM_ATTR_FPU_SP_EXT)
+             {
+               if (nds32_fpu_sp_ext && nds32_mac)
+                 nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST;
+               else
+                 as_bad (_("instruction %s requires enabling FPU_MAC "
+                           "extension"), insn->opcode->opcode);
+             }
+           else if (insn->opcode->attr & NASM_ATTR_FPU_DP_EXT)
+             {
+               if (nds32_fpu_dp_ext && nds32_mac)
+                 nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST;
+               else
+                 as_bad (_("instruction %s requires enabling FPU_MAC "
+                           "extension"), insn->opcode->opcode);
+             }
+           else if (insn->opcode->attr & NASM_ATTR_DXREG)
+             {
+               if (nds32_dx_regs && nds32_mac)
+                 nds32_elf_flags |= E_NDS32_HAS_MAC_DX_INST;
+               else
+                 as_bad (_("instruction %s requires enabling DX_REGS "
+                           "extension"), insn->opcode->opcode);
+             }
+
+           if (MAC_COMBO == (MAC_COMBO & nds32_elf_flags))
+             skip_flags |= NASM_ATTR_MAC;
+         }
+         break;
+       case NASM_ATTR_DSP_ISAEXT:
+         {
+           if (nds32_dsp_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_DSP_INST;
+               skip_flags |= NASM_ATTR_DSP_ISAEXT;
+             }
+           else
+             as_bad (_("instruction %s requires enabling dsp extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       case NASM_ATTR_ZOL:
+         {
+           if (nds32_zol_ext)
+             {
+               nds32_elf_flags |= E_NDS32_HAS_ZOL;
+               skip_flags |= NASM_ATTR_ZOL;
+             }
+           else
+             as_bad (_("instruction %s requires enabling zol extension"),
+                     insn->opcode->opcode);
+         }
+         break;
+       default:
+         as_bad (_("internal error: unknown instruction attribute: 0x%08x"),
+                 next);
+       }
+    }
+}
+
+/* Flag for analysis relaxation type.  */
+
+enum nds32_insn_type
+{
+  N32_RELAX_SETHI = 1,
+  N32_RELAX_BR = (1 << 1),
+  N32_RELAX_LSI = (1 << 2),
+  N32_RELAX_JUMP = (1 << 3),
+  N32_RELAX_CALL = (1 << 4),
+  N32_RELAX_ORI = (1 << 5),
+  N32_RELAX_MEM = (1 << 6),
+  N32_RELAX_MOVI = (1 << 7),
+  N32_RELAX_ALU1 = (1 << 8),
+  N32_RELAX_16BIT = (1 << 9),
+};
+
+struct nds32_hint_map
+{
+  /* the preamble relocation */
+  bfd_reloc_code_real_type hi_type;
+  /* mnemonic */
+  const char *opc;
+  /* relax pattern ID */
+  enum nds32_relax_hint_type hint_type;
+  /* range */
+  enum nds32_br_range range;
+  /* pattern character flags */
+  enum nds32_insn_type insn_list;
+  /* optional pattern character flags */
+  enum nds32_insn_type option_list;
+};
+
+/* Table to match instructions with hint and relax pattern.  */
+
+static struct nds32_hint_map hint_map [] =
+{
+  {
+    /* LONGCALL4.  */
+    BFD_RELOC_NDS32_HI20,
+    "jal",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL,
+    0,
+  },
+  {
+    /* LONGCALL5.  */
+    _dummy_first_bfd_reloc_code_real,
+    "bgezal",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_S16M,
+    N32_RELAX_BR | N32_RELAX_CALL,
+    0,
+  },
+  {
+    /* LONGCALL6.  */
+    BFD_RELOC_NDS32_HI20,
+    "bgezal",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_U4G,
+    N32_RELAX_BR | N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL,
+    0,
+  },
+  {
+    /* LONGJUMP4.  */
+    BFD_RELOC_NDS32_HI20,
+    "j",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_JUMP,
+    0,
+  },
+  {
+    /* LONGJUMP5.  */
+    /* There is two kinds of variation of LONGJUMP5.  One of them
+       generate EMPTY relocation for converted INSN16 if needed.
+       But we don't distinguish them here.  */
+    _dummy_first_bfd_reloc_code_real,
+    "beq",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_S16M,
+    N32_RELAX_BR | N32_RELAX_JUMP,
+    0,
+  },
+  {
+    /* LONGJUMP6.  */
+    BFD_RELOC_NDS32_HI20,
+    "beq",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_BR | N32_RELAX_JUMP,
+    0,
+  },
+  {
+    /* LONGJUMP7.  */
+    _dummy_first_bfd_reloc_code_real,
+    "beqc",
+    NDS32_RELAX_HINT_NONE,
+    BR_RANGE_S16K,
+    N32_RELAX_MOVI | N32_RELAX_BR,
+    0,
+  },
+  {
+    /* LONGCALL (BAL|JR|LA symbol@PLT).  */
+    BFD_RELOC_NDS32_PLT_GOTREL_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LA_PLT,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI,
+    N32_RELAX_ALU1 | N32_RELAX_CALL | N32_RELAX_JUMP,
+  },
+  /* relative issue: #12566 */
+  {
+    /* LA and Floating LSI.  */
+    BFD_RELOC_NDS32_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LA_FLSI,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_LSI,
+    0,
+  },
+  /* relative issue: #11685 #11602 */
+  {
+    /* load address / load-store (LALS).  */
+    BFD_RELOC_NDS32_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LALS,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI,
+    N32_RELAX_ORI | N32_RELAX_LSI,
+  },
+  {
+    /* setup $GP (_GLOBAL_OFFSET_TABLE_)  */
+    BFD_RELOC_NDS32_GOTPC_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LALS,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI,
+    0,
+  },
+  {
+    /* GOT LA/LS (symbol@GOT)  */
+    BFD_RELOC_NDS32_GOT_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LA_GOT,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI,
+    N32_RELAX_MEM,
+  },
+  {
+    /* GOTOFF LA/LS (symbol@GOTOFF)  */
+    BFD_RELOC_NDS32_GOTOFF_HI20,
+    NULL,
+    NDS32_RELAX_HINT_LA_GOTOFF,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI,
+    N32_RELAX_ALU1  | N32_RELAX_MEM, /* | N32_RELAX_LSI, */
+  },
+  {
+    /* TLS LE LA|LS (@TPOFF)  */
+    BFD_RELOC_NDS32_TLS_LE_HI20,
+    NULL,
+    NDS32_RELAX_HINT_TLS_LE_LS,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI,
+    N32_RELAX_ALU1 | N32_RELAX_MEM,
+  },
+  {
+    /* TLS IE LA */
+    BFD_RELOC_NDS32_TLS_IE_HI20,
+    NULL,
+    NDS32_RELAX_HINT_TLS_IE_LA,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_LSI,
+    0,
+  },
+{
+    /* TLS IE LS */
+    BFD_RELOC_NDS32_TLS_IE_HI20,
+    NULL,
+    NDS32_RELAX_HINT_TLS_IE_LS,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_LSI | N32_RELAX_MEM,
+    0,
+  },
+  {
+    /* TLS IEGP LA */
+    BFD_RELOC_NDS32_TLS_IEGP_HI20,
+    NULL,
+    NDS32_RELAX_HINT_TLS_IEGP_LA,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_MEM,
+    0,
+  },
+  {
+    /* TLS DESC LS */
+    BFD_RELOC_NDS32_TLS_DESC_HI20,
+    NULL,
+    NDS32_RELAX_HINT_TLS_DESC_LS,
+    BR_RANGE_U4G,
+    N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_ALU1 | N32_RELAX_CALL,
+    N32_RELAX_LSI | N32_RELAX_MEM,
+  },
+  /* last one */
+  {0, NULL, 0, 0 ,0, 0}
+};
+
+/* Find the relaxation pattern according to instructions.  */
+
+static bfd_boolean
+nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern,
+                       struct nds32_relax_hint_table *hint_info)
+{
+  unsigned int opcode, seq_size;
+  enum nds32_br_range range;
+  struct nds32_relocs_pattern *pattern, *hi_pattern = NULL;
+  const char *opc = NULL;
+  relax_info_t *relax_info = NULL;
+  nds32_relax_fixup_info_t *fixup_info, *hint_fixup;
+  enum nds32_relax_hint_type hint_type = NDS32_RELAX_HINT_NONE;
+  struct nds32_relax_hint_table *table_ptr;
+  uint32_t *code_seq, *hint_code;
+  enum nds32_insn_type relax_type = 0;
+  struct nds32_hint_map *map_ptr = hint_map;
+  unsigned int i;
+  const char *check_insn[] =
+    { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" };
+
+  /* TODO: PLT GOT.  */
+  /* Traverse all pattern instruction and set flag.  */
+  pattern = relocs_pattern;
+  while (pattern)
+    {
+      if (pattern->opcode->isize == 4)
+       {
+         /* 4 byte instruction.  */
+         opcode = N32_OP6 (pattern->opcode->value);
+         switch (opcode)
+           {
+           case N32_OP6_SETHI:
+             hi_pattern = pattern;
+             relax_type |= N32_RELAX_SETHI;
+             break;
+           case N32_OP6_MEM:
+             relax_type |= N32_RELAX_MEM;
+             break;
+           case N32_OP6_ALU1:
+             relax_type |= N32_RELAX_ALU1;
+             break;
+           case N32_OP6_ORI:
+             relax_type |= N32_RELAX_ORI;
+             break;
+           case N32_OP6_BR1:
+           case N32_OP6_BR2:
+           case N32_OP6_BR3:
+             relax_type |= N32_RELAX_BR;
+             break;
+           case N32_OP6_MOVI:
+             relax_type |= N32_RELAX_MOVI;
+             break;
+           case N32_OP6_LBI:
+           case N32_OP6_SBI:
+           case N32_OP6_LBSI:
+           case N32_OP6_LHI:
+           case N32_OP6_SHI:
+           case N32_OP6_LHSI:
+           case N32_OP6_LWI:
+           case N32_OP6_SWI:
+           case N32_OP6_LWC:
+           case N32_OP6_SWC:
+           case N32_OP6_LDC:
+           case N32_OP6_SDC:
+             relax_type |= N32_RELAX_LSI;
+             break;
+           case N32_OP6_JREG:
+             if (__GF (pattern->opcode->value, 0, 1) == 1)
+               relax_type |= N32_RELAX_CALL;
+             else
+               relax_type |= N32_RELAX_JUMP;
+             break;
+           case N32_OP6_JI:
+             if (__GF (pattern->opcode->value, 24, 1) == 1)
+               relax_type |= N32_RELAX_CALL;
+             else
+               relax_type |= N32_RELAX_JUMP;
+             break;
+           default:
+             as_warn (_("relax hint unrecognized instruction: line %d."),
+                      pattern->frag->fr_line);
+             return FALSE;
+           }
+       }
+      else
+       {
+         /* 2 byte instruction.  Compare by opcode name because
+            the opcode of 2byte instruction is not regular.  */
+         int is_matched = 0;
+         for (i = 0; i < ARRAY_SIZE (check_insn); i++)
+           {
+             if (strcmp (pattern->opcode->opcode, check_insn[i]) == 0)
+               {
+                 relax_type |= N32_RELAX_BR;
+                 is_matched += 1;
+                 break;
+               }
+           }
+         if (!is_matched)
+           relax_type |= N32_RELAX_16BIT;
+       }
+      pattern = pattern->next;
     }
-  else if (fld && fld->bitpos == 0 && insn->opcode->isize == 2
-          && (insn->attr & NASM_ATTR_PCREL))
+
+  /* Analysis instruction flag to choose relaxation table.  */
+  while (map_ptr->insn_list != 0)
     {
-      /* Relocation for 16-bit branch instructions.  */
-      if (fld->bitsize == 8 && fld->shift == 1)
-       reloc = BFD_RELOC_NDS32_9_PCREL;
-      else
-       abort ();
+      struct nds32_hint_map *hint = map_ptr++;
+      enum nds32_insn_type must = hint->insn_list;
+      enum nds32_insn_type optional = hint->option_list;
+      enum nds32_insn_type extra;
+
+      if (must != (must & relax_type))
+       continue;
+
+      extra = relax_type ^ must;
+      if (extra != (extra & optional))
+       continue;
 
-      fix_new_exp (frag_now, out - frag_now->fr_literal,
-                  insn->opcode->isize, insn->info, 1 /* pcrel */,
-                  reloc);
+      if (!hi_pattern
+         || (hi_pattern->fixP
+             && hi_pattern->fixP->fx_r_type == hint->hi_type))
+       {
+         opc = hint->opc;
+         hint_type = hint->hint_type;
+         range = hint->range;
+         map_ptr = hint;
+         break;
+       }
     }
-  else if (fld)
+
+  if (map_ptr->insn_list == 0)
     {
-      as_bad (_("Don't know how to handle this field. %s"),
-             str);
+      if (!nds32_pic)
+       as_warn (_("Can not find match relax hint.  Line: %d"),
+                relocs_pattern->frag->fr_line);
+      return FALSE;
     }
 
-  if (pseudo_opcode)
+  /* Get the match table.  */
+  if (opc)
     {
-      /* Save instruction relation for pseudo instruction expanding pattern.  */
-      reloc_ptr = nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, NULL);
-      if (!relocs_list)
-       relocs_list = reloc_ptr;
-      else
+      /* Branch relax pattern.  */
+      relax_info = hash_find (nds32_relax_info_hash, opc);
+      if (!relax_info)
+       return FALSE;
+      fixup_info = relax_info->relax_fixup[range];
+      code_seq = relax_info->relax_code_seq[range];
+      seq_size = relax_info->relax_code_size[range];
+    }
+  else if (hint_type)
+    {
+      /* Load-store relax pattern.  */
+      table_ptr = relax_ls_table;
+      while (table_ptr->main_type != 0)
        {
-         struct nds32_relocs_pattern *temp = relocs_list;
-         while (temp->next)
-           temp = temp->next;
-         temp->next = reloc_ptr;
+         if (table_ptr->main_type == hint_type)
+           {
+             fixup_info = table_ptr->relax_fixup;
+             code_seq = table_ptr->relax_code_seq;
+             seq_size = table_ptr->relax_code_size;
+             break;
+           }
+         table_ptr++;
        }
+      if (table_ptr->main_type == 0)
+       return FALSE;
     }
-  else if (nds32_relax_hint_current)
+  else
+    return FALSE;
+
+  hint_fixup = hint_info->relax_fixup;
+  hint_code = hint_info->relax_code_seq;
+  hint_info->relax_code_size = seq_size;
+
+  while (fixup_info->size != 0)
     {
-      /* Save instruction relation by relax hint.  */
-      group = nds32_relax_hint_current;
-      while (group)
+      if (fixup_info->ramp & NDS32_HINT)
        {
-         nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, group->pattern);
-         group = group->next;
-         free (nds32_relax_hint_current);
-         nds32_relax_hint_current = group;
+         memcpy (hint_fixup, fixup_info, sizeof (nds32_relax_fixup_info_t));
+         hint_fixup++;
        }
+      fixup_info++;
     }
+  /* Clear final relocation.  */
+  memset (hint_fixup, 0, sizeof (nds32_relax_fixup_info_t));
+  /* Copy code sequence.  */
+  memcpy (hint_code, code_seq, seq_size);
+  return TRUE;
 }
 
-#define N32_MEM_EXT(insn) (N32_OP6_MEM<< 25| insn)
+/* Because there are a lot of variant of load-store, check
+   all these type here.  */
 
-/* Relax pattern for link time relaxation.  */
+#define CLEAN_REG(insn) ((insn) & 0xfe0003ff)
+#define GET_OPCODE(insn) ((insn) & 0xfe000000)
 
-static struct nds32_relocation_map relocation_table[] =
+static bfd_boolean
+nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq)
 {
-    {
-      /* Load-Store: sethi lwi+
-        Load address: sethi ori  */
-      BFD_RELOC_NDS32_HI20,            /* main_type */
-      {
-       {
-         {BFD_RELOC_NDS32_LOADSTORE, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_INSN16, 0},
-         {0, 0}
-       },
-       {
-         {0, 0}
-       }
-      },
-    },
-    {
-      /* Load-Store: sethi ori lwi+
-        Load address: sethi ori add  */
-      BFD_RELOC_NDS32_GOTOFF_HI20,     /* main_type */
-      {
-       {
-         {BFD_RELOC_NDS32_LOADSTORE, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_INSN16, 0},
-         {BFD_RELOC_NDS32_PTR, 0},
-         {BFD_RELOC_NDS32_PTR_COUNT, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_GOTOFF_SUFF, 0},
-         {BFD_RELOC_NDS32_PTR_RESOLVED, 0},
-         {0, 0}
-       },
-       {
-         {0, 0}
-       }
-      },
-    },
-    {
-      /* Load-Store: sethi ori lw lwi+
-        Load address: sethi ori lw [addi|add]  */
-      BFD_RELOC_NDS32_GOT_HI20,                /* main_type */
-      {
-       {
-         {BFD_RELOC_NDS32_LOADSTORE, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_INSN16, 0},
-         /* For pseudo la and l.w.
-            Lw is the next one instruction.  */
-         {BFD_RELOC_NDS32_PTR, N32_MEM_EXT (N32_MEM_LW)},
-         {BFD_RELOC_NDS32_PTR_COUNT, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_GOT_SUFF, N32_MEM_EXT (N32_MEM_LW)},
-         {BFD_RELOC_NDS32_PTR_RESOLVED, N32_MEM_EXT (N32_MEM_LW)},
-         {0, 0}
-       },
-       {
-         {0, 0},
-       },
-      },
-    },
-    {
-      BFD_RELOC_NDS32_PLT_GOTREL_HI20, /* main_type */
-      {
-       {
-         {BFD_RELOC_NDS32_LOADSTORE, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_INSN16, 0},
-         /* For pseudo bal.
-            jral is the target instruction.  */
-         {BFD_RELOC_NDS32_PTR, INSN_JRAL},
-         {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))},
-         {BFD_RELOC_NDS32_PTR_COUNT, 0},
-         {0, 0}
-       },
-       {
-         /* For pseudo bal.
-            jral is the target instruction.  */
-         {BFD_RELOC_NDS32_PTR, INSN_JRAL},
-         {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))},
-         {BFD_RELOC_NDS32_PTR_COUNT, 0},
-         {0, 0}
-       },
-       {
-         {BFD_RELOC_NDS32_PLT_GOT_SUFF, 0},
-         {BFD_RELOC_NDS32_PTR_RESOLVED, 0},
-         {0, 0}
-       },
-       {
-         {0, 0},
-       },
-      },
-    },
-    {
-      0,
-      {
-        {
-          {0, 0},
-       },
-      },
-    }
-};
+  const char *check_insn[] =
+    { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8", "jral5" };
+  uint32_t insn = opcode->value;
+  unsigned int i;
 
-/* Since sethi loadstore relocation has to using next instruction to determine
-   elimination itself or not, we have to return the next instruction range.  */
+  insn = CLEAN_REG (opcode->value);
+  if (insn == seq)
+    return TRUE;
 
-static int
-nds32_elf_sethi_range (struct nds32_relocs_pattern *relocs_ptr)
-{
-  unsigned int insn = relocs_ptr->insn;
-  int range;
-  switch (insn)
-    {
-    case INSN_LBI:
-    case INSN_SBI:
-    case INSN_LBSI:
-    case N32_MEM_EXT (N32_MEM_LB):
-    case N32_MEM_EXT (N32_MEM_LBS):
-    case N32_MEM_EXT (N32_MEM_SB):
-      range = 0x01;
+  switch (seq)
+    {
+    case OP6 (LBI):
+      /* In relocation_table, it regards instruction LBI as representation
+        of all the NDS32_RELAX_HINT_LS pattern.  */
+      if (insn == OP6 (LBI) || insn == OP6 (SBI) || insn == OP6 (LBSI)
+         || insn == OP6 (LHI) || insn == OP6 (SHI) || insn == OP6 (LHSI)
+         || insn == OP6 (LWI) || insn == OP6 (SWI)
+         || insn == OP6 (LWC) || insn == OP6 (SWC)
+         || insn == OP6 (LDC) || insn == OP6 (SDC))
+       return TRUE;
       break;
-    case INSN_LHI:
-    case INSN_SHI:
-    case INSN_LHSI:
-    case N32_MEM_EXT (N32_MEM_LH):
-    case N32_MEM_EXT (N32_MEM_LHS):
-    case N32_MEM_EXT (N32_MEM_SH):
-      range = 0x02;
+    case OP6 (BR2):
+      /* This is for LONGCALL5 and LONGCALL6.  */
+      if (insn == OP6 (BR2))
+       return TRUE;
       break;
-    case INSN_LWI:
-    case INSN_SWI:
-    case N32_MEM_EXT (N32_MEM_LW):
-    case N32_MEM_EXT (N32_MEM_SW):
-      range = 0x04;
+    case OP6 (BR1):
+      /* This is for LONGJUMP5 and LONGJUMP6.  */
+      if (opcode->isize == 4
+         && (insn == OP6 (BR1) || insn == OP6 (BR2) || insn == OP6 (BR3)))
+       return TRUE;
+      else if (opcode->isize == 2)
+       {
+         for (i = 0; i < ARRAY_SIZE (check_insn); i++)
+           if (strcmp (opcode->opcode, check_insn[i]) == 0)
+             return TRUE;
+       }
       break;
-    case INSN_FLSI:
-    case INSN_FSSI:
-      range = 0x08;
+    case OP6 (MOVI):
+      /* This is for LONGJUMP7.  */
+      if (opcode->isize == 2 && strcmp (opcode->opcode, "movi55") == 0)
+       return TRUE;
       break;
-    case INSN_FLDI:
-    case INSN_FSDI:
-      range = 0x10;
+    case OP6 (MEM):
+      if (OP6 (MEM) == GET_OPCODE (insn))
+       return TRUE;
       break;
-    case INSN_ORI:
-      range = 0x20;
+    case OP6 (JREG):
+      /* bit 24: N32_JI_JAL  */ /* feed me!  */
+      if ((insn & ~(N32_BIT (24))) == JREG (JRAL))
+       return TRUE;
       break;
     default:
-      range = 0x0;
-      break;
+      if (opcode->isize == 2)
+       {
+         for (i = 0; i < ARRAY_SIZE (check_insn); i++)
+           if (strcmp (opcode->opcode, check_insn[i]) == 0)
+             return TRUE;
+
+         if ((strcmp (opcode->opcode, "add5.pc") == 0) ||
+             (strcmp (opcode->opcode, "add45") == 0))
+           return TRUE;
+       }
     }
-  return range;
+  return FALSE;
 }
 
-/* The args means: instruction size, the 1st instruction is converted to 16 or
-   not, optimize option, 16 bit instruction is enable.  */
-#define SET_ADDEND( size, convertible, optimize, insn16_on ) \
-  (((size) & 0xff) | ((convertible) ? 1 << 31 : 0) \
-   | ((optimize) ? 1<< 30 : 0) | (insn16_on ? 1 << 29 : 0))
-
-/* Insert new fix.  */
+/* Append relax relocation for link time relaxing.  */
 
 static void
-nds32_elf_insert_relocation (struct nds32_relocs_pattern *pattern, unsigned int reloc,
-                            unsigned int insn_mask, symbolS *sym)
+nds32_elf_append_relax_relocs (const char *key, void *value)
 {
+  struct nds32_relocs_pattern *relocs_pattern =
+    (struct nds32_relocs_pattern *) value;
+  struct nds32_relocs_pattern *pattern_temp, *pattern_now;
+  symbolS *sym, *hi_sym = NULL;
   expressionS exp;
-  symbolS *sym_t;
-  struct nds32_relocs_pattern *pattern_t;
-  int range;
-  fragS *frag = pattern->frag;
-  char *out = pattern->where;
-  unsigned int size = pattern->size;
-  static int ptr_count = 0;
-
-  exp.X_op = O_symbol;
-  exp.X_add_symbol = abs_section_sym;
-  exp.X_add_number = 0;
-
-  switch (reloc)
-    {
-    case BFD_RELOC_NDS32_LOADSTORE:
-      /* To get the sethi match pattern.  */
-      range = nds32_elf_sethi_range (pattern->next);
-      exp.X_add_number = SET_ADDEND (4 /* size */, 0, optimize, enable_16bit);
-      exp.X_add_number |= ((range & 0x3f) << 8);
-      fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0 /* pcrel */, reloc);
-      break;
+  fragS *fragP;
+  segT seg_bak = now_seg;
+  frchainS *frchain_bak = frchain_now;
+  struct nds32_relax_hint_table hint_info;
+  nds32_relax_fixup_info_t *hint_fixup, *fixup_now;
+  size_t fixup_size;
+  offsetT branch_offset, hi_branch_offset = 0;
+  fixS *fixP;
+  int range, offset;
+  unsigned int ptr_offset, hint_count, relax_code_size, count = 0;
+  uint32_t *code_seq, code_insn;
+  char *where;
+  int pcrel;
 
-    case BFD_RELOC_NDS32_PTR:
-      pattern_t = pattern->next;
-      while (pattern_t)
-       {
-         if (insn_mask == 0 || pattern_t->insn == insn_mask)
-           {
-             sym_t = symbol_temp_new (pattern_t->seg,
-                                      pattern_t->where - pattern_t->frag->fr_literal,
-                                      pattern_t->frag);
-             exp.X_add_symbol = sym_t;
-             fix_new_exp (frag, out - frag->fr_literal, 0, &exp, 0 /* pcrel */, reloc);
-             ptr_count++;
-             break;
-           }
-         pattern_t = pattern_t->next;
-       }
-      break;
+  if (!relocs_pattern)
+    return;
 
-    case BFD_RELOC_NDS32_PTR_COUNT:
-      /* In current design, it only be referanced once.  */
-      if (ptr_count != 0)
-       {
-         exp.X_add_number = ptr_count;
-         fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc);
-       }
-      ptr_count = 0;
-      break;
+  if (!nds32_find_reloc_table (relocs_pattern, &hint_info))
+    return;
 
-    case BFD_RELOC_NDS32_GOTOFF_SUFF:
-    case BFD_RELOC_NDS32_GOT_SUFF:
-    case BFD_RELOC_NDS32_PLT_GOT_SUFF:
-      /* It has to record symbol.  */
-      if (insn_mask == 0 || pattern->insn == insn_mask)
+  /* Save symbol for some EMPTY relocation using.  */
+  pattern_now = relocs_pattern;
+  while (pattern_now)
+    {
+      if (pattern_now->opcode->value == OP6 (SETHI))
        {
-         exp.X_add_symbol = sym;
-         fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc);
+         hi_sym = pattern_now->sym;
+         hi_branch_offset = pattern_now->fixP->fx_offset;
+         break;
        }
-      break;
+      pattern_now = pattern_now->next;
+    }
 
-    case BFD_RELOC_NDS32_PTR_RESOLVED:
-    default:
-      if (insn_mask == 0 || pattern->insn == insn_mask)
+  /* Inserting fix up must specify now_seg or frchain_now.  */
+  now_seg = relocs_pattern->seg;
+  frchain_now = relocs_pattern->frchain;
+  fragP = relocs_pattern->frag;
+  branch_offset = fragP->fr_offset;
+
+  hint_fixup = hint_info.relax_fixup;
+  code_seq = hint_info.relax_code_seq;
+  relax_code_size = hint_info.relax_code_size;
+  pattern_now = relocs_pattern;
+
+#ifdef NDS32_LINUX_TOOLCHAIN
+  /* prepare group relocation ID (number).  */
+  long group_id = 0;
+  if (key)
+    {
+      /* convert .relax_hint key to number */
+      errno = 0;
+      group_id = strtol (key, NULL, 10);
+      if ((errno == ERANGE && (group_id == LONG_MAX || group_id == LONG_MIN))
+         || (errno != 0 && group_id == 0))
        {
-         fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc);
+         as_bad (_("Internal error: .relax_hint KEY is not a number!"));
+         goto restore;
        }
     }
-}
+#endif
 
-static void
-nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn)
-{
-  /* Set E_NDS32_HAS_EXT_INST.  */
-  if (insn->opcode->attr & NASM_ATTR_PERF_EXT)
-    {
-      if (nds32_perf_ext)
-       nds32_elf_flags |= E_NDS32_HAS_EXT_INST;
-      else
-       as_bad (_("instruction %s requires enabling performance extension"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_PERF2_EXT)
-    {
-      if (nds32_perf_ext2)
-       nds32_elf_flags |= E_NDS32_HAS_EXT2_INST;
-      else
-       as_bad (_("instruction %s requires enabling performance extension II"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_AUDIO_ISAEXT)
-    {
-      if (nds32_audio_ext)
-       nds32_elf_flags |= E_NDS32_HAS_AUDIO_INST;
-      else
-       as_bad (_("instruction %s requires enabling AUDIO extension"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_STR_EXT)
-    {
-      if (nds32_string_ext)
-       nds32_elf_flags |= E_NDS32_HAS_STRING_INST;
-      else
-       as_bad (_("instruction %s requires enabling STRING extension"),
-               insn->opcode->opcode);
-    }
-  else if ((insn->opcode->attr & NASM_ATTR_DIV)
-          && (insn->opcode->attr & NASM_ATTR_DXREG))
-    {
-      if (nds32_div && nds32_dx_regs)
-       nds32_elf_flags |= E_NDS32_HAS_DIV_DX_INST;
-      else
-       as_bad (_("instruction %s requires enabling DIV & DX_REGS extension"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_FPU)
+  /* Insert relaxation.  */
+  exp.X_op = O_symbol;
+
+  /* For each instruction in the hint group.  */
+  while (pattern_now)
     {
-      if (nds32_fpu_sp_ext || nds32_fpu_dp_ext)
+      if (count >= relax_code_size / 4)
+       count = 0;
+
+      /* Choose the match fixup by instruction.  */
+      code_insn = CLEAN_REG (*(code_seq + count));
+      if (!nds32_match_hint_insn (pattern_now->opcode, code_insn))
        {
-         if (!(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST)))
-           nds32_fpu_com = 1;
+         /* Try search from head again */
+         count = 0;
+         code_insn = CLEAN_REG (*(code_seq + count));
+
+         while (!nds32_match_hint_insn (pattern_now->opcode, code_insn))
+           {
+             count++;
+             if (count >= relax_code_size / 4)
+               {
+                 as_bad (_("Internal error: Relax hint (%s) error. %s: %s (%x)"),
+                         key,
+                         now_seg->name,
+                         pattern_now->opcode->opcode,
+                         pattern_now->opcode->value);
+                 goto restore;
+               }
+             code_insn = CLEAN_REG (*(code_seq + count));
+           }
        }
-      else
-       as_bad (_("instruction %s requires enabling FPU extension"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_FPU_SP_EXT)
-    {
-      if (nds32_fpu_sp_ext)
-       nds32_elf_flags |= E_NDS32_HAS_FPU_INST;
-      else
-       as_bad (_("instruction %s requires enabling FPU_SP extension"),
-               insn->opcode->opcode);
-    }
-  else if ((insn->opcode->attr & NASM_ATTR_FPU_SP_EXT)
-          && (insn->opcode->attr & NASM_ATTR_MAC))
-    {
-      if (nds32_fpu_sp_ext && nds32_mac)
+      fragP = pattern_now->frag;
+      sym = pattern_now->sym;
+      branch_offset = fragP->fr_offset;
+      offset = count * 4;
+      where = pattern_now->where;
+      /* Find the instruction map fix.  */
+      fixup_now = hint_fixup;
+      while (fixup_now->offset != offset)
        {
-         nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST;
-         nds32_elf_flags |= E_NDS32_HAS_FPU_INST;
+         fixup_now++;
+         if (fixup_now->size == 0)
+           break;
        }
-      else
-       as_bad (_("instruction %s requires enabling FPU_MAC extension"),
-               insn->opcode->opcode);
-    }
-  else if (insn->opcode->attr & NASM_ATTR_FPU_DP_EXT)
-    {
-      if (nds32_fpu_dp_ext)
-       nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST;
-      else
-       as_bad (_("instruction %s requires enabling FPU_DP extension"),
-               insn->opcode->opcode);
-    }
-  else if ((insn->opcode->attr & NASM_ATTR_FPU_DP_EXT)
-          && (insn->opcode->attr & NASM_ATTR_MAC))
-    {
-      if (nds32_fpu_dp_ext && nds32_mac)
+      /* This element is without relaxation relocation.  */
+      if (fixup_now->size == 0)
        {
-         nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST;
-         nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST;
+         pattern_now = pattern_now->next;
+         continue;
        }
-      else
-       as_bad (_("instruction %s requires enabling FPU_MAC extension"),
-               insn->opcode->opcode);
-    }
-  /* TODO: FPU_BOTH */
-  else if ((insn->opcode->attr & NASM_ATTR_MAC)
-          && (insn->opcode->attr & NASM_ATTR_DXREG))
-    {
-      if (nds32_mac && nds32_dx_regs)
-       nds32_elf_flags |= E_NDS32_HAS_MAC_DX_INST;
-      else
-       as_bad (_("instruction %s requires enabling DX_REGS extension"),
-               insn->opcode->opcode);
-    }
-  /* TODO: for DX_REG set but not for MAC, DIV, AUDIO */
-  else if (insn->opcode->attr & NASM_ATTR_IFC_EXT)
-    {
-      nds32_elf_flags |= E_NDS32_HAS_IFC_INST;
-    }
-  /* TODO: E_NDS32_HAS_SATURATION_INST */
-}
-
-/* Append relax relocation for link time relaxing.  */
+      fixup_size = fixup_now->size;
 
-static void
-nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value)
-{
-  struct nds32_relocs_pattern *relocs_temp =
-    (struct nds32_relocs_pattern *) value;
-  unsigned int reloc, group_type, insn;
-  symbolS *sym;
-  unsigned int i = 0, x = 0, y;
-  segT seg_bak = now_seg;
-  frchainS *frchain_bak = frchain_now;
-
-  if (!relocs_temp)
-    return;
+      /* Insert all fixup.  */
+      while (fixup_size != 0 && fixup_now->offset == offset)
+       {
+         /* Set the real instruction size in element.  */
+         fixup_size = pattern_now->opcode->isize;
+         pcrel = ((fixup_now->ramp & NDS32_PCREL) != 0) ? 1 : 0;
+         if (fixup_now->ramp & NDS32_FIX)
+           {
+             /* Convert original relocation.  */
+             pattern_now->fixP->fx_r_type = fixup_now->r_type ;
+             fixup_size = 0;
+           }
+         else if ((fixup_now->ramp & NDS32_PTR) != 0)
+           {
+             /* This relocation has to point to another instruction.  Make
+                sure each resolved relocation has to be pointed.  */
+             pattern_temp = relocs_pattern;
+             /* All instruction in relax_table should be 32-bit.  */
+             hint_count = hint_info.relax_code_size / 4;
+             code_insn = CLEAN_REG (*(code_seq + hint_count - 1));
+             while (pattern_temp)
+               {
+                 /* Point to every resolved relocation.  */
+                 if (nds32_match_hint_insn (pattern_temp->opcode, code_insn))
+                   {
+                     ptr_offset =
+                       pattern_temp->where - pattern_temp->frag->fr_literal;
+                     exp.X_add_symbol = symbol_temp_new (now_seg, ptr_offset,
+                                                         pattern_temp->frag);
+                     exp.X_add_number = 0;
+                     fixP =
+                       fix_new_exp (fragP, where - fragP->fr_literal,
+                                    fixup_size, &exp, 0, fixup_now->r_type);
+                     fixP->fx_addnumber = fixP->fx_offset;
+                   }
+                 pattern_temp = pattern_temp->next;
+               }
+             fixup_size = 0;
+           }
+         else if (fixup_now->ramp & NDS32_ADDEND)
+           {
+             range = nds32_elf_sethi_range (relocs_pattern);
+             if (range == NDS32_LOADSTORE_NONE)
+               {
+                 as_bad (_("Internal error: Range error. %s"), now_seg->name);
+                 return;
+               }
+             exp.X_add_symbol = abs_section_sym;
+             exp.X_add_number = SET_ADDEND (4, 0, optimize, enable_16bit);
+             exp.X_add_number |= ((range & 0x3f) << 8);
+           }
+         else if ((fixup_now->ramp & NDS32_ABS) != 0)
+           {
+             /* This is a tag relocation.  */
+             exp.X_add_symbol = abs_section_sym;
+             exp.X_add_number = 0;
+           }
+         else if ((fixup_now->ramp & NDS32_INSN16) != 0)
+           {
+             if (!enable_16bit)
+               fixup_size = 0;
+             /* This is a tag relocation.  */
+             exp.X_add_symbol = abs_section_sym;
+             exp.X_add_number = 0;
+           }
+         else if ((fixup_now->ramp & NDS32_SYM) != 0)
+           {
+             /* For EMPTY relocation save the true symbol.  */
+             exp.X_add_symbol = hi_sym;
+             exp.X_add_number = hi_branch_offset;
+           }
+         else if (NDS32_SYM_DESC_MEM & fixup_now->ramp)
+           {
+             /* Do the same as NDS32_SYM.  */
+             exp.X_add_symbol = hi_sym;
+             exp.X_add_number = hi_branch_offset;
+
+             /* Extra to NDS32_SYM.  */
+             /* Detect if DESC_FUNC relax type do apply.  */
+             if ((REG_GP == N32_RA5 (pattern_now->insn))
+                 || (REG_GP == N32_RB5 (pattern_now->insn)))
+               {
+                 fixP = fix_new_exp (fragP, where - fragP->fr_literal,
+                                     fixup_size, &exp, pcrel,
+                                     BFD_RELOC_NDS32_TLS_DESC_FUNC);
+                 fixP->fx_addnumber = fixP->fx_offset;
 
-  group_type = relocs_temp->reloc;
-  sym = relocs_temp->sym;
-  /* Inserting fix up must specify now_seg or frchain_now.  */
-  now_seg = relocs_temp->seg;
-  frchain_now = relocs_temp->frchain;
+                 fixup_size = 0;
+               }
+             /* Else do as usual.  */
+           }
+         else if (fixup_now->ramp & NDS32_PTR_PATTERN)
+           {
+             /* Find out PTR_RESOLVED code pattern.  */
+             nds32_relax_fixup_info_t *next_fixup = fixup_now + 1;
+             uint32_t resolved_pattern = 0;
+             while (next_fixup->offset)
+               {
+                 if (next_fixup->r_type == BFD_RELOC_NDS32_PTR_RESOLVED)
+                   {
+                     uint32_t new_pattern = code_seq[next_fixup->offset >> 2];
+                     if (!resolved_pattern)
+                       resolved_pattern = new_pattern;
+                     else if (new_pattern != resolved_pattern)
+                       {
+                         as_warn (_("Multiple BFD_RELOC_NDS32_PTR_RESOLVED "
+                                    "patterns are not supported yet!"));
+                         break;
+                       }
+                   }
+                 ++next_fixup;
+               }
 
-  /* Find pattern in relocation table.  */
-  while (i < (sizeof (relocation_table)/sizeof (relocation_table[0]))
-        &&relocation_table[i].main_type != group_type)
-    i++;
+             /* Find matched code and insert fix-ups.  */
+             struct nds32_relocs_pattern *next_pattern = pattern_now->next;
+             /* This relocation has to point to another instruction.
+                Make sure each resolved relocation has to be pointed.  */
+             /* All instruction in relax_table should be 32-bit.  */
+             while (next_pattern)
+               {
+                 uint32_t cur_pattern = GET_OPCODE (next_pattern->opcode->value);
+                 if (cur_pattern == resolved_pattern)
+                   {
+                     ptr_offset = next_pattern->where
+                       - next_pattern->frag->fr_literal;
+                     exp.X_add_symbol = symbol_temp_new (now_seg, ptr_offset,
+                                                         next_pattern->frag);
+                     exp.X_add_number = 0;
+                     fixP = fix_new_exp (fragP, where - fragP->fr_literal,
+                                         fixup_size, &exp, 0,
+                                         fixup_now->r_type);
+                     fixP->fx_addnumber = fixP->fx_offset;
+                   }
+                 next_pattern = next_pattern->next;
+               }
 
-  /* Can not find relocation pattern.  */
-  if (relocation_table[i].main_type == 0)
-    return;
+             fixup_size = 0;
+           }
+         else if (fixup_now->ramp & NDS32_PTR_MULTIPLE)
+           {
+             /* Find each PTR_RESOLVED pattern after PTR.  */
+             nds32_relax_fixup_info_t *next_fixup = fixup_now + 1;
+             while (next_fixup->offset)
+               {
+                 if (next_fixup->r_type == BFD_RELOC_NDS32_PTR_RESOLVED)
+                   {
+                     uint32_t pattern = code_seq[next_fixup->offset >> 2];
+                     /* Find matched code to insert fix-ups.  */
+                     struct nds32_relocs_pattern *next_insn = pattern_now->next;
+                     while (next_insn)
+                       {
+                         uint32_t insn_pattern = GET_OPCODE (next_insn->opcode->value);
+                         if (insn_pattern == pattern)
+                           {
+                             ptr_offset = next_insn->where
+                               - next_insn->frag->fr_literal;
+                             exp.X_add_symbol = symbol_temp_new (now_seg,
+                                                                 ptr_offset,
+                                                                 next_insn->frag);
+                             exp.X_add_number = 0;
+                             fixP = fix_new_exp (fragP,
+                                                 where - fragP->fr_literal,
+                                                 fixup_size, &exp, 0,
+                                                 fixup_now->r_type);
+                             fixP->fx_addnumber = fixP->fx_offset;
+                           }
+                         next_insn = next_insn->next;
+                       }
+                   }
+                 ++next_fixup;
+               }
+             fixup_size = 0;
+           }
+         else
+           {
+             exp.X_add_symbol = sym;
+             exp.X_add_number = branch_offset;
+           }
 
-  while (relocs_temp)
-    {
-      y = 0;
+         if (fixup_size != 0)
+           {
+             fixP = fix_new_exp (fragP, where - fragP->fr_literal, fixup_size,
+                                 &exp, pcrel, fixup_now->r_type);
+             fixP->fx_addnumber = fixP->fx_offset;
+           }
+         fixup_now++;
+         fixup_size = fixup_now->size;
+       }
 
-      while (relocation_table[i].reloc_insn[x][y][0] != 0)
+#ifdef NDS32_LINUX_TOOLCHAIN
+      /* Insert group relocation for each relax hint.  */
+      if (key)
        {
-         reloc = relocation_table[i].reloc_insn[x][y][0];
-         insn = relocation_table[i].reloc_insn[x][y][1];
-         nds32_elf_insert_relocation (relocs_temp, reloc, insn, sym);
-         y++;
+         exp.X_add_symbol = hi_sym; /* for eyes only */
+         exp.X_add_number = group_id;
+         fixP = fix_new_exp (fragP, where - fragP->fr_literal, fixup_size,
+                             &exp, pcrel, BFD_RELOC_NDS32_GROUP);
+         fixP->fx_addnumber = fixP->fx_offset;
        }
+#endif
+
+      if (count < relax_code_size / 4)
+       count++;
+      pattern_now = pattern_now->next;
+    }
+
+restore:
+  now_seg = seg_bak;
+  frchain_now = frchain_bak;
+}
 
-      /* Next instruction.  */
-      relocs_temp = relocs_temp->next;
+static void
+nds32_str_tolower (const char *src, char *dest)
+{
+  unsigned int i, len;
 
-      /* There are load store instruction shared setting symbol part, so
-        re-using the final relocation.  */
-      if (relocation_table[i].reloc_insn[x+1][0][0] != 0)
-       x++;
-    }
+  len = strlen (src);
 
-  now_seg = seg_bak;
-  frchain_now = frchain_bak;
+  for (i = 0; i < len; i++)
+    *(dest + i) = TOLOWER (*(src + i));
+
+  *(dest + i) = '\0';
 }
 
 /* Check instruction if it can be used for the baseline.  */
 
 static bfd_boolean
-nds32_check_insn_available (struct nds32_asm_insn insn, char *str)
+nds32_check_insn_available (struct nds32_asm_insn insn, const char *str)
 {
   int attr = insn.attr & ATTR_ALL;
   static int baseline_isa = 0;
+  char *s;
+
+  s = xmalloc (strlen (str) + 1);
+  nds32_str_tolower (str, s);
+  if (verbatim
+      && (((insn.opcode->value == ALU2 (MTUSR)
+           || insn.opcode->value == ALU2 (MFUSR))
+          && (strstr (s, "lc")
+              || strstr (s, "le")
+              || strstr (s, "lb")))
+         || (insn.attr & NASM_ATTR_ZOL)))
+    {
+      as_bad (_("Not support instruction %s in verbatim."), str);
+      return FALSE;
+    }
+  free (s);
+
+  if (!enable_16bit && insn.opcode->isize == 2)
+    {
+      as_bad (_("16-bit instruction is disabled: %s."), str);
+      return FALSE;
+    }
+
   /* No isa setting or all isa can use.  */
   if (attr == 0 || attr == ATTR_ALL)
     return TRUE;
@@ -4648,7 +6338,7 @@ nds32_check_insn_available (struct nds32_asm_insn insn, char *str)
 
   if  ((baseline_isa & attr) == 0)
     {
-      as_bad (_("Not support instrcution %s in the baseline."), str);
+      as_bad (_("Instruction %s not supported in the baseline."), str);
       return FALSE;
     }
   return TRUE;
@@ -4663,12 +6353,13 @@ md_assemble (char *str)
   char *out;
   struct nds32_pseudo_opcode *popcode;
   const struct nds32_field *fld = NULL;
-  fixS *fixP ATTRIBUTE_UNUSED;
-  int insn_type;
+  fixS *fixP;
   uint16_t insn_16;
-  uint32_t insn_32;
   struct nds32_relocs_pattern *relocs_temp;
-  expressionS *pexp;
+  struct nds32_relocs_group *group_temp;
+  fragS *fragP;
+  int label = label_exist;
+  static bfd_boolean pseudo_hint = FALSE;
 
   popcode = nds32_lookup_pseudo_opcode (str);
   /* Note that we need to check 'verbatim' and
@@ -4677,11 +6368,23 @@ md_assemble (char *str)
      need to perform pseudo instruction expansion/transformation.  */
   if (popcode && !(verbatim && popcode->physical_op))
     {
+      /* Pseudo instruction is with relax_hint.  */
+      if (relaxing)
+       pseudo_hint = TRUE;
       pseudo_opcode = TRUE;
       nds32_pseudo_opcode_wrapper (str, popcode);
       pseudo_opcode = FALSE;
+      pseudo_hint = FALSE;
       nds32_elf_append_relax_relocs (NULL, relocs_list);
 
+      /* Free relax_hint group list.  */
+      while (nds32_relax_hint_current)
+       {
+         group_temp = nds32_relax_hint_current->next;
+         free (nds32_relax_hint_current);
+         nds32_relax_hint_current = group_temp;
+       }
+
       /* Free pseudo list.  */
       relocs_temp = relocs_list;
       while (relocs_temp)
@@ -4694,7 +6397,9 @@ md_assemble (char *str)
       return;
     }
 
-  insn.info = (expressionS *) alloca (sizeof (expressionS));
+  label_exist = 0;
+  insn.info = XNEW (expressionS);
+  asm_desc.result = NASM_OK;
   nds32_assemble (&asm_desc, &insn, str);
 
   switch (asm_desc.result)
@@ -4706,7 +6411,7 @@ md_assemble (char *str)
       as_bad (_("Incorrect syntax, %s."), str);
       return;
     case NASM_ERR_OPERAND:
-      as_bad (_("Unrecognized operand, %s."), str);
+      as_bad (_("Unrecognized operand/register, %s."), str);
       return;
     case NASM_ERR_OUT_OF_RANGE:
       as_bad (_("Operand out of range, %s."), str);
@@ -4728,61 +6433,119 @@ md_assemble (char *str)
   if (!nds32_check_insn_available (insn, str))
     return;
 
-  /* Create new frag if the instruction can be relaxed.  */
+  /* Make sure the beginning of text being 2-byte align.  */
+  nds32_adjust_label (1);
+  add_mapping_symbol (MAP_CODE, 0, 0);
   fld = insn.field;
-  if (!verbatim && fld && (insn.attr & NASM_ATTR_BRANCH))
+  /* Try to allocate the max size to guarantee relaxable same branch
+     instructions in the same fragment.  */
+  frag_grow (NDS32_MAXCHAR);
+  fragP = frag_now;
+
+  if (fld && (insn.attr & NASM_ATTR_BRANCH)
+      && (pseudo_opcode || (insn.opcode->value != INSN_JAL
+                           && insn.opcode->value != INSN_J))
+      && (!verbatim || pseudo_opcode))
     {
       /* User assembly code branch relax for it.  */
-      fragS *fragp = frag_now;
-
       /* If fld is not NULL, it is a symbol.  */
+      /* Branch must relax to proper pattern in user assembly code exclude
+        J and JAL.  Keep these two in original type for users which wants
+        to keep their size be fixed.  In general, assembler does not convert
+        instruction generated by compiler.  But jump instruction may be
+        truncated in text virtual model.  For workaround, compiler generate
+        pseudo jump to fix this issue currently.  */
+
       /* Get branch range type.  */
+      dwarf2_emit_insn (0);
       enum nds32_br_range range_type;
-      range_type = get_range_type (fld);
+      expressionS *pexp = insn.info;
 
-      pexp = insn.info;
+      range_type = get_range_type (fld);
 
-      out = frag_var (rs_machine_dependent,
-                     NDS32_MAXCHAR,
+      out = frag_var (rs_machine_dependent, NDS32_MAXCHAR,
                      0, /* VAR is un-used.  */
                      range_type, /* SUBTYPE is used as range type.  */
-                     pexp->X_add_symbol,
-                     pexp->X_add_number,
-                     0);
-      /* If the original frag is full, the instruction must save in next
-        one.  */
-      while (fragp->fr_next != frag_now)
-       fragp = fragp->fr_next;
-      fragp->fr_fix += insn.opcode->isize;
-      fragp->tc_frag_data.opcode = insn.opcode;
-      fragp->tc_frag_data.insn = insn.insn;
-      dwarf2_emit_insn (insn.opcode->isize);
+                     pexp->X_add_symbol, pexp->X_add_number, 0);
+
+      fragP->fr_fix += insn.opcode->isize;
+      fragP->tc_frag_data.opcode = insn.opcode;
+      fragP->tc_frag_data.insn = insn.insn;
       if (insn.opcode->isize == 4)
        bfd_putb32 (insn.insn, out);
       else if (insn.opcode->isize == 2)
        bfd_putb16 (insn.insn, out);
+      fragP->tc_frag_data.flag |= NDS32_FRAG_BRANCH;
+
+      free (insn.info);
       return;
       /* md_convert_frag will insert relocations.  */
     }
-  else if (!verbatim && !fld && (optimize || optimize_for_space))
-    {
-      /* User assembly code without relocating convert it to 16bits if needed.  */
-      insn_32 = insn.insn;
+  else if (!relaxing && enable_16bit && (optimize || optimize_for_space)
+          && ((!fld && !verbatim && insn.opcode->isize == 4
+               && nds32_convert_32_to_16 (stdoutput, insn.insn, &insn_16, NULL))
+              || (insn.opcode->isize == 2
+                  && nds32_convert_16_to_32 (stdoutput, insn.insn, NULL))))
+    {
+      /* Record this one is relaxable.  */
+      expressionS *pexp = insn.info;
+      dwarf2_emit_insn (0);
+      if (fld)
+       {
+         out = frag_var (rs_machine_dependent,
+                         4, /* Max size is 32-bit instruction.  */
+                         0, /* VAR is un-used.  */
+                         0, pexp->X_add_symbol, pexp->X_add_number, 0);
+         fragP->tc_frag_data.flag |= NDS32_FRAG_RELAXABLE_BRANCH;
+       }
+      else
+       out = frag_var (rs_machine_dependent,
+                       4, /* Max size is 32-bit instruction.  */
+                       0, /* VAR is un-used.  */
+                       0, NULL, 0, NULL);
+      fragP->tc_frag_data.flag |= NDS32_FRAG_RELAXABLE;
+      fragP->tc_frag_data.opcode = insn.opcode;
+      fragP->tc_frag_data.insn = insn.insn;
+      fragP->fr_fix += 2;
+
+      /* In original, we don't relax the instruction with label on it,
+        but this may cause some redundant nop16.  Therefore, tag this
+        relaxable instruction and relax it carefully.  */
+      if (label)
+       fragP->tc_frag_data.flag |= NDS32_FRAG_LABEL;
 
-      /* Convert instruction to 16-bits.  */
-      if (insn.opcode->isize == 4
-         && nds32_convert_32_to_16 (stdoutput, insn_32,
-                                    &insn_16, &insn_type))
+      if (insn.opcode->isize == 4)
+       bfd_putb16 (insn_16, out);
+      else if (insn.opcode->isize == 2)
+       bfd_putb16 (insn.insn, out);
+
+      free (insn.info);
+      return;
+    }
+  else if ((verbatim || !relaxing) && optimize && label)
+    {
+      /* This instruction is with label.  */
+      expressionS exp;
+      out = frag_var (rs_machine_dependent, insn.opcode->isize,
+                     0, 0, NULL, 0, NULL);
+      /* If this instruction is branch target, it is not relaxable.  */
+      fragP->tc_frag_data.flag = NDS32_FRAG_LABEL;
+      fragP->tc_frag_data.opcode = insn.opcode;
+      fragP->tc_frag_data.insn = insn.insn;
+      fragP->fr_fix += insn.opcode->isize;
+      if (insn.opcode->isize == 4)
        {
-         out = frag_more (2);
-         frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL);
-         bfd_putb16 (insn_16, out);
-         dwarf2_emit_insn (2);
-         return;
+         exp.X_op = O_symbol;
+         exp.X_add_symbol = abs_section_sym;
+         exp.X_add_number = 0;
+         fixP = fix_new_exp (fragP, fragP->fr_fix - 4, 0, &exp,
+                             0, BFD_RELOC_NDS32_LABEL);
+         if (!verbatim)
+           fragP->tc_frag_data.flag = NDS32_FRAG_ALIGN;
        }
     }
-
-  out = frag_more (insn.opcode->isize);
+  else
+    out = frag_more (insn.opcode->isize);
 
   if (insn.opcode->isize == 4)
     bfd_putb32 (insn.insn, out);
@@ -4791,13 +6554,16 @@ md_assemble (char *str)
 
   dwarf2_emit_insn (insn.opcode->isize);
 
-  if (fld)
-    {
-      /* Compiler generating code and user assembly pseudo load-store, insert
-        fixup here.  */
-      pexp = insn.info;
-      nds32_elf_record_fixup_exp (str, fld, pexp, out, &insn);
-    }
+  /* Compiler generating code and user assembly pseudo load-store, insert
+     fixup here.  */
+  expressionS *pexp = insn.info;
+  fixP = nds32_elf_record_fixup_exp (fragP, str, fld, pexp, out, &insn);
+  /* Build relaxation pattern when relaxing is enable.  */
+  if (relaxing)
+    nds32_elf_build_relax_relation (fixP, pexp, out, &insn, fragP, fld,
+                                   pseudo_hint);
+
+  free (insn.info);
 }
 
 /* md_macro_start  */
@@ -4843,9 +6609,9 @@ md_operand (expressionS *expressionP)
 valueT
 md_section_align (segT segment, valueT size)
 {
-  int align = bfd_get_section_alignment (stdoutput, segment);
+  int align = bfd_section_alignment (segment);
 
-  return ((size + (1 << align) - 1) & (-1 << align));
+  return ((size + (1 << align) - 1) & ((valueT) -1 << align));
 }
 
 /* GAS will call this function when a symbol table lookup fails, before it
@@ -4921,7 +6687,7 @@ nds32_convert_to_range_type (long offset)
   return range_type;
 }
 
-/* Set insntruction register mask.  */
+/* Set instruction register mask.  */
 
 static void
 nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn,
@@ -4933,15 +6699,21 @@ nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn,
   int i = 0;
 
   /* The instruction has conditions.  Collect condition values.  */
-  while (offset == code_seq_cond[i].offset)
+  while (code_seq_cond[i].bitmask != 0)
     {
-      mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask;
-      *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos;
+      if (offset == code_seq_cond[i].offset)
+       {
+         mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask;
+         /* Sign extend.  */
+         if (cond_fields[i].signed_extend)
+           mask = (mask ^ ((cond_fields[i].bitmask + 1) >> 1)) -
+             ((cond_fields[i].bitmask + 1) >> 1);
+         *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos;
+       }
       i++;
     }
 }
 
-
 static int
 nds32_relax_branch_instructions (segT segment, fragS *fragP,
                                 long stretch ATTRIBUTE_UNUSED,
@@ -4959,28 +6731,47 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP,
   uint32_t *code_seq;
   uint32_t insn;
   int insn_size;
-  uint16_t insn_16;
-  int insn_type;
   int code_seq_offset;
 
   /* Replace with gas_assert (fragP->fr_symbol != NULL); */
   if (fragP->fr_symbol == NULL)
     return adjust;
 
-  /* If frag_var is not enough room, the previos frag is fr_full and with
+  /* If frag_var is not enough room, the previous frag is fr_full and with
      opcode.  The new one is rs_dependent but without opcode.  */
   if (opcode == NULL)
     return adjust;
 
+  /* Use U4G mode for b and bal in verbatim mode because lto may combine
+     functions into a file.  And order the file in the last when linking.
+     Once there is multiple definition, the same function will be kicked.
+     This may cause relocation truncated error.  */
+  if (verbatim && !nds32_pic
+      && (strcmp (opcode->opcode, "j") == 0
+         || strcmp (opcode->opcode, "jal") == 0))
+    {
+      fragP->fr_subtype = BR_RANGE_U4G;
+      if (init)
+       return 8;
+      else
+       return 0;
+    }
+
   relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
 
   if (relax_info == NULL)
     return adjust;
 
   if (init)
-    branch_range_type = relax_info->br_range;
+    {
+      branch_range_type = relax_info->br_range;
+      i = BR_RANGE_S256;
+    }
   else
-    branch_range_type = fragP->fr_subtype;
+    {
+      branch_range_type = fragP->fr_subtype;
+      i = branch_range_type;
+    }
 
   offset = nds32_calc_branch_offset (segment, fragP, stretch,
                                     relax_info, branch_range_type);
@@ -4989,15 +6780,21 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP,
 
   /* If actual range is equal to instruction jump range, do nothing.  */
   if (real_range_type == branch_range_type)
-    return adjust;
+    {
+      fragP->fr_subtype = real_range_type;
+      return adjust;
+    }
 
   /* Find out proper relaxation code sequence.  */
-  for (i = BR_RANGE_S256; i < BR_RANGE_NUM; i++)
+  for (; i < BR_RANGE_NUM; i++)
     {
       if (real_range_type <= (unsigned int) i)
        {
          if (init)
            diff = relax_info->relax_code_size[i] - opcode->isize;
+         else if (real_range_type < (unsigned int) i)
+           diff = relax_info->relax_code_size[real_range_type]
+             - relax_info->relax_code_size[branch_range_type];
          else
            diff = relax_info->relax_code_size[i]
              - relax_info->relax_code_size[branch_range_type];
@@ -5023,18 +6820,6 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP,
                  while (relax_info->relax_fixup[i][k].size !=0
                         && relax_info->relax_fixup[i][k].offset < code_seq_offset)
                    k++;
-                 if (relax_info->relax_fixup[i][k].size !=0
-                     && relax_info->relax_fixup[i][k].ramp & NDS32_ORIGIN)
-                   {
-                     /* Set register num to insntruction.  */
-                     nds32_elf_get_set_cond (relax_info, code_seq_offset, &insn,
-                                             fragP->tc_frag_data.insn, i);
-
-                     /* Try to convert to 16-bits instruction.  */
-                     if (nds32_convert_32_to_16 (stdoutput,
-                                                 insn, &insn_16, &insn_type))
-                       diff -= 2;
-                   }
                }
 
              code_seq_offset += insn_size;
@@ -5042,7 +6827,7 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP,
            }
 
          /* Update fr_subtype to new NDS32_BR_RANGE.  */
-         fragP->fr_subtype = i;
+         fragP->fr_subtype = real_range_type;
          break;
        }
     }
@@ -5050,6 +6835,105 @@ nds32_relax_branch_instructions (segT segment, fragS *fragP,
   return diff + adjust;
 }
 
+/* Adjust relaxable frag till current frag.  */
+
+static int
+nds32_adjust_relaxable_frag (fragS *startP, fragS *fragP)
+{
+  int adj;
+  if (startP->tc_frag_data.flag & NDS32_FRAG_RELAXED)
+    adj = -2;
+  else
+    adj = 2;
+
+  startP->tc_frag_data.flag ^= NDS32_FRAG_RELAXED;
+
+  while (startP)
+    {
+      startP = startP->fr_next;
+      if (startP)
+       {
+         startP->fr_address += adj;
+         if (startP == fragP)
+           break;
+       }
+    }
+  return adj;
+}
+
+static addressT
+nds32_get_align (addressT address, int align)
+{
+  addressT mask, new_address;
+
+  mask = ~((addressT) (~0) << align);
+  new_address = (address + mask) & (~mask);
+  return (new_address - address);
+}
+
+/* Check the prev_frag is legal.  */
+static void
+invalid_prev_frag (fragS * fragP, fragS **prev_frag, bfd_boolean relax)
+{
+  addressT address;
+  fragS *frag_start = *prev_frag;
+
+  if (!frag_start || !relax)
+    return;
+
+  if (frag_start->last_fr_address >= fragP->last_fr_address)
+    {
+      *prev_frag = NULL;
+      return;
+    }
+
+  fragS *frag_t = *prev_frag;
+  while (frag_t != fragP)
+    {
+      if (frag_t->fr_type == rs_align
+         || frag_t->fr_type == rs_align_code
+         || frag_t->fr_type == rs_align_test)
+       {
+         /* Relax instruction can not walk across label.  */
+         if (frag_t->tc_frag_data.flag & NDS32_FRAG_LABEL)
+           {
+             prev_frag = NULL;
+             return;
+           }
+         /* Relax previous relaxable to align rs_align frag.  */
+         address = frag_t->fr_address + frag_t->fr_fix;
+         addressT offset = nds32_get_align (address, (int) frag_t->fr_offset);
+         if (offset & 0x2)
+           {
+             /* If there is label on the prev_frag, check if it is aligned.  */
+             if (!((*prev_frag)->tc_frag_data.flag & NDS32_FRAG_LABEL)
+                 || (((*prev_frag)->fr_address + (*prev_frag)->fr_fix  - 2 )
+                     & 0x2) == 0)
+               nds32_adjust_relaxable_frag (*prev_frag, frag_t);
+           }
+         *prev_frag = NULL;
+         return;
+       }
+      frag_t = frag_t->fr_next;
+    }
+
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_ALIGN)
+    {
+      address = fragP->fr_address;
+      addressT offset = nds32_get_align (address, 2);
+      if (offset & 0x2)
+       {
+         /* If there is label on the prev_frag, check if it is aligned.  */
+         if (!((*prev_frag)->tc_frag_data.flag & NDS32_FRAG_LABEL)
+             || (((*prev_frag)->fr_address + (*prev_frag)->fr_fix  - 2 )
+                 & 0x2) == 0)
+           nds32_adjust_relaxable_frag (*prev_frag, fragP);
+       }
+      *prev_frag = NULL;
+      return;
+    }
+}
+
 /* md_relax_frag  */
 
 int
@@ -5059,9 +6943,21 @@ nds32_relax_frag (segT segment, fragS *fragP, long stretch ATTRIBUTE_UNUSED)
      1. relax for branch
      2. relax for 32-bits to 16-bits  */
 
-  int adjust;
+  static fragS *prev_frag = NULL;
+  int adjust = 0;
+
+  invalid_prev_frag (fragP, &prev_frag, TRUE);
 
-  adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0);
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH)
+    adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0);
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL)
+    prev_frag = NULL;
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE
+      && (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) == 0)
+    /* Here is considered relaxed case originally.  But it may cause
+       an endless loop when relaxing.  Once the instruction is relaxed,
+       it can not be undone.  */
+    prev_frag = fragP;
 
   return adjust;
 }
@@ -5083,9 +6979,20 @@ md_estimate_size_before_relax (fragS *fragP, segT segment)
      1. relax for branch
      2. relax for 32-bits to 16-bits  */
 
-  int adjust;
+  /* Save previous relaxable frag.  */
+  static fragS *prev_frag = NULL;
+  int adjust = 0;
+
+  invalid_prev_frag (fragP, &prev_frag, FALSE);
 
-  adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1);
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH)
+    adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1);
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL)
+    prev_frag = NULL;
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)
+    adjust = 2;
+  else if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE)
+    prev_frag = fragP;
 
   return adjust;
 }
@@ -5110,174 +7017,213 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP)
   enum nds32_br_range branch_range_type = fragP->fr_subtype;
   struct nds32_opcode *opcode = fragP->tc_frag_data.opcode;
   uint32_t origin_insn = fragP->tc_frag_data.insn;
-  int backup_endian;
   relax_info_t *relax_info;
   char *fr_buffer;
   int fr_where;
   int addend ATTRIBUTE_UNUSED;
-  offsetT branch_target_address;
-  offsetT branch_insn_address;
+  offsetT branch_target_address, branch_insn_address;
   expressionS exp;
   fixS *fixP;
   uint32_t *code_seq;
-  int code_size;
   uint32_t insn;
-  int insn_size;
-  int offset;
-  int i, j, k;
+  int code_size, insn_size, offset, fixup_size;
+  int buf_offset, pcrel;
+  int i, k;
   uint16_t insn_16;
-  int insn_type;
-  int buf_offset;
-  nds32_relax_fixup_info_t fixup_info[MAX_RELAX_NUM];
+  nds32_relax_fixup_info_t fixup_info[MAX_RELAX_FIX];
   /* Save the 1st instruction is converted to 16 bit or not.  */
-  bfd_boolean insn_convert = FALSE;
-  int fixup_size;
+  unsigned int branch_size;
+  enum bfd_reloc_code_real final_r_type;
 
   /* Replace with gas_assert (branch_symbol != NULL); */
-  if (branch_symbol == NULL)
+  if (branch_symbol == NULL && !(fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED))
     return;
 
-  /* If frag_var is not enough room, the previos frag is fr_full and with
+  /* If frag_var is not enough room, the previous frag is fr_full and with
      opcode.  The new one is rs_dependent but without opcode.  */
   if (opcode == NULL)
     return;
 
-  relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE_BRANCH)
+    {
+      relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
 
-  if (relax_info == NULL)
-    return;
+      if (relax_info == NULL)
+       return;
 
-  backup_endian = target_big_endian;
-  target_big_endian = 1;
+      i = BR_RANGE_S256;
+      while (i < BR_RANGE_NUM
+            && relax_info->relax_code_size[i]
+            != (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED ? 4 : 2))
+       i++;
 
-  fr_where = fragP->fr_fix - opcode->isize;
-  fr_buffer = fragP->fr_literal + fr_where;
+      if (i >= BR_RANGE_NUM)
+       as_bad ("Internal error: Cannot find relocation of"
+               "relaxable branch.");
 
-  if ((S_GET_SEGMENT (branch_symbol) != sec)
-      || S_IS_WEAK (branch_symbol))
-    {
-      if (fragP->fr_offset & 3)
-       as_warn (_("Addend to unresolved symbol is not on word boundary."));
-      addend = 0;
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = branch_symbol;
+      exp.X_add_number = branch_offset;
+      pcrel = ((relax_info->relax_fixup[i][0].ramp & NDS32_PCREL) != 0) ? 1 : 0;
+      fr_where = fragP->fr_fix - 2;
+      fixP = fix_new_exp (fragP, fr_where, relax_info->relax_fixup[i][0].size,
+                         &exp, pcrel, relax_info->relax_fixup[i][0].r_type);
+      fixP->fx_addnumber = fixP->fx_offset;
+
+      if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)
+       {
+         insn_16 = fragP->tc_frag_data.insn;
+         nds32_convert_16_to_32 (stdoutput, insn_16, &insn);
+         fr_buffer = fragP->fr_literal + fr_where;
+         fragP->fr_fix += 2;
+         exp.X_op = O_symbol;
+         exp.X_add_symbol = abs_section_sym;
+         exp.X_add_number = 0;
+         fix_new_exp (fragP, fr_where, 4,
+                      &exp, 0, BFD_RELOC_NDS32_INSN16);
+         number_to_chars_bigendian (fr_buffer, insn, 4);
+       }
     }
-  else
+  else if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)
     {
-      /* Calculate symbol-to-instruction offset.  */
-      branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset;
-      branch_insn_address = fragP->fr_address + fr_where;
-      addend = (branch_target_address - branch_insn_address) >> 1;
+      if (fragP->tc_frag_data.opcode->isize == 2)
+       {
+         insn_16 = fragP->tc_frag_data.insn;
+         nds32_convert_16_to_32 (stdoutput, insn_16, &insn);
+       }
+      else
+       insn = fragP->tc_frag_data.insn;
+      fragP->fr_fix += 2;
+      fr_where = fragP->fr_fix - 4;
+      fr_buffer = fragP->fr_literal + fr_where;
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = abs_section_sym;
+      exp.X_add_number = 0;
+      fix_new_exp (fragP, fr_where, 4, &exp, 0,
+                  BFD_RELOC_NDS32_INSN16);
+      number_to_chars_bigendian (fr_buffer, insn, 4);
     }
+  else if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH)
+    {
+      /* Branch instruction adjust and append relocations.  */
+      relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
 
-  code_size = relax_info->relax_code_size[branch_range_type];
-  code_seq = relax_info->relax_code_seq[branch_range_type];
+      if (relax_info == NULL)
+       return;
 
-  memcpy (fixup_info,
-         relax_info->relax_fixup[branch_range_type],
-         sizeof (fixup_info));
+      fr_where = fragP->fr_fix - opcode->isize;
+      fr_buffer = fragP->fr_literal + fr_where;
 
-  /* Fill in frag.  */
-  i = 0;
-  k = 0;
-  offset = 0; /* code_seq offset */
-  buf_offset = 0; /* fr_buffer offset */
-  while (offset < code_size)
-    {
-      insn = code_seq[i];
-      if (insn & 0x80000000) /* 16-bits instruction.  */
+      if ((S_GET_SEGMENT (branch_symbol) != sec)
+         || S_IS_WEAK (branch_symbol))
        {
-         insn = (insn >> 16) & 0xFFFF;
-         insn_size = 2;
+         if (fragP->fr_offset & 3)
+           as_warn (_("Addend to unresolved symbol is not on word boundary."));
+         addend = 0;
        }
-      else /* 32-bits instruction.  */
+      else
        {
-         insn_size = 4;
+         /* Calculate symbol-to-instruction offset.  */
+         branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset;
+         branch_insn_address = fragP->fr_address + fr_where;
+         addend = (branch_target_address - branch_insn_address) >> 1;
        }
 
-      nds32_elf_get_set_cond (relax_info, offset, &insn,
-                             origin_insn, branch_range_type);
+      code_size = relax_info->relax_code_size[branch_range_type];
+      code_seq = relax_info->relax_code_seq[branch_range_type];
 
-      /* Try to convert to 16-bits instruction.  Currently, only the first
-        insntruction in pattern can be converted.  EX: bnez sethi ori jr,
-        only bnez can be converted to 16 bit and ori can't.  */
+      memcpy (fixup_info, relax_info->relax_fixup[branch_range_type],
+             sizeof (fixup_info));
 
-      while (fixup_info[k].size != 0
-            && relax_info->relax_fixup[branch_range_type][k].offset < offset)
-       k++;
-      if ((fixup_info[k].size != 0
-          && fixup_info[k].ramp & NDS32_ORIGIN)
-         && nds32_convert_32_to_16 (stdoutput, insn, &insn_16, &insn_type))
+      /* Fill in frag.  */
+      i = 0;
+      k = 0;
+      offset = 0; /* code_seq offset */
+      buf_offset = 0; /* fr_buffer offset */
+      while (offset < code_size)
        {
-         /* Reduce to 16-bits instructions, adjust fixup_info[j]->offset.  */
-         for (j = 0; fixup_info[j].size != 0; j++)
+         insn = code_seq[i];
+         if (insn & 0x80000000) /* 16-bits instruction.  */
            {
-             if (fixup_info[j].ramp & NDS32_RELAX)
-               fixup_info[j].size -= 2;
-
-             if (fixup_info[j].offset > buf_offset)
-               fixup_info[j].offset -= 2;
+             insn = (insn >> 16) & 0xFFFF;
+             insn_size = 2;
+           }
+         else /* 32-bits instruction.  */
+           {
+             insn_size = 4;
            }
 
-         md_number_to_chars (fr_buffer + buf_offset, insn_16, 2);
-         buf_offset += 2;
-         if (offset == 0)
-           insn_convert = TRUE;
-       }
-      else
-       {
-         md_number_to_chars (fr_buffer + buf_offset, insn, insn_size);
-         buf_offset += insn_size;
-       }
-
-      offset += insn_size;
-      i++;
-    }
+         nds32_elf_get_set_cond (relax_info, offset, &insn,
+                                 origin_insn, branch_range_type);
 
-  /* Set up fixup.  */
-  exp.X_op = O_symbol;
+         /* Try to convert to 16-bits instruction.  Currently, only the first
+            instruction in pattern can be converted.  EX: bnez sethi ori jr,
+            only bnez can be converted to 16 bit and ori can't.  */
 
-  for (i = 0; fixup_info[i].size != 0; i++)
-    {
-      fixup_size = fixup_info[i].size;
+         while (fixup_info[k].size != 0
+                && relax_info->relax_fixup[branch_range_type][k].offset < offset)
+           k++;
 
-      if (((fixup_info[i].ramp & NDS32_ORIGIN) && insn_convert == TRUE)
-         ||((fixup_info[i].ramp & NDS32_CONVERT) && insn_convert == FALSE))
-       continue;
+         number_to_chars_bigendian (fr_buffer + buf_offset, insn, insn_size);
+         buf_offset += insn_size;
 
-      if ((fixup_info[i].ramp & NDS32_CREATE_LABLE) != 0)
-       {
-         /* This is a reverse branch.  */
-         exp.X_add_symbol = symbol_temp_new (sec, 0, fragP->fr_next);
-         exp.X_add_number = 0;
-       }
-      else if ((fixup_info[i].ramp & NDS32_RELAX) != 0)
-       {
-         /* This is a relax relocation.  */
-         exp.X_add_symbol = abs_section_sym;
-         exp.X_add_number =
-           SET_ADDEND (fixup_size /* size */ ,
-                       insn_convert , optimize, enable_16bit);
-       }
-      else
-       {
-         exp.X_add_symbol = branch_symbol;
-         exp.X_add_number = branch_offset;
+         offset += insn_size;
+         i++;
        }
 
-      if (fixup_info[i].r_type != 0)
+      /* Set up fixup.  */
+      exp.X_op = O_symbol;
+
+      for (i = 0; fixup_info[i].size != 0; i++)
        {
-         fixP = fix_new_exp (fragP,
-                             fr_where + fixup_info[i].offset,
-                             fixup_size,
-                             &exp,
-                             0,
-                             fixup_info[i].r_type);
-         fixP->fx_addnumber = fixP->fx_offset;
-       }
-    }
+         fixup_size = fixup_info[i].size;
+         pcrel = ((fixup_info[i].ramp & NDS32_PCREL) != 0) ? 1 : 0;
+
+         if ((fixup_info[i].ramp & NDS32_CREATE_LABEL) != 0)
+           {
+             /* This is a reverse branch.  */
+             exp.X_add_symbol = symbol_temp_new (sec, 0, fragP->fr_next);
+             exp.X_add_number = 0;
+           }
+         else if ((fixup_info[i].ramp & NDS32_PTR) != 0)
+           {
+             /* This relocation has to point to another instruction.  */
+             branch_size = fr_where + code_size - 4;
+             exp.X_add_symbol = symbol_temp_new (sec, branch_size, fragP);
+             exp.X_add_number = 0;
+           }
+         else if ((fixup_info[i].ramp & NDS32_ABS) != 0)
+           {
+             /* This is a tag relocation.  */
+             exp.X_add_symbol = abs_section_sym;
+             exp.X_add_number = 0;
+           }
+         else if ((fixup_info[i].ramp & NDS32_INSN16) != 0)
+           {
+             if (!enable_16bit)
+               continue;
+             /* This is a tag relocation.  */
+             exp.X_add_symbol = abs_section_sym;
+             exp.X_add_number = 0;
+           }
+         else
+           {
+             exp.X_add_symbol = branch_symbol;
+             exp.X_add_number = branch_offset;
+           }
 
-  fragP->fr_fix = fr_where + buf_offset;
+         if (fixup_info[i].r_type != 0)
+           {
+             final_r_type = fixup_info[i].r_type;
+             fixP = fix_new_exp (fragP, fr_where + fixup_info[i].offset,
+                                 fixup_size, &exp, pcrel,
+                                 final_r_type);
+             fixP->fx_addnumber = fixP->fx_offset;
+           }
+       }
 
-  target_big_endian = backup_endian;
+      fragP->fr_fix = fr_where + buf_offset;
+    }
 }
 
 /* tc_frob_file_before_fix  */
@@ -5287,15 +7233,62 @@ nds32_frob_file_before_fix (void)
 {
 }
 
-/* TC_FORCE_RELOCATION  */
-
-int
-nds32_force_relocation (fixS *fix ATTRIBUTE_UNUSED)
+static bfd_boolean
+nds32_relaxable_section (asection *sec)
 {
-  /* Always force relocation, because linker may adjust the code.  */
-  return 1;
+  return ((sec->flags & SEC_DEBUGGING) == 0
+         && strcmp (sec->name, ".eh_frame") != 0);
 }
 
+/* TC_FORCE_RELOCATION */
+int
+nds32_force_relocation (fixS * fix)
+{
+  switch (fix->fx_r_type)
+    {
+    case BFD_RELOC_NDS32_INSN16:
+    case BFD_RELOC_NDS32_LABEL:
+    case BFD_RELOC_NDS32_LONGCALL1:
+    case BFD_RELOC_NDS32_LONGCALL2:
+    case BFD_RELOC_NDS32_LONGCALL3:
+    case BFD_RELOC_NDS32_LONGJUMP1:
+    case BFD_RELOC_NDS32_LONGJUMP2:
+    case BFD_RELOC_NDS32_LONGJUMP3:
+    case BFD_RELOC_NDS32_LOADSTORE:
+    case BFD_RELOC_NDS32_9_FIXED:
+    case BFD_RELOC_NDS32_15_FIXED:
+    case BFD_RELOC_NDS32_17_FIXED:
+    case BFD_RELOC_NDS32_25_FIXED:
+    case BFD_RELOC_NDS32_9_PCREL:
+    case BFD_RELOC_NDS32_15_PCREL:
+    case BFD_RELOC_NDS32_17_PCREL:
+    case BFD_RELOC_NDS32_WORD_9_PCREL:
+    case BFD_RELOC_NDS32_10_UPCREL:
+    case BFD_RELOC_NDS32_25_PCREL:
+    case BFD_RELOC_NDS32_MINUEND:
+    case BFD_RELOC_NDS32_SUBTRAHEND:
+      return 1;
+
+    case BFD_RELOC_8:
+    case BFD_RELOC_16:
+    case BFD_RELOC_32:
+    case BFD_RELOC_NDS32_DIFF_ULEB128:
+      /* Linker should handle difference between two symbol.  */
+      return fix->fx_subsy != NULL
+       && nds32_relaxable_section (S_GET_SEGMENT (fix->fx_addsy));
+    case BFD_RELOC_64:
+      if (fix->fx_subsy)
+       as_bad ("Double word for difference between two symbols "
+               "is not supported across relaxation.");
+    default:
+      ;
+    }
+
+  if (generic_force_reloc (fix))
+    return 1;
+
+  return fix->fx_pcrel;
+}
 
 /* TC_VALIDATE_FIX_SUB  */
 
@@ -5323,13 +7316,10 @@ md_number_to_chars (char *buf, valueT val, int n)
     number_to_chars_littleendian (buf, val, n);
 }
 
-/* Equal to MAX_PRECISION in atof-ieee.c.  */
-#define MAX_LITTLENUMS 6
-
 /* This function is called to convert an ASCII string into a floating point
    value in format used by the CPU.  */
 
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
   int i;
@@ -5446,14 +7436,14 @@ nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
   fixS *fixp;
 
   seginfo = seg_info (sec);
-  if (!seginfo || !symbol_rootP || !subseg_text_p (sec))
+  if (!seginfo || !symbol_rootP || !subseg_text_p (sec) || sec->size == 0)
     return;
-  /* If there is no relocation and relax is disabled, it is not necessary to
-     insert R_NDS32_RELAX_ENTRY for linker do EX9 or IFC optimization.  */
+
   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
     if (!fixp->fx_done)
       break;
-  if (!fixp && !enable_relax_ex9 && !verbatim)
+
+  if (!fixp && !verbatim && ict_flag == ICT_NONE)
     return;
 
   subseg_change (sec, 0);
@@ -5461,21 +7451,21 @@ nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
   /* Set RELAX_ENTRY flags for linker.  */
   fragP = seginfo->frchainP->frch_root;
   exp.X_op = O_symbol;
-  exp.X_add_symbol = section_symbol (sec);
+  exp.X_add_symbol = abs_section_sym;
   exp.X_add_number = 0;
   if (!enable_relax_relocs)
     exp.X_add_number |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG;
   else
     {
       /* These flags are only enabled when global relax is enabled.
-        Maybe we can check DISABLE_RELAX_FLAG at linke-time,
+        Maybe we can check DISABLE_RELAX_FLAG at link-time,
         so we set them anyway.  */
-      if (enable_relax_ex9)
-       exp.X_add_number |= R_NDS32_RELAX_ENTRY_EX9_FLAG;
-      if (enable_relax_ifc)
-       exp.X_add_number |= R_NDS32_RELAX_ENTRY_IFC_FLAG;
       if (verbatim)
        exp.X_add_number |= R_NDS32_RELAX_ENTRY_VERBATIM_FLAG;
+      if (ict_flag == ICT_SMALL)
+       exp.X_add_number |= R_NDS32_RELAX_ENTRY_ICT_SMALL;
+      else if (ict_flag == ICT_LARGE)
+       exp.X_add_number |= R_NDS32_RELAX_ENTRY_ICT_LARGE;
     }
   if (optimize)
     exp.X_add_number |= R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG;
@@ -5494,9 +7484,42 @@ nds32_elf_analysis_relax_hint (void)
   hash_traverse (nds32_hint_hash, nds32_elf_append_relax_relocs);
 }
 
+static void
+nds32_elf_insert_final_frag (void)
+{
+  struct frchain *frchainP;
+  asection *s;
+  fragS *fragP;
+
+  if (!optimize)
+    return;
+
+  for (s = stdoutput->sections; s; s = s->next)
+    {
+      segment_info_type *seginfo = seg_info (s);
+      if (!seginfo)
+       continue;
+
+      for (frchainP = seginfo->frchainP; frchainP != NULL;
+          frchainP = frchainP->frch_next)
+       {
+         subseg_set (s, frchainP->frch_subseg);
+
+         if (subseg_text_p (now_seg))
+           {
+             fragP = frag_now;
+             frag_var (rs_machine_dependent, 2, /* Max size.  */
+                       0, /* VAR is un-used.  */ 0, NULL, 0, NULL);
+             fragP->tc_frag_data.flag |= NDS32_FRAG_FINAL;
+           }
+       }
+    }
+}
+
 void
 md_end (void)
 {
+  nds32_elf_insert_final_frag ();
   nds32_elf_analysis_relax_hint ();
   bfd_map_over_sections (stdoutput, nds32_insert_leb128_fixes, NULL);
 }
@@ -5542,13 +7565,13 @@ compar_relent (const void *lhs, const void *rhs)
    relocation.  */
 
 void
-nds32_set_section_relocs (asection *sec, arelent ** relocs ATTRIBUTE_UNUSED,
-                         unsigned int n ATTRIBUTE_UNUSED)
+nds32_set_section_relocs (asection *sec ATTRIBUTE_UNUSED,
+                         arelent **relocs, unsigned int n)
 {
-  bfd *abfd ATTRIBUTE_UNUSED = sec->owner;
-  if (bfd_get_section_flags (abfd, sec) & (flagword) SEC_RELOC)
-    nds32_insertion_sort (sec->orelocation, sec->reloc_count, sizeof (arelent**),
-                         compar_relent);
+  if (n <= 1)
+    return;
+
+  nds32_insertion_sort (relocs, n, sizeof (*relocs), compar_relent);
 }
 
 long
@@ -5573,8 +7596,6 @@ nds32_post_relax_hook (void)
   bfd_map_over_sections (stdoutput, nds32_insert_relax_entry, NULL);
 }
 
-
-
 /* tc_fix_adjustable ()
 
    Return whether this symbol (fixup) can be replaced with
@@ -5596,6 +7617,13 @@ nds32_fix_adjustable (fixS *fixP)
     case BFD_RELOC_16:
     case BFD_RELOC_32:
     case BFD_RELOC_NDS32_PTR:
+    case BFD_RELOC_NDS32_LONGCALL4:
+    case BFD_RELOC_NDS32_LONGCALL5:
+    case BFD_RELOC_NDS32_LONGCALL6:
+    case BFD_RELOC_NDS32_LONGJUMP4:
+    case BFD_RELOC_NDS32_LONGJUMP5:
+    case BFD_RELOC_NDS32_LONGJUMP6:
+    case BFD_RELOC_NDS32_LONGJUMP7:
       return 1;
     default:
       return 0;
@@ -5607,13 +7635,14 @@ nds32_fix_adjustable (fixS *fixP)
 void
 elf_nds32_final_processing (void)
 {
-  /* An FPU_COM instruction is found without previous non-FPU_COM instruction.  */
+  /* An FPU_COM instruction is found without previous non-FPU_COM
+     instruction.  */
   if (nds32_fpu_com
       && !(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST)))
     {
       /* Since only FPU_COM instructions are used and no other FPU instructions
-         are used.  The nds32_elf_flags will be decided by the enabled options by
-        command line or default configuration.  */
+        are used.  The nds32_elf_flags will be decided by the enabled options
+        by command line or default configuration.  */
       if (nds32_fpu_dp_ext || nds32_fpu_sp_ext)
        {
          nds32_elf_flags |= nds32_fpu_dp_ext ? E_NDS32_HAS_FPU_DP_INST : 0;
@@ -5645,7 +7674,7 @@ elf_nds32_final_processing (void)
   elf_elfheader (stdoutput)->e_flags |= nds32_elf_flags;
 }
 
-/* Implement md_apply_fix.  Apply the fix-up or tranform the fix-up for
+/* Implement md_apply_fix.  Apply the fix-up or transform the fix-up for
    later relocation generation.  */
 
 void
@@ -5658,21 +7687,43 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       && fixP->fx_r_type > BFD_RELOC_NONE
       && fixP->fx_r_type != BFD_RELOC_NDS32_DIFF_ULEB128)
     {
-      /* FIXME: This implementation is partially borrowed from our old
-                nds32 binutils.  Its purpose is to leave original bfd
-                relocation untouched, while other relocation created by CGEN
-                will be converted into general bfd relocations.
-                However, since we no longer use CGEN, we can simply use
-                a little piece of code to deal with general bfd relocation,
-                especially for the BFD_RELOC_NDS32_DATA, which is just used
-                as a marker for different purpose.
-                It is believed that we can construct a better mechanism to
-                deal with the whole relocation issue in nds32 target
-                without using CGEN.  */
+      /* In our old nds32 binutils, it must convert relocations which is
+        generated by CGEN.  However, it does not have to consider this anymore.
+        In current, it only deal with data relocations which enum
+        is smaller than BFD_RELOC_NONE and BFD_RELOC_NDS32_DIFF_ULEB128.
+        It is believed that we can construct a better mechanism to
+        deal with the whole relocation issue in nds32 target
+        without using CGEN.  */
       fixP->fx_addnumber = value;
       fixP->tc_fix_data = NULL;
-      if (fixP->fx_r_type == BFD_RELOC_NDS32_DATA)
-        fixP->fx_done = 1;
+
+      /* Transform specific relocations here for later relocation generation.
+        Tag tls data for linker.  */
+      switch (fixP->fx_r_type)
+       {
+       case BFD_RELOC_NDS32_DATA:
+         /* This reloc is obselete, we do not need it so far.  */
+         fixP->fx_done = 1;
+         break;
+       case BFD_RELOC_NDS32_TPOFF:
+       case BFD_RELOC_NDS32_TLS_LE_HI20:
+       case BFD_RELOC_NDS32_TLS_LE_LO12:
+       case BFD_RELOC_NDS32_TLS_LE_ADD:
+       case BFD_RELOC_NDS32_TLS_LE_LS:
+       case BFD_RELOC_NDS32_GOTTPOFF:
+       case BFD_RELOC_NDS32_TLS_IE_HI20:
+       case BFD_RELOC_NDS32_TLS_IE_LO12S2:
+       case BFD_RELOC_NDS32_TLS_DESC_HI20:
+       case BFD_RELOC_NDS32_TLS_DESC_LO12:
+       case BFD_RELOC_NDS32_TLS_IE_LO12:
+       case BFD_RELOC_NDS32_TLS_IEGP_HI20:
+       case BFD_RELOC_NDS32_TLS_IEGP_LO12:
+       case BFD_RELOC_NDS32_TLS_IEGP_LO12S2:
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
+         break;
+       default:
+         break;
+       }
       return;
     }
 
@@ -5708,7 +7759,7 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
         ---- 8< ---- 8< ---- 8< ---- 8< ----
 
         We use a single relocation entry for this expression.
-        * The initial distance value is stored direcly in that location
+        * The initial distance value is stored directly in that location
           specified by r_offset (i.e., foo in this example.)
         * The begin of the region, i.e., .LBEGIN, is specified by
           r_info/R_SYM and r_addend, e.g., .text + 0x32.
@@ -5772,7 +7823,8 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          /* cvt_frag_to_fill () has called output_leb128 () for us.  */
          break;
        default:
-         as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _("expression too complex"));
          return;
        }
     }
@@ -5793,10 +7845,12 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
          break;
        case BFD_RELOC_64:
          md_number_to_chars (where, value, 8);
+         break;
        default:
          as_bad_where (fixP->fx_file, fixP->fx_line,
                        _("Internal error: Unknown fixup type %d (`%s')"),
-                       fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
+                       fixP->fx_r_type,
+                       bfd_get_reloc_code_name (fixP->fx_r_type));
          break;
        }
     }
@@ -5810,9 +7864,9 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) xmalloc (sizeof (arelent));
+  reloc = XNEW (arelent);
 
-  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
 
@@ -5847,6 +7901,16 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
   return reloc;
 }
 
+static struct suffix_name suffix_table[] =
+{
+  {"GOTOFF",   BFD_RELOC_NDS32_GOTOFF},
+  {"GOT",      BFD_RELOC_NDS32_GOT20},
+  {"TPOFF",    BFD_RELOC_NDS32_TPOFF},
+  {"PLT",      BFD_RELOC_NDS32_25_PLTREL},
+  {"GOTTPOFF", BFD_RELOC_NDS32_GOTTPOFF},
+  {"TLSDESC",  BFD_RELOC_NDS32_TLS_DESC},
+};
+
 /* Implement md_parse_name.  */
 
 int
@@ -5854,35 +7918,37 @@ nds32_parse_name (char const *name, expressionS *exprP,
                  enum expr_mode mode ATTRIBUTE_UNUSED,
                  char *nextcharP ATTRIBUTE_UNUSED)
 {
-  char *suffix_table[] = { "GOTOFF", "GOT", "PLT" };
-  short unsigned int reloc_table [] =
-  {
-    BFD_RELOC_NDS32_GOTOFF, BFD_RELOC_NDS32_GOT20,
-    BFD_RELOC_NDS32_25_PLTREL
-  };
   segT segment;
 
   exprP->X_op_symbol = NULL;
   exprP->X_md = BFD_RELOC_UNUSED;
 
   exprP->X_add_symbol = symbol_find_or_make (name);
+  exprP->X_op = O_symbol;
+  exprP->X_add_number = 0;
 
+  /* Check the special name if a symbol.  */
   segment = S_GET_SEGMENT (exprP->X_add_symbol);
-  if (segment != undefined_section)
+  if ((segment != undefined_section) && (*nextcharP != '@'))
     return 0;
 
-  if (*nextcharP == '@')
+  if (strcmp (name, GOT_NAME) == 0 && *nextcharP != '@')
+    {
+      /* Set for _GOT_OFFSET_TABLE_.  */
+      exprP->X_md = BFD_RELOC_NDS32_GOTPC20;
+    }
+  else if (*nextcharP == '@')
     {
       size_t i;
       char *next;
       for (i = 0; i < ARRAY_SIZE (suffix_table); i++)
        {
-         next = input_line_pointer + 1 + strlen (suffix_table[i]);
-         if (strncasecmp (input_line_pointer + 1, suffix_table[i],
-                          strlen (suffix_table[i])) == 0
+         next = input_line_pointer + 1 + strlen (suffix_table[i].suffix);
+         if (strncasecmp (input_line_pointer + 1, suffix_table[i].suffix,
+                          strlen (suffix_table[i].suffix)) == 0
              && !is_part_of_name (*next))
            {
-             exprP->X_md = reloc_table[i];
+             exprP->X_md = suffix_table[i].reloc;
              *input_line_pointer = *nextcharP;
              input_line_pointer = next;
              *nextcharP = *input_line_pointer;
@@ -5892,9 +7958,6 @@ nds32_parse_name (char const *name, expressionS *exprP,
        }
     }
 
-  exprP->X_op = O_symbol;
-  exprP->X_add_number = 0;
-
   return 1;
 }
 
@@ -5903,18 +7966,18 @@ nds32_parse_name (char const *name, expressionS *exprP,
 int
 tc_nds32_regname_to_dw2regnum (char *regname)
 {
-  symbolS *sym = symbol_find (regname);
+  struct nds32_keyword *sym = hash_find (nds32_gprs_hash, regname);
+
+  if (!sym)
+    return -1;
 
-  if (S_GET_SEGMENT (sym) == reg_section
-      && sym->sy_value.X_add_number < 32)
-    return sym->sy_value.X_add_number;
-  return -1;
+  return sym->value;
 }
 
 void
 tc_nds32_frame_initial_instructions (void)
 {
   /* CIE */
-  /* Default cfa is register-28/sp.  */
+  /* Default cfa is register-31/sp.  */
   cfi_add_CFA_def_cfa (31, 0);
 }
This page took 0.123178 seconds and 4 git commands to generate.