NDS32: Code refactoring of relaxation.
authorKuan-Lin Chen <kuanlinchentw@gmail.com>
Thu, 11 Sep 2014 06:25:05 +0000 (14:25 +0800)
committerKuan-Lin Chen <kuanlinchentw@gmail.com>
Tue, 16 Sep 2014 05:08:00 +0000 (13:08 +0800)
Refactor each relaxation pattern to raise the maintainability.
In origin, all patterns is analysed in nds32_elf_relax_section,
so it is hard to debug and maintain.  Therefore, we classify all
patterns into different functions in this patch.
Moreover, we adjust all optimizations into nds32_elf_relax_section
to take these optimizations in turn.  This can promise all relaxation
being done after calling gld${EMULATION_NAME}_after_allocation.

13 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-nds32.c
bfd/elf32-nds32.h
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-nds32.c
gas/config/tc-nds32.h
include/elf/ChangeLog
include/elf/nds32.h
ld/ChangeLog
ld/emultempl/nds32elf.em

index 3fea46e..fcfdead 100644 (file)
@@ -1,3 +1,35 @@
+2014-09-16  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * bfd-in2.h: Regenerate.
+       * elf32-nds32.c (nds32_elf_mkobject): Hook bfd_elf32_mkobject.
+       (nds32_elf_relax_section): Code refactoring.
+       (nds32_elf_relax_longcall1, nds32_elf_relax_longcall2,
+       nds32_elf_relax_longcall3, nds32_elf_relax_longcall4,
+       nds32_elf_relax_longcall5, nds32_elf_relax_longcall6): Relax call
+       pattern. The first three is moved from nds32_elf_relax_section,
+       and the last three is new function.
+       (nds32_elf_relax_longjump1, nds32_elf_relax_longjump2,
+       nds32_elf_relax_longjump3, nds32_elf_relax_longjump4,
+       nds32_elf_relax_longjump5, nds32_elf_relax_longjump6,
+       nds32_elf_relax_longjump7): Relax condition branch pattern. The first
+       three is moved from nds32_elf_relax_section, and the last four
+       is new function.
+       (nds32_elf_relax_loadstore, nds32_elf_relax_lo12): Relax load-store
+       pattern and address setting pattern.
+       (nds32_elf_relax_piclo12, nds32_elf_relax_ptr,
+       nds32_elf_relax_pltgot_suff, nds32_elf_relax_got_suff,
+       nds32_elf_relax_gotoff_suff): Relax pic pattern.
+       (nds32_elf_relax_letlslo12, nds32_elf_relax_letlsadd,
+       nds32_elf_relax_letlsls): Relax TLS pattern.
+       (nds32_relax_adjust_label): Adjust alignment and nop.
+       (nds32_elf_pick_relax): Choose relaxation optimization.
+       (nds32_elf_get_relocated_section_contents): New hook.
+       (nds32_elf_order_insn_times, nds32_elf_ex9_build_itable): Release ex9
+       table 234th entry.
+       * elf32-nds32.h: Declare.
+       * libbfd.h: Regenerate.
+       * reloc.c: Add nds32 new relocations.
+
 2014-09-15  Chen Gang  <gang.chen.5i5j@gmail.com>
 
        * dwarf2.c (find_abstract_instance_name): Use 'form' instead of
index 1f1aed5..a40a14a 100644 (file)
@@ -3956,6 +3956,13 @@ and shift left by 0 for use in lbi.gp, sbi.gp...  */
   BFD_RELOC_NDS32_15_FIXED,
   BFD_RELOC_NDS32_17_FIXED,
   BFD_RELOC_NDS32_25_FIXED,
+  BFD_RELOC_NDS32_LONGCALL4,
+  BFD_RELOC_NDS32_LONGCALL5,
+  BFD_RELOC_NDS32_LONGCALL6,
+  BFD_RELOC_NDS32_LONGJUMP4,
+  BFD_RELOC_NDS32_LONGJUMP5,
+  BFD_RELOC_NDS32_LONGJUMP6,
+  BFD_RELOC_NDS32_LONGJUMP7,
 
 /* for PIC  */
   BFD_RELOC_NDS32_PLTREL_HI20,
@@ -4016,12 +4023,32 @@ This is a 5 bit absolute address.  */
   BFD_RELOC_NDS32_DIFF16,
   BFD_RELOC_NDS32_DIFF32,
   BFD_RELOC_NDS32_DIFF_ULEB128,
+  BFD_RELOC_NDS32_EMPTY,
+
+/* This is a 25 bit absolute address.  */
   BFD_RELOC_NDS32_25_ABS,
+
+/* For ex9 and ifc using.  */
   BFD_RELOC_NDS32_DATA,
   BFD_RELOC_NDS32_TRAN,
   BFD_RELOC_NDS32_17IFC_PCREL,
   BFD_RELOC_NDS32_10IFCU_PCREL,
 
+/* For TLS.  */
+  BFD_RELOC_NDS32_TPOFF,
+  BFD_RELOC_NDS32_TLS_LE_HI20,
+  BFD_RELOC_NDS32_TLS_LE_LO12,
+  BFD_RELOC_NDS32_TLS_LE_ADD,
+  BFD_RELOC_NDS32_TLS_LE_LS,
+  BFD_RELOC_NDS32_GOTTPOFF,
+  BFD_RELOC_NDS32_TLS_IE_HI20,
+  BFD_RELOC_NDS32_TLS_IE_LO12S2,
+  BFD_RELOC_NDS32_TLS_TPOFF,
+  BFD_RELOC_NDS32_TLS_LE_20,
+  BFD_RELOC_NDS32_TLS_LE_15S0,
+  BFD_RELOC_NDS32_TLS_LE_15S1,
+  BFD_RELOC_NDS32_TLS_LE_15S2,
+
 /* This is a 9-bit reloc  */
   BFD_RELOC_V850_9_PCREL,
 
index d1a2c30..4a0fad2 100644 (file)
@@ -17,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-   02110-1301, USA.*/
+   02110-1301, USA.  */
 
 
 #include "sysdep.h"
@@ -97,6 +97,7 @@ static bfd_boolean nds32_elf_finish_dynamic_sections
 static bfd_boolean nds32_elf_finish_dynamic_symbol
   (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
    Elf_Internal_Sym *);
+static bfd_boolean nds32_elf_mkobject (bfd *);
 
 /* Nds32 helper functions.  */
 static bfd_reloc_status_type nds32_elf_final_sda_base
@@ -111,15 +112,21 @@ static bfd_vma calculate_memory_address
 static int nds32_get_section_contents (bfd *, asection *, bfd_byte **);
 static bfd_boolean nds32_elf_ex9_build_hash_table
   (bfd *, asection *, struct bfd_link_info *);
+static bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *);
+static void nds32_elf_ex9_import_table (struct bfd_link_info *);
+static void nds32_elf_ex9_finish (struct bfd_link_info *);
+static void nds32_elf_ex9_reloc_jmp (struct bfd_link_info *);
 static void nds32_elf_get_insn_with_reg
-  (Elf_Internal_Rela *, unsigned long, unsigned long *);
+  (Elf_Internal_Rela *, uint32_t, uint32_t *);
 static int nds32_get_local_syms (bfd *, asection *ATTRIBUTE_UNUSED,
                                 Elf_Internal_Sym **);
 static bfd_boolean nds32_elf_ex9_replace_instruction
   (struct bfd_link_info *, bfd *, asection *);
 static bfd_boolean nds32_elf_ifc_calc (struct bfd_link_info *, bfd *,
                                       asection *);
+static bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *);
 static bfd_boolean nds32_elf_ifc_replace (struct bfd_link_info *);
+static bfd_boolean nds32_elf_ifc_reloc (void);
 static bfd_boolean  nds32_relax_fp_as_gp
   (struct bfd_link_info *link_info, bfd *abfd, asection *sec,
    Elf_Internal_Rela *internal_relocs, Elf_Internal_Rela *irelend,
@@ -127,6 +134,13 @@ static bfd_boolean  nds32_relax_fp_as_gp
 static bfd_boolean nds32_fag_remove_unused_fpbase
   (bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs,
    Elf_Internal_Rela *irelend);
+static bfd_byte *
+nds32_elf_get_relocated_section_contents (bfd *abfd,
+                                         struct bfd_link_info *link_info,
+                                         struct bfd_link_order *link_order,
+                                         bfd_byte *data,
+                                         bfd_boolean relocatable,
+                                         asymbol **symbols);
 
 enum
 {
@@ -181,13 +195,31 @@ enum
 #define PLT_PIC_ENTRY_WORD4  0x45000000                /* movi   r16, sizeof(RELA) * n      */
 #define PLT_PIC_ENTRY_WORD5  0x48000000                /* j      .plt0                      */
 
+/* These are macros used to get the relocation accurate value.  */
+#define ACCURATE_8BIT_S1       (0x100)
+#define ACCURATE_U9BIT_S1      (0x400)
+#define ACCURATE_12BIT_S1      (0x2000)
+#define ACCURATE_14BIT_S1      (0x4000)
+#define ACCURATE_19BIT         (0x40000)
+
+/* These are macros used to get the relocation conservative value.  */
+#define CONSERVATIVE_8BIT_S1   (0x100 - 4)
+#define CONSERVATIVE_14BIT_S1  (0x4000 - 4)
+#define CONSERVATIVE_16BIT_S1  (0x10000 - 4)
+#define CONSERVATIVE_24BIT_S1  (0x1000000 - 4)
+/* These must be more conservative because the address may be in
+   different segment.  */
+#define CONSERVATIVE_15BIT     (0x4000 - 0x1000)
+#define CONSERVATIVE_15BIT_S1  (0x8000 - 0x1000)
+#define CONSERVATIVE_15BIT_S2  (0x10000 - 0x1000)
+#define CONSERVATIVE_19BIT     (0x40000 - 0x1000)
+#define CONSERVATIVE_20BIT     (0x80000 - 0x1000)
+
 /* Size of small data/bss sections, used to calculate SDA_BASE.  */
 static long got_size = 0;
 static int is_SDA_BASE_set = 0;
 static int is_ITB_BASE_set = 0;
 
-static int relax_active = 0;
-
 /* Convert ELF-VER in eflags to string for debugging purpose.  */
 static const char *const nds32_elfver_strtab[] =
 {
@@ -243,6 +275,12 @@ struct elf_nds32_link_hash_entry
 
   /* Track dynamic relocs copied for this symbol.  */
   struct elf_nds32_dyn_relocs *dyn_relocs;
+
+  /* For checking relocation type.  */
+#define GOT_UNKNOWN     0
+#define GOT_NORMAL      1
+#define GOT_TLS_IE      2
+  unsigned int tls_type;
 };
 
 /* Get the nds32 ELF linker hash table from a link_info structure.  */
@@ -251,6 +289,32 @@ struct elf_nds32_link_hash_entry
 static int check_start_export_sym = 0;
 static size_t ex9_relax_size = 0;              /* Save ex9 predicted reducing size.  */
 
+/* The offset for executable tls relaxation.  */
+#define TP_OFFSET 0x0
+
+struct elf_nds32_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+};
+
+#define elf_nds32_tdata(bfd) \
+  ((struct elf_nds32_obj_tdata *) (bfd)->tdata.any)
+
+#define elf32_nds32_local_got_tls_type(bfd) \
+  (elf_nds32_tdata (bfd)->local_got_tls_type)
+
+#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent))
+
+static bfd_boolean
+nds32_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_nds32_obj_tdata),
+                                 NDS32_ELF_DATA);
+}
+
 /* Relocations used for relocation.  */
 static reloc_howto_type nds32_elf_howto_table[] =
 {
@@ -1704,6 +1768,234 @@ static reloc_howto_type nds32_elf_howto_table[] =
         0x1ff,                 /* src_mask */
         0x1ff,                 /* dst_mask */
         TRUE),                 /* pcrel_offset */
+
+  /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol.  */
+  HOWTO (R_NDS32_TLS_LE_HI20,  /* type */
+        12,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_HI20", /* name */
+        FALSE,                 /* partial_inplace */
+        0x000fffff,            /* src_mask */
+        0x000fffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_LO12,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_LO12", /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol.  */
+  HOWTO (R_NDS32_TLS_IE_HI20,  /* type */
+        12,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_IE_HI20", /* name */
+        FALSE,                 /* partial_inplace */
+        0x000fffff,            /* src_mask */
+        0x000fffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_IE_LO12S2,        /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        10,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_IE_LO12S2",       /* name */
+        FALSE,                 /* partial_inplace */
+        0x000003ff,            /* src_mask */
+        0x000003ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* Mark a TLS IE entry in GOT.  */
+  HOWTO (R_NDS32_TLS_TPOFF,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,    /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_TPOFF",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* A 20 bit address.  */
+  HOWTO (R_NDS32_TLS_LE_20,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_20",   /* name */
+        FALSE,         /* partial_inplace */
+        0xfffff,               /* src_mask */
+        0xfffff,               /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S0,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S0", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S1,  /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S1", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S2,  /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S2", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for unconditional call sequence  */
+  HOWTO (R_NDS32_LONGCALL4,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL4",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional call sequence.  */
+  HOWTO (R_NDS32_LONGCALL5,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL5",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional call sequence.  */
+  HOWTO (R_NDS32_LONGCALL6,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL6",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for unconditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP4,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP4",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP5,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP5",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP6,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP6",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP7,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP7",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 /* Relocations used for relaxation.  */
@@ -1956,6 +2248,45 @@ static reloc_howto_type nds32_elf_relax_howto_table[] =
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_ADD,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_TLS_LE_ADD",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_LS,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_TLS_LE_LS",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_EMPTY,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_EMPTY",               /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 \f
@@ -1967,7 +2298,7 @@ nds32_insertion_sort (void *base, size_t nmemb, size_t size,
                      int (*compar) (const void *lhs, const void *rhs))
 {
   char *ptr = (char *) base;
-  unsigned int i, j;
+  int i, j;
   char *tmp = alloca (size);
 
   /* If i is less than j, i is inserted before j.
@@ -1977,14 +2308,16 @@ nds32_insertion_sort (void *base, size_t nmemb, size_t size,
         sorted         unsorted
    */
 
-  for (i = 1; i < nmemb; i++)
+  for (i = 1; i < (int) nmemb; i++)
     {
-      for (j = 0; j < i; j++)
-       if (compar (ptr + i * size, ptr + j * size) < 0)
+      for (j = (i - 1); j >= 0; j--)
+       if (compar (ptr + i * size, ptr + j * size) >= 0)
          break;
 
+      j++;
+
       if (i == j)
-       continue; /* j is in order.  */
+       continue; /* i is in order.  */
 
       memcpy (tmp, ptr + i * size, size);
       memmove (ptr + (j + 1) * size, ptr + j * size, (i - j) * size);
@@ -2065,7 +2398,8 @@ nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 static bfd_reloc_status_type
 nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto,
                            asection *input_section, bfd_byte *data,
-                           bfd_vma offset, asection *symbol_section ATTRIBUTE_UNUSED,
+                           bfd_vma offset,
+                           asection *symbol_section ATTRIBUTE_UNUSED,
                            bfd_vma symbol_value, bfd_vma addend)
 {
   bfd_signed_vma relocation;
@@ -2084,7 +2418,7 @@ nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto,
      before doing pcrel calculations.  */
   relocation -= (offset & -(bfd_vma) 2);
 
-  if (relocation < -0x100 || relocation > 0xff)
+  if (relocation < -ACCURATE_8BIT_S1 || relocation >= ACCURATE_8BIT_S1)
     status = bfd_reloc_overflow;
   else
     status = bfd_reloc_ok;
@@ -2495,9 +2829,16 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1},
   {BFD_RELOC_NDS32_LONGCALL2, R_NDS32_LONGCALL2},
   {BFD_RELOC_NDS32_LONGCALL3, R_NDS32_LONGCALL3},
+  {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4},
+  {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5},
+  {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6},
   {BFD_RELOC_NDS32_LONGJUMP1, R_NDS32_LONGJUMP1},
   {BFD_RELOC_NDS32_LONGJUMP2, R_NDS32_LONGJUMP2},
   {BFD_RELOC_NDS32_LONGJUMP3, R_NDS32_LONGJUMP3},
+  {BFD_RELOC_NDS32_LONGJUMP4, R_NDS32_LONGJUMP4},
+  {BFD_RELOC_NDS32_LONGJUMP5, R_NDS32_LONGJUMP5},
+  {BFD_RELOC_NDS32_LONGJUMP6, R_NDS32_LONGJUMP6},
+  {BFD_RELOC_NDS32_LONGJUMP7, R_NDS32_LONGJUMP7},
   {BFD_RELOC_NDS32_LOADSTORE, R_NDS32_LOADSTORE},
   {BFD_RELOC_NDS32_9_FIXED, R_NDS32_9_FIXED_RELA},
   {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA},
@@ -2538,6 +2879,7 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_RELAX_REGION_END, R_NDS32_RELAX_REGION_END},
   {BFD_RELOC_NDS32_MINUEND, R_NDS32_MINUEND},
   {BFD_RELOC_NDS32_SUBTRAHEND, R_NDS32_SUBTRAHEND},
+  {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY},
 
   {BFD_RELOC_NDS32_DIFF8, R_NDS32_DIFF8},
   {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16},
@@ -2548,6 +2890,17 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_TRAN, R_NDS32_TRAN},
   {BFD_RELOC_NDS32_17IFC_PCREL, R_NDS32_17IFC_PCREL_RELA},
   {BFD_RELOC_NDS32_10IFCU_PCREL, R_NDS32_10IFCU_PCREL_RELA},
+  {BFD_RELOC_NDS32_TLS_LE_HI20, R_NDS32_TLS_LE_HI20},
+  {BFD_RELOC_NDS32_TLS_LE_LO12, R_NDS32_TLS_LE_LO12},
+  {BFD_RELOC_NDS32_TLS_LE_ADD, R_NDS32_TLS_LE_ADD},
+  {BFD_RELOC_NDS32_TLS_LE_LS, R_NDS32_TLS_LE_LS},
+  {BFD_RELOC_NDS32_TLS_IE_HI20, R_NDS32_TLS_IE_HI20},
+  {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2},
+  {BFD_RELOC_NDS32_TLS_TPOFF, R_NDS32_TLS_TPOFF},
+  {BFD_RELOC_NDS32_TLS_LE_20, R_NDS32_TLS_LE_20},
+  {BFD_RELOC_NDS32_TLS_LE_15S0, R_NDS32_TLS_LE_15S0},
+  {BFD_RELOC_NDS32_TLS_LE_15S1, R_NDS32_TLS_LE_15S1},
+  {BFD_RELOC_NDS32_TLS_LE_15S2, R_NDS32_TLS_LE_15S2},
 };
 
 /* Patch tag.  */
@@ -2802,7 +3155,7 @@ nds32_elf_add_symbol_hook (bfd *abfd,
 
 static asection *sda_rela_sec = NULL;
 
-#define SDA_SECTION_NUM 11
+#define SDA_SECTION_NUM 10
 
 static bfd_reloc_status_type
 nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
@@ -2811,6 +3164,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
   int relax_fp_as_gp;
   struct elf_nds32_link_hash_table *table;
   struct bfd_link_hash_entry *h, *h2;
+  long unsigned int total = 0;
 
   h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE);
   if (!h || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak))
@@ -2823,7 +3177,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
       static const char sec_name[SDA_SECTION_NUM][10] =
        {
          ".data", ".got", ".sdata_d", ".sdata_w", ".sdata_h", ".sdata_b",
-         ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d", ".bss"
+         ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d"
        };
       size_t i = 0;
 
@@ -2834,24 +3188,49 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
        }
 
       /* Get the first and final section.  */
-      while (i < sizeof (sec_name) / 10)
+      while (i < sizeof (sec_name) / sizeof (sec_name [0]))
        {
          temp = bfd_get_section_by_name (output_bfd, sec_name[i]);
          if (temp && !first && (temp->size != 0 || temp->rawsize != 0))
            first = temp;
          if (temp && (temp->size != 0 || temp->rawsize != 0))
            final = temp;
+
+         /* Summarize the sections in order to check if joining .bss.  */
+         if (temp && temp->size != 0)
+           total += temp->size;
+         else if (temp && temp->rawsize != 0)
+           total += temp->rawsize;
+
          i++;
        }
 
+      /* Check .bss size.  */
+      temp = bfd_get_section_by_name (output_bfd, ".bss");
+      if (temp)
+       {
+         if (temp->size != 0)
+           total += temp->size;
+         else if (temp->rawsize != 0)
+           total += temp->rawsize;
+
+         if (total < 0x80000)
+           {
+             if (!first && (temp->size != 0 || temp->rawsize != 0))
+               first = temp;
+             if ((temp->size != 0 || temp->rawsize != 0))
+               final = temp;
+           }
+       }
+
       if (first && final)
        {
          /* The middle of data region.  */
-         sda_base = (final->vma + final->rawsize + first->vma) / 2;
+         sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2;
 
          /* Find the section sda_base located.  */
          i = 0;
-         while (i < sizeof (sec_name) / 10)
+         while (i < sizeof (sec_name) / sizeof (sec_name [0]))
            {
              final = bfd_get_section_by_name (output_bfd, sec_name[i]);
              if (final && (final->size != 0 || final->rawsize != 0)
@@ -2876,7 +3255,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
              *psb = elf_gp (output_bfd);
              return bfd_reloc_ok;
            }
-         sda_base = first->vma;
+         sda_base = first->vma + first->rawsize;
        }
 
       sda_base -= first->vma;
@@ -2963,6 +3342,7 @@ nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
 
       eh = (struct elf_nds32_link_hash_entry *) ret;
       eh->dyn_relocs = NULL;
+      eh->tls_type = GOT_UNKNOWN;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -3453,6 +3833,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       asection *s;
       bfd_boolean dyn;
+      int tls_type = elf32_nds32_hash_entry (h)->tls_type;
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -3463,9 +3844,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        }
 
       s = htab->sgot;
-
       h->got.offset = s->size;
-      s->size += 4;
+
+      if (tls_type == GOT_UNKNOWN)
+       abort ();
+      else if (tls_type == GOT_NORMAL
+              || tls_type == GOT_TLS_IE)
+       /* Need a GOT slot.  */
+       s->size += 4;
+
       dyn = htab->root.dynamic_sections_created;
       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h))
        htab->srelgot->size += sizeof (Elf32_External_Rela);
@@ -4060,6 +4447,15 @@ nds32_elf_output_symbol_hook (struct bfd_link_info *info,
    section, which means that the addend must be adjusted
    accordingly.  */
 
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
 static bfd_boolean
 nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info * info,
@@ -4113,6 +4509,15 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
        return FALSE;
     }
 
+  if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON)
+    if (!nds32_elf_ifc_reloc ())
+      (*_bfd_error_handler) (_("error: IFC relocation error."));
+
+ /* Relocation for .ex9.itable.  */
+  if (table->target_optimize & NDS32_RELAX_EX9_ON
+      || (table->ex9_import_file && table->update_ex9_table))
+    nds32_elf_ex9_reloc_jmp (info);
+
   /* Use gp as fp to prevent truncated fit.  Because in relaxation time
      the fp value is set as gp, and it has be reverted for instruction
      setting fp.  */
@@ -4153,7 +4558,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          || r_type == R_NDS32_RELA_GNU_VTINHERIT
          || (r_type >= R_NDS32_INSN16 && r_type <= R_NDS32_25_FIXED_RELA)
          || r_type == R_NDS32_DATA
-         || r_type == R_NDS32_TRAN)
+         || r_type == R_NDS32_TRAN
+         || (r_type >= R_NDS32_LONGCALL4 && r_type <= R_NDS32_LONGJUMP6))
        continue;
 
       /* If we enter the fp-as-gp region.  Resolve the address of best fp-base.  */
@@ -4581,8 +4987,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          if (info->shared)
            {
              (*_bfd_error_handler)
-               (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared mode."),
-                bfd_get_filename (input_bfd));
+               (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared "
+                  "mode."), bfd_get_filename (input_bfd));
              return FALSE;
            }
          break;
@@ -4616,7 +5022,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                }
              else
                r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                             contents, offset, relocation, addend);
+                                             contents, offset, relocation,
+                                             addend);
            }
 
          goto check_reloc;
@@ -4789,6 +5196,101 @@ handle_sda:
          /* do nothing */
          break;
 
+       case R_NDS32_TLS_LE_HI20:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_LE_20:
+       case R_NDS32_TLS_LE_15S0:
+       case R_NDS32_TLS_LE_15S1:
+       case R_NDS32_TLS_LE_15S2:
+         if (elf_hash_table (info)->tls_sec != NULL)
+           relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET);
+         break;
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+         {
+           /* Relocation is to the entry for this symbol in the global
+              offset table.  */
+           unsigned int tls_type;
+           asection *srelgot;
+           Elf_Internal_Rela outrel;
+           bfd_vma off;
+           bfd_byte *loc;
+           int indx = 0;
+
+           BFD_ASSERT (sgot != NULL);
+           if (h != NULL)
+             {
+               bfd_boolean dyn;
+
+               off = h->got.offset;
+               BFD_ASSERT (off != (bfd_vma) - 1);
+               dyn = htab->root.dynamic_sections_created;
+               tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type;
+               if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+                   && (!info->shared
+                       || !SYMBOL_REFERENCES_LOCAL (info, h)))
+                 indx = h->dynindx;
+             }
+           else
+             {
+               /* Never happen currently.  */
+               BFD_ASSERT (local_got_offsets != NULL
+                           && local_got_offsets[r_symndx] != (bfd_vma) - 1);
+
+               off = local_got_offsets[r_symndx];
+
+               tls_type = elf32_nds32_local_got_tls_type (input_bfd)[r_symndx];
+             }
+           relocation = sgot->output_section->vma + sgot->output_offset + off;
+
+           if (r_type == R_NDS32_TLS_IE_LO12S2)
+             break;
+
+           /* The offset must always be a multiple of 4.  We use
+              the least significant bit to record whether we have
+              already processed this entry.  */
+           if ((off & 1) != 0)
+             off &= ~1;
+           else
+             {
+               bfd_boolean need_relocs = FALSE;
+               srelgot = htab->srelgot;
+               if ((info->shared || indx != 0)
+                   && (h == NULL
+                       || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                       || h->root.type != bfd_link_hash_undefweak))
+                 {
+                   need_relocs = TRUE;
+                   BFD_ASSERT (srelgot != NULL);
+                 }
+               if (tls_type & GOT_TLS_IE)
+                 {
+                   if (need_relocs)
+                     {
+                       if (h->dynindx == 0)
+                         outrel.r_addend = relocation - dtpoff_base (info);
+                       else
+                         outrel.r_addend = 0;
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset
+                                          + off);
+                       outrel.r_info =
+                         ELF32_R_INFO (h->dynindx, R_NDS32_TLS_TPOFF);
+
+                       loc = srelgot->contents;
+                       loc +=
+                         srelgot->reloc_count * sizeof (Elf32_External_Rela);
+                       bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                       ++srelgot->reloc_count;
+                     }
+                   else
+                     bfd_put_32 (output_bfd, h->root.u.def.value - TP_OFFSET,
+                                 sgot->contents + off);
+                 }
+             }
+         }
+       break;
+
          /* DON'T   fall through.  */
 
        default:
@@ -4855,8 +5357,16 @@ handle_sda:
        case R_NDS32_PLT_GOTREL_LO20:
        case R_NDS32_17IFC_PCREL_RELA:
        case R_NDS32_10IFCU_PCREL_RELA:
+       case R_NDS32_TLS_LE_HI20:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+       case R_NDS32_TLS_LE_20:
+       case R_NDS32_TLS_LE_15S0:
+       case R_NDS32_TLS_LE_15S1:
+       case R_NDS32_TLS_LE_15S2:
          /* Instruction related relocs must handle endian properly.  */
-         /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER */
+         /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER */
          r = nds32_elf_final_link_relocate (howto, input_bfd,
                                             input_section, contents,
                                             rel->r_offset, relocation,
@@ -5845,6 +6355,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       enum elf_nds32_reloc_type r_type;
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      int tls_type, old_tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -5858,7 +6369,9 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
-      /* Some relocs require a global offset table.  */
+      /* Some relocs require a global offset table.  We create
+        got section here, since these relocation need got section
+        and it is not created yet.  */
       if (htab->sgot == NULL)
        {
          switch (r_type)
@@ -5878,6 +6391,8 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_NDS32_GOTPC_HI20:
            case R_NDS32_GOTPC_LO12:
            case R_NDS32_GOT20:
+           case R_NDS32_TLS_IE_HI20:
+           case R_NDS32_TLS_IE_LO12S2:
              if (dynobj == NULL)
                htab->root.dynobj = dynobj = abfd;
              if (!create_got_section (dynobj, info))
@@ -5896,8 +6411,23 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_NDS32_GOT_LO15:
        case R_NDS32_GOT_LO19:
        case R_NDS32_GOT20:
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+         switch (r_type)
+           {
+           case R_NDS32_TLS_IE_HI20:
+           case R_NDS32_TLS_IE_LO12S2:
+             tls_type = GOT_TLS_IE;
+             break;
+           default:
+             tls_type = GOT_NORMAL;
+             break;
+           }
          if (h != NULL)
-           h->got.refcount += 1;
+           {
+             old_tls_type = elf32_nds32_hash_entry (h)->tls_type;
+             h->got.refcount += 1;
+           }
          else
            {
              bfd_signed_vma *local_got_refcounts;
@@ -5917,10 +6447,25 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
                }
              local_got_refcounts[r_symndx] += 1;
+             old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx];
            }
-         break;
 
-       case R_NDS32_9_PLTREL:
+         /* We will already have issued an error message if there
+            is a TLS/non-TLS mismatch, based on the symbol
+            type.  So just combine any TLS types needed.  */
+         if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
+             && tls_type != GOT_NORMAL)
+           tls_type |= old_tls_type;
+
+         if (old_tls_type != tls_type)
+           {
+             if (h != NULL)
+               elf32_nds32_hash_entry (h)->tls_type = tls_type;
+             else
+               elf32_nds32_local_got_tls_type (abfd)[r_symndx] = tls_type;
+           }
+         break;
+       case R_NDS32_9_PLTREL:
        case R_NDS32_25_PLTREL:
        case R_NDS32_PLTREL_HI20:
        case R_NDS32_PLTREL_LO12:
@@ -5944,6 +6489,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (h->forced_local)
            break;
 
+         elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL;
          h->needs_plt = 1;
          h->plt.refcount += 1;
          break;
@@ -6602,7 +7148,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
          else if (N32_IS_RT4 (insn) && N32_RT5 (insn) == N32_RA5 (insn)
                   && N32_IMM15S (insn) > -32)
            {
-             insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn), 0 - N32_IMM15S (insn));
+             insn16 = N16_TYPE45 (SUBI45, N32_RT54 (insn),
+                                  0 - N32_IMM15S (insn));
              insn_type = NDS32_INSN_SUBI45;
            }
          else if (mach >= MACH_V2 && N32_RT5 (insn) == REG_SP
@@ -6727,7 +7274,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
       else if (mach >= MACH_V2 && N32_IS_RT4 (insn) && N32_RA5 (insn) == REG_R8
               && -32 <= N32_IMM15S (insn) && N32_IMM15S (insn) < 0)
        {
-         insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn), N32_IMM15S (insn) + 32);
+         insn16 = N16_TYPE45 (LWI45_FE, N32_RT54 (insn),
+                              N32_IMM15S (insn) + 32);
          insn_type = NDS32_INSN_LWI45_FE;
        }
       break;
@@ -6741,7 +7289,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
       else if (N32_IS_RT3 (insn) && N32_IS_RA3 (insn)
               && IS_WITHIN_U (N32_IMM15S (insn), 3))
        {
-         insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn), N32_IMM15S (insn));
+         insn16 = N16_TYPE333 (SWI333, N32_RT5 (insn), N32_RA5 (insn),
+                               N32_IMM15S (insn));
          insn_type = NDS32_INSN_SWI333;
        }
       else if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_FP
@@ -6863,7 +7412,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
              insn16 = N16_TYPE38 (BEQZ38, N32_RT5 (insn), N32_IMM16S (insn));
              insn_type = NDS32_INSN_BEQZ38;
            }
-         else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8))
+         else if (N32_RT5 (insn) == REG_R15
+                  && IS_WITHIN_S (N32_IMM16S (insn), 8))
            {
              insn16 = N16_TYPE8 (BEQZS8, N32_IMM16S (insn));
              insn_type = NDS32_INSN_BEQZS8;
@@ -6876,7 +7426,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
              insn16 = N16_TYPE38 (BNEZ38, N32_RT5 (insn), N32_IMM16S (insn));
              insn_type = NDS32_INSN_BNEZ38;
            }
-         else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8))
+         else if (N32_RT5 (insn) == REG_R15
+                  && IS_WITHIN_S (N32_IMM16S (insn), 8))
            {
              insn16 = N16_TYPE8 (BNEZS8, N32_IMM16S (insn));
              insn_type = NDS32_INSN_BNEZS8;
@@ -7026,71 +7577,88 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
   switch (__GF (insn16, 9, 6))
     {
     case 0x4:                  /* add45 */
-      insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16), N16_RA5 (insn16));
+      insn = N32_ALU1 (ADD, N16_RT4 (insn16), N16_RT4 (insn16),
+                      N16_RA5 (insn16));
       goto done;
     case 0x5:                  /* sub45 */
-      insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16), N16_RA5 (insn16));
+      insn = N32_ALU1 (SUB, N16_RT4 (insn16), N16_RT4 (insn16),
+                      N16_RA5 (insn16));
       goto done;
     case 0x6:                  /* addi45 */
-      insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16));
+      insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16),
+                       N16_IMM5U (insn16));
       goto done;
     case 0x7:                  /* subi45 */
-      insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16), -N16_IMM5U (insn16));
+      insn = N32_TYPE2 (ADDI, N16_RT4 (insn16), N16_RT4 (insn16),
+                       -N16_IMM5U (insn16));
       goto done;
     case 0x8:                  /* srai45 */
-      insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16));
+      insn = N32_ALU1 (SRAI, N16_RT4 (insn16), N16_RT4 (insn16),
+                      N16_IMM5U (insn16));
       goto done;
     case 0x9:                  /* srli45 */
-      insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16), N16_IMM5U (insn16));
+      insn = N32_ALU1 (SRLI, N16_RT4 (insn16), N16_RT4 (insn16),
+                      N16_IMM5U (insn16));
       goto done;
-
     case 0xa:                  /* slli333 */
-      insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_ALU1 (SLLI, N16_RT3 (insn16), N16_RA3 (insn16),
+                      N16_IMM3U (insn16));
       goto done;
     case 0xc:                  /* add333 */
-      insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16), N16_RB3 (insn16));
+      insn = N32_ALU1 (ADD, N16_RT3 (insn16), N16_RA3 (insn16),
+                      N16_RB3 (insn16));
       goto done;
     case 0xd:                  /* sub333 */
-      insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16), N16_RB3 (insn16));
+      insn = N32_ALU1 (SUB, N16_RT3 (insn16), N16_RA3 (insn16),
+                      N16_RB3 (insn16));
       goto done;
     case 0xe:                  /* addi333 */
-      insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0xf:                  /* subi333 */
-      insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16), -N16_IMM3U (insn16));
+      insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       -N16_IMM3U (insn16));
       goto done;
-
     case 0x10:                 /* lwi333 */
-      insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (LWI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x12:                 /* lhi333 */
-      insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (LHI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x13:                 /* lbi333 */
-      insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (LBI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x11:                 /* lwi333.bi */
-      insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (LWI_BI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x14:                 /* swi333 */
-      insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (SWI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x16:                 /* shi333 */
-      insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (SHI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x17:                 /* sbi333 */
-      insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (SBI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
     case 0x15:                 /* swi333.bi */
-      insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16), N16_IMM3U (insn16));
+      insn = N32_TYPE2 (SWI_BI, N16_RT3 (insn16), N16_RA3 (insn16),
+                       N16_IMM3U (insn16));
       goto done;
-
     case 0x18:                 /* addri36.sp */
-      insn = N32_TYPE2 (ADDI, REG_SP, N16_RT3 (insn16), N16_IMM6U (insn16) << 2);
+      insn = N32_TYPE2 (ADDI, N16_RT3 (insn16), REG_SP,
+                       N16_IMM6U (insn16) << 2);
       goto done;
-
     case 0x19:                 /* lwi45.fe */
-      insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8, (32 - N16_IMM5U (insn16)) << 2);
+      insn = N32_TYPE2 (LWI, N16_RT4 (insn16), REG_R8,
+                       (N16_IMM5U (insn16) - 32));
       goto done;
     case 0x1a:                 /* lwi450 */
       insn = N32_TYPE2 (LWI, N16_RT4 (insn16), N16_RA5 (insn16), 0);
@@ -7099,7 +7667,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       insn = N32_TYPE2 (SWI, N16_RT4 (insn16), N16_RA5 (insn16), 0);
       goto done;
 
-    /* These are r15 implied instructions.  */
+      /* These are r15 implied instructions.  */
     case 0x30:                 /* slts45 */
       insn = N32_ALU1 (SLTS, REG_TA, N16_RT4 (insn16), N16_RA5 (insn16));
       goto done;
@@ -7132,30 +7700,35 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       goto done;
 
     case 0x3f:                 /* MISC33 */
-      switch (insn & 0x7)
+      switch (insn16 & 0x7)
        {
        case 2:                 /* neg33 */
          insn = N32_TYPE2 (SUBRI, N16_RT3 (insn16), N16_RA3 (insn16), 0);
          break;
        case 3:                 /* not33 */
-         insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 4:                 /* mul33 */
-         insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 5:                 /* xor33 */
-         insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 6:                 /* and33 */
-         insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 7:                 /* or33 */
-         insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        }
       goto done;
 
-    case 0xb:                  /* ... */
+    case 0xb:
       switch (insn16 & 0x7)
        {
        case 0:                 /* zeb33 */
@@ -7178,11 +7751,11 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
          break;
        case 6:                 /* bmski33 */
          insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16),
-                           1 << N16_IMM3U (insn16));
+                           1 << __GF (insn16, 3, 3));
          break;
        case 7:                 /* fexti33 */
          insn = N32_TYPE2 (ANDI, N16_RT3 (insn16), N16_RT3 (insn16),
-                           (1 << (N16_IMM3U (insn16) + 1)) - 1);
+                           (1 << (__GF (insn16, 3, 3) + 1)) - 1);
          break;
        }
       goto done;
@@ -7193,9 +7766,9 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
     case 0x0:                  /* mov55 or ifret16 */
       if (mach >= MACH_V3 && N16_RT5 (insn16) == REG_SP
          && N16_RT5 (insn16) == N16_RA5 (insn16))
-         insn = N32_JREG (JR, 0, 0, 0, 3);
+       insn = N32_JREG (JR, 0, 0, 0, 3);
       else
-         insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0);
+       insn = N32_TYPE2 (ADDI, N16_RT5 (insn16), N16_RA5 (insn16), 0);
       goto done;
     case 0x1:                  /* movi55 */
       insn = N32_TYPE1 (MOVI, N16_RT5 (insn16), N16_IMM5S (insn16));
@@ -7582,7 +8155,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
   /* Find the first relocation of the same relocation-type,
      so we iteratie them forward.  */
   pc_rel = reloc;
-  while ((pc_rel - 1) > internal_relocs && pc_rel[-1].r_offset == offset)
+  while ((pc_rel - 1) >= internal_relocs && pc_rel[-1].r_offset == offset)
     pc_rel--;
 
   for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++)
@@ -7594,19 +8167,29 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
        {
          off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr,
                                  &pic_ext_target);
-         if (off > 0xff || off < -0x100 || off == 0)
+         if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1
+             || off == 0)
            return FALSE;
          break;
        }
       else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA)
        {
          /* movi => movi55  */
-         mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, symtab_hdr);
-         /* mem_addr is unsigned, but the value should be between [-16, 15].  */
+         mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf,
+                                              symtab_hdr);
+         /* mem_addr is unsigned, but the value should
+            be between [-16, 15].  */
          if ((mem_addr + 0x10) >> 5)
            return FALSE;
          break;
        }
+      else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_20)
+              || (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_LO12))
+       {
+         /* It never happen movi to movi55 for R_NDS32_TLS_LE_20,
+            because it can be relaxed to addi for TLS_LE_ADD.  */
+         return FALSE;
+       }
       else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA
                || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA)
               && (reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG)
@@ -7624,9 +8207,18 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
               || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_LOADSTORE)
                   && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_DWARF2_OP1_RELA)))
        {
-         /* Prevent unresolved addi instruction translate to addi45 or addi333.  */
+         /* Prevent unresolved addi instruction translate
+            to addi45 or addi333.  */
          return FALSE;
        }
+      else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA))
+       {
+         off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr,
+                                 &pic_ext_target);
+         if (off >= ACCURATE_U9BIT_S1 || off <= 0)
+           return FALSE;
+         break;
+       }
     }
 
   return TRUE;
@@ -7669,6 +8261,9 @@ nds32_elf_write_16 (bfd *abfd ATTRIBUTE_UNUSED, bfd_byte *contents,
               || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA)
        pc_rel->r_info =
          ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_SDA_FP7U2_RELA);
+      else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA))
+       pc_rel->r_info =
+         ELF32_R_INFO (ELF32_R_SYM (pc_rel->r_info), R_NDS32_10IFCU_PCREL_RELA);
     }
 }
 
@@ -7695,7 +8290,7 @@ find_relocs_at_address (Elf_Internal_Rela *reloc,
     if (ELF32_R_TYPE (rel_t->r_info) == reloc_type)
       return rel_t;
 
-  /* We didn't find it backward. Try find it forward.  */
+  /* We didn't find it backward.  Try find it forward.  */
   for (rel_t = reloc;
        rel_t < irelend && rel_t->r_offset == reloc->r_offset;
        rel_t++)
@@ -7985,7 +8580,7 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
                               nds32_elf_blank_t *blank_p)
 {
   Elf_Internal_Shdr *symtab_hdr;       /* Symbol table header of this bfd.  */
-  Elf_Internal_Sym *isym = NULL;               /* Symbol table of this bfd.  */
+  Elf_Internal_Sym *isym = NULL;       /* Symbol table of this bfd.  */
   Elf_Internal_Sym *isymend;           /* Symbol entry iterator.  */
   unsigned int sec_shndx;              /* The section the be relaxed.  */
   bfd_byte *contents;                  /* Contents data of iterating section.  */
@@ -8066,18 +8661,28 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
              && isym[ELF32_R_SYM (irel->r_info)].st_shndx == sec_shndx)
            {
              unsigned long val = 0;
-             unsigned long before, between;
+             unsigned long mask;
+             long before, between;
+             long offset;
 
              switch (ELF32_R_TYPE (irel->r_info))
                {
                case R_NDS32_DIFF8:
-                 val = bfd_get_8 (abfd, contents + irel->r_offset);
+                 offset = bfd_get_8 (abfd, contents + irel->r_offset);
                  break;
                case R_NDS32_DIFF16:
-                 val = bfd_get_16 (abfd, contents + irel->r_offset);
+                 offset = bfd_get_16 (abfd, contents + irel->r_offset);
                  break;
                case R_NDS32_DIFF32:
                  val = bfd_get_32 (abfd, contents + irel->r_offset);
+                 /* Get the signed bit and mask for the high part.  The
+                    gcc will alarm when right shift 32-bit since the
+                    type size of long may be 32-bit.  */
+                 mask = 0 - (val >> 31);
+                 if (mask)
+                   offset = (val | (mask - 0xffffffff));
+                 else
+                   offset = val;
                  break;
                default:
                  BFD_ASSERT (0);
@@ -8090,23 +8695,28 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
                -- before ---| *****************
                --------------------- between ---|
 
-               We only care how much data are relax between DIFF, marked as ***.  */
+               We only care how much data are relax between DIFF,
+               marked as ***.  */
 
              before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0);
-             between = get_nds32_elf_blank_total (&blank_t, irel->r_addend + val, 0);
+             between = get_nds32_elf_blank_total (&blank_t,
+                                                  irel->r_addend + offset, 0);
              if (between == before)
                goto done_adjust_diff;
 
              switch (ELF32_R_TYPE (irel->r_info))
                {
                case R_NDS32_DIFF8:
-                 bfd_put_8 (abfd, val - (between - before), contents + irel->r_offset);
+                 bfd_put_8 (abfd, offset - (between - before),
+                            contents + irel->r_offset);
                  break;
                case R_NDS32_DIFF16:
-                 bfd_put_16 (abfd, val - (between - before), contents + irel->r_offset);
+                 bfd_put_16 (abfd, offset - (between - before),
+                             contents + irel->r_offset);
                  break;
                case R_NDS32_DIFF32:
-                 bfd_put_32 (abfd, val - (between - before), contents + irel->r_offset);
+                 bfd_put_32 (abfd, offset - (between - before),
+                             contents + irel->r_offset);
                  break;
                }
            }
@@ -8118,10 +8728,12 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
              unsigned long before, between;
              bfd_byte *endp, *p;
 
-             val = read_unsigned_leb128 (abfd, contents + irel->r_offset, &len);
+             val = read_unsigned_leb128 (abfd, contents + irel->r_offset,
+                                         &len);
 
              before = get_nds32_elf_blank_total (&blank_t, irel->r_addend, 0);
-             between = get_nds32_elf_blank_total (&blank_t, irel->r_addend + val, 0);
+             between = get_nds32_elf_blank_total (&blank_t,
+                                                  irel->r_addend + val, 0);
              if (between == before)
                goto done_adjust_diff;
 
@@ -8138,14 +8750,17 @@ done_adjust_diff:
          if (sec == sect)
            {
              raddr = irel->r_offset;
-             irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, irel->r_offset, 1);
+             irel->r_offset -= get_nds32_elf_blank_total (&blank_t2,
+                                                          irel->r_offset, 1);
 
              if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE)
                continue;
              if (blank_t2 && blank_t2->next
-                 && (blank_t2->offset > raddr || blank_t2->next->offset <= raddr))
-               (*_bfd_error_handler) (_("%B: %s\n"), abfd,
-                                      "Error: search_nds32_elf_blank reports wrong node");
+                 && (blank_t2->offset > raddr
+                     || blank_t2->next->offset <= raddr))
+               (*_bfd_error_handler)
+                 (_("%B: %s\n"), abfd,
+                  "Error: search_nds32_elf_blank reports wrong node");
 
              /* Mark reloc in deleted portion as NONE.
                 For some relocs like R_NDS32_LABEL that doesn't modify the
@@ -8197,9 +8812,11 @@ done_adjust_diff:
              isym->st_value -= ahead;
 
              /* Adjust function size.  */
-             if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC && isym->st_size > 0)
-               isym->st_size -= get_nds32_elf_blank_total
-                                  (&blank_t, orig_addr + isym->st_size, 0) - ahead;
+             if (ELF32_ST_TYPE (isym->st_info) == STT_FUNC
+                 && isym->st_size > 0)
+               isym->st_size -=
+                 get_nds32_elf_blank_total
+                 (&blank_t, orig_addr + isym->st_size, 0) - ahead;
            }
        }
     }
@@ -8228,8 +8845,9 @@ done_adjust_diff:
 
              /* Adjust function size.  */
              if (sym_hash->type == STT_FUNC)
-               sym_hash->size -= get_nds32_elf_blank_total
-                                   (&blank_t, orig_addr + sym_hash->size, 0) - ahead;
+               sym_hash->size -=
+                 get_nds32_elf_blank_total
+                 (&blank_t, orig_addr + sym_hash->size, 0) - ahead;
 
            }
        }
@@ -8323,8 +8941,9 @@ nds32_get_local_syms (bfd *abfd, asection *sec ATTRIBUTE_UNUSED,
 }
 
 /* Range of small data.  */
-static bfd_vma sdata_range[5][2];
-static bfd_vma const sdata_init_range[5] = { 0x2000, 0x4000, 0x8000, 0x10000, 0x40000 };
+static bfd_vma sdata_range[2][2];
+static bfd_vma const sdata_init_range[2] =
+{ ACCURATE_12BIT_S1, ACCURATE_19BIT };
 
 static int
 nds32_elf_insn_size (bfd *abfd ATTRIBUTE_UNUSED,
@@ -8348,9 +8967,9 @@ relax_range_measurement (bfd *abfd)
   /* For upper bound.   */
   bfd_vma maxpgsz = get_elf_backend_data (abfd)->maxpagesize;
   bfd_vma align;
-  bfd_vma init_range;
   static int decide_relax_range = 0;
   int i;
+  int range_number = sizeof (sdata_init_range) / sizeof (sdata_init_range[0]);
 
   if (decide_relax_range)
     return;
@@ -8359,7 +8978,7 @@ relax_range_measurement (bfd *abfd)
   if (sda_rela_sec == NULL)
     {
       /* Since there is no data sections, we assume the range is page size.  */
-      for (i = 0; i < 5; i++)
+      for (i = 0; i < range_number; i++)
        {
          sdata_range[i][0] = sdata_init_range[i] - 0x1000;
          sdata_range[i][1] = sdata_init_range[i] - 0x1000;
@@ -8380,12 +8999,11 @@ relax_range_measurement (bfd *abfd)
 
   /* I guess we can not determine the section before
      gp located section, so we assume the align is max page size.  */
-  for (i = 0; i < 5; i++)
+  for (i = 0; i < range_number; i++)
     {
-      init_range = sdata_init_range[i];
-      sdata_range[i][1] = init_range - align;
+      sdata_range[i][1] = sdata_init_range[i] - align;
       BFD_ASSERT (sdata_range[i][1] <= sdata_init_range[i]);
-      sdata_range[i][0] = init_range - maxpgsz;
+      sdata_range[i][0] = sdata_init_range[i] - maxpgsz;
       BFD_ASSERT (sdata_range[i][0] <= sdata_init_range[i]);
     }
 }
@@ -8397,2561 +9015,3284 @@ relax_range_measurement (bfd *abfd)
 #define IS_OPTIMIZE(addend)     ((addend) & 0x40000000)
 #define IS_16BIT_ON(addend)     ((addend) & 0x20000000)
 
+/* Relax LONGCALL1 relocation for nds32_elf_relax_section.  */
+
 static bfd_boolean
-nds32_elf_relax_section (bfd *abfd, asection *sec,
-                        struct bfd_link_info *link_info, bfd_boolean *again)
-{
-  nds32_elf_blank_t *relax_blank_list = NULL;
-  Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Rela *irelend;
-  Elf_Internal_Sym *isymbuf = NULL;
-  bfd_byte *contents = NULL;
-  bfd_boolean result = TRUE;
-  int optimize = 0;
-  int optimize_for_space ATTRIBUTE_UNUSED = 0;
-  int optimize_for_space_no_align ATTRIBUTE_UNUSED = 0;
-  int insn_opt = 0;
-  int i;
+nds32_elf_relax_longcall1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGCALL1
+     case 4-4-2; 16-bit on, optimize off or optimize for space
+     sethi ta, hi20(symbol)     ; LONGCALL1/HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jral5 ta                   ;
+
+     case 4-4-4; 16-bit off, optimize don't care
+     sethi ta, hi20(symbol)     ; LONGCALL1/HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jral  ta                   ;
+
+     case 4-4-4; 16-bit on, optimize for speed
+     sethi ta, hi20(symbol)     ; LONGCALL1/HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jral  ta                   ;
+     Check code for -mlong-calls output.  */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
   uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
   uint16_t insn16;
-  bfd_vma local_sda;
-
-  /* Target dependnet option.  */
-  struct elf_nds32_link_hash_table *table;
-  int load_store_relax;
-  int relax_round;
 
-  relax_blank_list = NULL;
-
-  *again = FALSE;
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-  /* Nothing to do for
-   * relocatable link or
-   * non-relocatable section or
-   * non-code section or
-   * empty content or
-   * no reloc entry.  */
-  if (link_info->relocatable
-      || (sec->flags & SEC_RELOC) == 0
-      || (sec->flags & SEC_EXCLUDE) == 1
-      || (sec->flags & SEC_CODE) == 0
-      || sec->size == 0)
-    return TRUE;
+  hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_HI20_RELA, laddr);
+  lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_LO12S0_ORI_RELA,
+                                          laddr + 4);
 
-  /* 09.12.11 Workaround.  */
-  /*  We have to adjust align for R_NDS32_LABEL if needed.
-     The adjust approach only can fix 2-byte align once.  */
-  if (sec->alignment_power > 2)
+  if (hi_irelfn == irelend || lo_irelfn == irelend)
     {
       (*_bfd_error_handler)
-       (_("%B(%A): warning: relax is suppressed for sections "
-          "of alignment %d-bytes > 4-byte."),
-        abfd, sec, sec->alignment_power);
-      return TRUE;
+       ("%B: warning: R_NDS32_LONGCALL1 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
     }
 
-  /* The optimization type to do.  */
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-  table = nds32_elf_hash_table (link_info);
-  relax_round = table->relax_round;
-  switch (relax_round)
-    {
-    case NDS32_RELAX_JUMP_IFC_ROUND:
-      /* Here is the entrance of ifc jump relaxation.  */
-      if (!nds32_elf_ifc_calc (link_info, abfd, sec))
-       return FALSE;
-      return TRUE;
+  /* This condition only happened when symbol is undefined.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-    case NDS32_RELAX_EX9_BUILD_ROUND:
-      /* Here is the entrance of ex9 relaxation.  There are two pass of
-        ex9 relaxation.  The one is to traverse all instructions and build
-        the hash table.  The other one is to compare instructions and replace
-        it by ex9.it.  */
-      if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info))
-       return FALSE;
-      return TRUE;
+  /* Relax to: jal symbol; 25_PCREL */
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
+
+  /* Replace the long call with a jal.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                              R_NDS32_25_PCREL_RELA);
+  irel->r_addend = hi_irelfn->r_addend;
+
+  /* We don't resolve this here but resolve it in relocate_section.  */
+  insn = INSN_JAL;
+  bfd_putb32 (insn, contents + irel->r_offset);
+
+  hi_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+  lo_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
+  *insn_len = 4;
+
+  if (seq_len & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16);
+      lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  return TRUE;
+}
 
-    case NDS32_RELAX_EX9_REPLACE_ROUND:
-      if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec))
-       return FALSE;
-      return TRUE;
+#define CONVERT_CONDITION_CALL(insn) (((insn) & 0xffff0000) ^ 0x90000)
+/* Relax LONGCALL2 relocation for nds32_elf_relax_section.  */
 
-    default:
-      if (sec->reloc_count == 0)
-       return TRUE;
-      break;
-    }
+static bfd_boolean
+nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* bltz  rt, .L1   ; LONGCALL2
+     jal   symbol   ; 25_PCREL
+     .L1: */
 
-  /* The begining of general relaxation.  */
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-  if (is_SDA_BASE_set == 0)
-    {
-      bfd_vma gp;
-      is_SDA_BASE_set = 1;
-      nds32_elf_final_sda_base (sec->output_section->owner, link_info, &gp, FALSE);
-      relax_range_measurement (abfd);
-    }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-  if (is_ITB_BASE_set == 0)
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  i1_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_25_PCREL_RELA, laddr + 4);
+
+  if (i1_irelfn == irelend)
     {
-      /* Set the _ITB_BASE_.  */
-      if (!nds32_elf_ex9_itb_base (link_info))
-       {
-         (*_bfd_error_handler) (_("%B: error: Cannot set _ITB_BASE_"), abfd);
-         bfd_set_error (bfd_error_bad_value);
-       }
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
     }
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  /* Relocations MUST be kept in memory, because relaxation adjust them.  */
-  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                              TRUE /* keep_memory */);
-  if (internal_relocs == NULL)
-    goto error_return;
+  insn = bfd_getb32 (contents + laddr);
 
-  irelend = internal_relocs + sec->reloc_count;
-  irel =
-    find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                           R_NDS32_RELAX_ENTRY);
-  /* If 31th bit of addend of R_NDS32_RELAX_ENTRY is set,
-     this section is already relaxed.  */
-  if (irel == irelend)
-    return TRUE;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY)
-    {
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG)
-       return TRUE;
+  if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG)
-       optimize = 1;
+  /* Relax to  bgezal   rt, label ; 17_PCREL
+     or                bltzal   rt, label ; 17_PCREL */
+
+  /* Convert to complimentary conditional call.  */
+  insn = CONVERT_CONDITION_CALL (insn);
+
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
+
+  /* Clean unnessary relocations.  */
+  i1_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
+  cond_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_17_PCREL_RELA, laddr);
+  if (cond_irelfn != irelend)
+    cond_irelfn->r_info =
+      ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), R_NDS32_NONE);
+
+  /* Replace the long call with a bgezal.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
+                              R_NDS32_17_PCREL_RELA);
+  irel->r_addend = i1_irelfn->r_addend;
+
+  bfd_putb32 (insn, contents + irel->r_offset);
+
+  *insn_len = 4;
+  return TRUE;
+}
 
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG)
-       optimize_for_space = 1;
+/* Relax LONGCALL3 relocation for nds32_elf_relax_section.  */
+
+static bfd_boolean
+nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGCALL3
+     case 4-4-4-2; 16-bit on, optimize off or optimize for space
+     bltz  rt,   $1                ; LONGCALL3
+     sethi ta,   hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral5 ta                      ;
+     $1
+
+     case 4-4-4-4; 16-bit off, optimize don't care
+     bltz  rt,   $1                ; LONGCALL3
+     sethi ta,   hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral  ta                      ;
+     $1
+
+     case 4-4-4-4; 16-bit on, optimize for speed
+     bltz  rt,   $1                ; LONGCALL3
+     sethi ta,   hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral  ta                      ;
+     $1 */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint16_t insn16;
+
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
+
+  hi_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_HI20_RELA, laddr + 4);
+  lo_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_LO12S0_ORI_RELA, laddr + 8);
+
+  if (hi_irelfn == irelend || lo_irelfn == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
     }
 
-  relax_active = 1;
-  load_store_relax = table->load_store_relax;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-  /* Get symbol table and section content.  */
-  if (!nds32_get_section_contents (abfd, sec, &contents)
-      || !nds32_get_local_syms (abfd, sec, &isymbuf))
-    goto error_return;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-  /* Do relax loop only when finalize is not done.
-     Take care of relaxable relocs except INSN16.  */
-  for (irel = internal_relocs; irel < irelend; irel++)
+  insn = bfd_getb32 (contents + laddr);
+  if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
     {
-      bfd_vma laddr;
-      unsigned long comp_insn = 0;
-      unsigned short comp_insn16 = 0;
-      unsigned long i_mask = 0xffffffff;
-      int seq_len;             /* Original length of instruction sequence.  */
-      int insn_len = 0;                /* Final length of instruction sequence.  */
-      int convertible;         /* 1st insn convertible.  */
-      int insn16_on;           /* 16-bit on/off.  */
-      Elf_Internal_Rela *hi_irelfn = NULL;
-      Elf_Internal_Rela *lo_irelfn = NULL;
-      Elf_Internal_Rela *i1_irelfn = NULL;
-      Elf_Internal_Rela *i2_irelfn = NULL;
-      Elf_Internal_Rela *cond_irelfn = NULL;
-      int i1_offset = 0;
-      int i2_offset = 0;
-      bfd_signed_vma foff;
-      unsigned long reloc = R_NDS32_NONE;
-      int hi_off;
-      int insn_off;
-      int pic_ext_target = 0;
-      bfd_vma access_addr = 0;
-      bfd_vma range_l = 0, range_h = 0;        /* Upper/lower bound.  */
+      /* Relax to  bgezal   rt, label ; 17_PCREL
+        or        bltzal   rt, label ; 17_PCREL */
 
-      insn = 0;
-      insn16 = 0;
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
-         && (irel->r_addend & 0x1f) >= 2)
-       optimize = 1;
+      /* Convert to complimentary conditional call.  */
+      insn = CONVERT_CONDITION_CALL (insn);
+      bfd_putb32 (insn, contents + irel->r_offset);
 
-      /* Relocation Types
-        R_NDS32_LONGCALL1      53
-        R_NDS32_LONGCALL2      54
-        R_NDS32_LONGCALL3      55
-        R_NDS32_LONGJUMP1      56
-        R_NDS32_LONGJUMP2      57
-        R_NDS32_LONGJUMP3      58
-        R_NDS32_LOADSTORE      59  */
-      if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
-         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE)
+      *insn_len = 4;
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+      hi_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
+
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_17_PCREL_RELA, laddr);
+      if (cond_irelfn != irelend)
        {
-         seq_len = GET_SEQ_LEN (irel->r_addend);
-         insn_opt = IS_OPTIMIZE (irel->r_addend);
-         convertible = IS_1ST_CONVERT (irel->r_addend);
-         insn16_on = IS_16BIT_ON (irel->r_addend);
-         laddr = irel->r_offset;
+         cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                             R_NDS32_17_PCREL_RELA);
+         cond_irelfn->r_addend = hi_irelfn->r_addend;
        }
-      /* Relocation Types
-        R_NDS32_LO12S0_RELA            30
-        R_NDS32_LO12S1_RELA            29
-        R_NDS32_LO12S2_RELA            28
-        R_NDS32_LO12S2_SP_RELA         71
-        R_NDS32_LO12S2_DP_RELA         70
-        R_NDS32_GOT_LO12               46
-        R_NDS32_GOTOFF_LO12            50
-        R_NDS32_PLTREL_LO12            65
-        R_NDS32_PLT_GOTREL_LO12        67
-        R_NDS32_GOT_SUFF               193
-        R_NDS32_GOTOFF_SUFF            194
-        R_NDS32_PLT_GOT_SUFF           195
-        R_NDS32_MULCALL_SUFF           196
-        R_NDS32_PTR                    197  */
-      else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA
-               && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA)
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12
-              || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF
-                  && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR)
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTBLOCK
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA)
+
+      if (seq_len & 0x2)
        {
-         seq_len = 0;
-         insn_opt = IS_OPTIMIZE (irel->r_addend) > 0;
-         convertible = 0;
-         insn16_on = 0;
-         laddr = irel->r_offset;
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+         hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                           R_NDS32_INSN16);
+         hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+         insn_len += 2;
        }
-      else
-       continue;
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1)
+    {
+      /* Relax to the following instruction sequence
+        bltz  rt,   $1 ; LONGCALL2
+        jal   symbol   ; 25_PCREL
+        $1     */
+      *insn_len = 8;
+      insn = INSN_JAL;
+      bfd_putb32 (insn, contents + hi_irelfn->r_offset);
 
-      insn_len = seq_len;
+      hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                       R_NDS32_25_PCREL_RELA);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2);
+
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
 
-      if (laddr + seq_len > (bfd_vma) sec->size)
+      if (seq_len & 0x2)
        {
-         char *s = NULL;
-         int pass_check = 0;
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+         lo_irelfn->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16);
+         lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+         insn_len += 2;
+       }
+    }
+  return TRUE;
+}
 
-         if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
-             && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP3)
-           {
-             for (i1_irelfn = irel;
-                  i1_irelfn < irelend && i1_irelfn->r_offset < (laddr + seq_len - 4);
-                  i1_irelfn++)
-               ;
-
-             for (;
-                  i1_irelfn < irelend && i1_irelfn->r_offset == (laddr + seq_len - 4);
-                  i1_irelfn++)
-               if (ELF32_R_TYPE (i1_irelfn->r_info) == R_NDS32_INSN16)
-                 {
-                   pass_check = 1;
-                   break;
-                 }
-             i1_irelfn = NULL;
-           }
+/* Relax LONGJUMP1 relocation for nds32_elf_relax_section.  */
 
-         if (pass_check == 0)
-           {
-             reloc_howto_type *howto =
-               bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE
-                                                      (irel->r_info));
-             s = howto->name;
+static bfd_boolean
+nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGJUMP1
+     case 4-4-2; 16-bit bit on, optimize off or optimize for space
+     sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)  ; LO12S0
+     jr5   ta                    ;
+
+     case 4-4-4; 16-bit off, optimize don't care
+     sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)  ; LO12S0
+     jr    ta                    ;
+
+     case 4-4-4; 16-bit on, optimize for speed
+     sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)  ; LO12S0
+     jr    ta                    ;     */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  int insn16_on;       /* 16-bit on/off.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint16_t insn16;
+  unsigned long reloc;
 
-             (*_bfd_error_handler)
-              ("%B: warning: %s points to unrecognized insns at 0x%lx.",
-               abfd, s, (long) irel->r_offset);
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
+  insn16_on = IS_16BIT_ON (irel->r_addend);
+
+  hi_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_HI20_RELA, laddr);
+  lo_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_LO12S0_ORI_RELA, laddr + 4);
+  if (hi_irelfn == irelend || lo_irelfn == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-             continue;
-           }
-       }
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL1)
-       {
-         /* There are 3 variations for LONGCALL1
-            case 4-4-2; 16-bit on, optimize off or optimize for space
-            sethi ta, hi20(symbol)     ; LONGCALL1/HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jral5 ta                   ;
-
-            case 4-4-4; 16-bit off, optimize don't care
-            sethi ta, hi20(symbol)     ; LONGCALL1/HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jral  ta                   ;
-
-            case 4-4-4; 16-bit on, optimize for speed
-            sethi ta, hi20(symbol)     ; LONGCALL1/HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jral  ta                   ; (INSN16)
-            Check code for -mlong-calls output.  */
-
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_HI20_RELA, laddr);
-         lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_LO12S0_ORI_RELA,
-                                                  laddr + 4);
-         i1_offset = 8;
-
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                      R_NDS32_20_RELA, laddr);
-             i1_offset = 4;
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGCALL1 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
-                 continue;
-               }
-           }
+  if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         i1_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_INSN16,
-                                                  laddr + i1_offset);
+  if (insn16_on && foff >= -ACCURATE_8BIT_S1
+      && foff < ACCURATE_8BIT_S1 && (seq_len & 0x2))
+    {
+      /* j8    label */
+      /* 16-bit on, but not optimized for speed.  */
+      reloc = R_NDS32_9_PCREL_RELA;
+      insn16 = INSN_J8;
+      bfd_putb16 (insn16, contents + irel->r_offset);
+      *insn_len = 2;
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+    }
+  else
+    {
+      /* j     label */
+      reloc = R_NDS32_25_PCREL_RELA;
+      insn = INSN_J;
+      bfd_putb32 (insn, contents + irel->r_offset);
+      *insn_len = 4;
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16);
+      irel->r_addend = 0;
+    }
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+  hi_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
+  lo_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
+  if ((seq_len & 0x2) && ((*insn_len & 2) == 0))
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
+                     R_NDS32_INSN16);
+      lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  return TRUE;
+}
+
+/* Revert condition branch.  This function does not check if the input
+   instruction is condition branch or not.  */
+
+static void
+nds32_elf_convert_branch (uint16_t insn16, uint32_t insn,
+                          uint16_t *re_insn16, uint32_t *re_insn)
+{
+  uint32_t comp_insn = 0;
+  uint16_t comp_insn16 = 0;
+
+  if (insn)
+    {
+      if (N32_OP6 (insn) == N32_OP6_BR1)
+       {
+         /* beqs label.  */
+         comp_insn = (insn ^ 0x4000) & 0xffffc000;
+         if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5)
            {
-             continue;
+             /* Insn can be contracted to 16-bit implied r5.  */
+             comp_insn16 =
+               (comp_insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38;
+             comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
            }
-
-         /* Relax to
-            jal   symbol   ; 25_PCREL */
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
-
-         /* Replace the long call with a jal.  */
-         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                      R_NDS32_25_PCREL_RELA);
-         irel->r_addend = hi_irelfn->r_addend;
-
-         /* We don't resolve this here but resolve it in relocate_section.  */
-         insn = INSN_JAL;
-
-         bfd_putb32 (insn, contents + irel->r_offset);
-         hi_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-         lo_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-         insn_len = 4;
-         if (i1_irelfn != irelend)
+       }
+      else if (N32_OP6 (insn) == N32_OP6_BR3)
+       {
+         /* bnec $ta, imm11, label.  */
+         comp_insn = (insn ^ 0x80000) & 0xffffff00;
+       }
+      else
+       {
+         comp_insn = (insn ^ 0x10000) & 0xffffc000;
+         if (N32_BR2_SUB (insn) == N32_BR2_BEQZ
+             || N32_BR2_SUB (insn) == N32_BR2_BNEZ)
            {
-             if (!insn_opt
-                 && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
+             if (N32_IS_RT3 (insn))
                {
-                 /* The instruction pointed by R_NDS32_INSN16 is already
-                    turned into 16-bit instruction, so the total length of
-                    this sequence is decreased by 2.  */
-                 seq_len = seq_len - 2;
+                 /* Insn can be contracted to 16-bit.  */
+                 comp_insn16 =
+                   (comp_insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38;
+                 comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
+               }
+             else if (N32_RT5 (insn) == REG_R15)
+               {
+                 /* Insn can be contracted to 16-bit.  */
+                 comp_insn16 =
+                   (comp_insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38;
                }
-             i1_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-           }
-         if (seq_len & 0x2)
-           {
-             insn16 = NDS32_NOP16;
-             bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                             R_NDS32_INSN16);
-             lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-             insn_len += 2;
            }
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL2)
+    }
+  else
+    {
+      switch ((insn16 & 0xf000) >> 12)
        {
-         /* bltz  rt, $1   ; LONGCALL2
-            jal   symbol   ; 25_FIXED
-            $1: */
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_25_PCREL_RELA, laddr + 4);
+       case 0xc:
+         /* beqz38 or bnez38 */
+         comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ;
+         comp_insn |= ((comp_insn16 & 0x0700) >> 8) << 20;
+         break;
 
-         if (i1_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
+       case 0xd:
+         /* beqs38 or bnes38 */
+         comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0800) ? INSN_BNE : INSN_BEQ;
+         comp_insn |= (((comp_insn16 & 0x0700) >> 8) << 20)
+           | (REG_R5 << 15);
+         break;
 
-             continue;
-           }
+       case 0xe:
+         /* beqzS8 or bnezS8 */
+         comp_insn16 = (insn16 ^ 0x0100) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ;
+         comp_insn |= REG_R15 << 20;
+         break;
 
-         insn = bfd_getb32 (contents + laddr);
+       default:
+         break;
+       }
+    }
+  if (comp_insn && re_insn)
+    *re_insn = comp_insn;
+  if (comp_insn16 && re_insn16)
+    *re_insn16 = comp_insn16;
+}
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (foff == 0)
-           continue;
-         if (foff < -0x10000 - 4 || foff >= 0x10000 - 4)
-           /* After all that work, we can't shorten this function call.  */
-           continue;
+/* Relax LONGJUMP2 relocation for nds32_elf_relax_section.  */
 
-         /* Relax to   bgezal   rt, label ; 17_PCREL
-            or         bltzal   rt, label ; 17_PCREL */
+static bfd_boolean
+nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGJUMP2
+     case 2-4;  1st insn convertible, 16-bit on,
+     optimize off or optimize for space
+     bnes38  rt, ra, $1 ; LONGJUMP2
+     j       label      ; 25_PCREL
+     $1:
+
+     case 4-4; 1st insn not convertible
+     bne  rt, ra, $1 ; LONGJUMP2
+     j    label      ; 25_PCREL
+     $1:
+
+     case 4-4; 1st insn convertible, 16-bit on, optimize for speed
+     bne  rt, ra, $1 ; LONGJUMP2
+     j    label      ; 25_PCREL
+     $1: */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0, first_size;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc, cond_reloc;
 
-         /* Convert to complimentary conditional call.  */
-         insn &= 0xffff0000;
-         insn ^= 0x90000;
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
 
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
+  first_size = (seq_len == 6) ? 2 : 4;
+
+  i2_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs,
+                                irelend, R_NDS32_25_PCREL_RELA,
+                                laddr + first_size);
+
+  for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++)
+    {
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    checked_types[i], laddr);
+      if (cond_irelfn != irelend)
+       break;
+    }
 
-         /* Replace the long call with a bgezal.  */
-         irel->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                         R_NDS32_17_PCREL_RELA);
+  if (i2_irelfn == irelend || cond_irelfn == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-         bfd_putb32 (insn, contents + irel->r_offset);
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff =
+    calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr,
+                     &pic_ext_target);
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         i1_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-         cond_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_17_PCREL_RELA, laddr);
-         if (cond_irelfn != irelend)
-           {
-             cond_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                             R_NDS32_17_PCREL_RELA);
-             cond_irelfn->r_addend = i1_irelfn->r_addend;
-           }
-         insn_len = 4;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL3)
-       {
-         /* There are 3 variations for LONGCALL3
-            case 4-4-4-2; 16-bit on, optimize off or optimize for space
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral5 ta                      ;
-            $1
-
-            case 4-4-4-4; 16-bit off, optimize don't care
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral  ta                      ;
-            $1
-
-            case 4-4-4-4; 16-bit on, optimize for speed
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral  ta                      ; (INSN16)
-            $1 */
-
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         hi_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_HI20_RELA, laddr + 4);
-         lo_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_LO12S0_ORI_RELA, laddr + 8);
-         i2_offset = 12;
+  /* Get the all corresponding instructions.  */
+  if (first_size == 4)
+    {
+      insn = bfd_getb32 (contents + laddr);
+      nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
+    }
+  else
+    {
+      insn16 = bfd_getb16 (contents + laddr);
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             i2_offset = 8;
-             hi_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_20_RELA, laddr + 4);
+  if (re_insn16 && foff >= -(ACCURATE_8BIT_S1 - first_size)
+      && foff < ACCURATE_8BIT_S1 - first_size)
+    {
+      if (first_size == 4)
+       {
+         /* Don't convert it to 16-bit now, keep this as relaxable for
+            ``label reloc; INSN16''.  */
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
-                 continue;
-               }
-           }
+         /* Save comp_insn32 to buffer.  */
+         bfd_putb32 (re_insn, contents + irel->r_offset);
+         *insn_len = 4;
+         reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ?
+           R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+         cond_reloc = R_NDS32_INSN16;
+       }
+      else
+       {
+         bfd_putb16 (re_insn16, contents + irel->r_offset);
+         *insn_len = 2;
+         reloc = R_NDS32_9_PCREL_RELA;
+         cond_reloc = R_NDS32_NONE;
+       }
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR1
+          && (foff >= -(ACCURATE_14BIT_S1 - first_size)
+              && foff < ACCURATE_14BIT_S1 - first_size))
+    {
+      /* beqs     label    ; 15_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_15_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1
+          && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz     label ; 17_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_17_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+    }
+  else
+    return FALSE;
 
-         i2_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr + i2_offset);
+  /* Set all relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc);
+  irel->r_addend = i2_irelfn->r_addend;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           continue;
+  cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
+                                     cond_reloc);
+  cond_irelfn->r_addend = 0;
 
-         insn = bfd_getb32 (contents + laddr);
-         if (foff >= -0x10000 - 4 && foff < 0x10000 - 4)
-           {
-             /* Relax to  bgezal   rt, label ; 17_PCREL
-                or        bltzal   rt, label ; 17_PCREL */
+  if ((seq_len ^ *insn_len ) & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + 4);
+      i2_irelfn->r_offset = 4;
+      i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
+                                       R_NDS32_INSN16);
+      i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  else
+    i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
+                                     R_NDS32_NONE);
+  return TRUE;
+}
 
-             /* Convert to complimentary conditional call.  */
-             insn &= 0xffff0000;
-             insn ^= 0x90000;
-             bfd_putb32 (insn, contents + irel->r_offset);
+/* Relax LONGJUMP3 relocation for nds32_elf_relax_section.  */
 
-             insn_len = 4;
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                             R_NDS32_NONE);
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (i2_irelfn != irelend)
-               {
-                 if (!insn_opt
-                     && (i2_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-                   {
-                     /* The instruction pointed by R_NDS32_INSN16 is already
-                        turned into 16-bit instruction, so the total length
-                        of this sequence is decreased by 2.  */
-                     seq_len = seq_len - 2;
-                   }
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_NONE);
-               }
-             cond_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_17_PCREL_RELA, laddr);
-             if (cond_irelfn != irelend)
-               {
-                 cond_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_17_PCREL_RELA);
-                 cond_irelfn->r_addend = hi_irelfn->r_addend;
-               }
+static bfd_boolean
+nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 5 variations for LONGJUMP3
+     case 1: 2-4-4-2; 1st insn convertible, 16-bit on,
+     optimize off or optimize for space
+     bnes38   rt, ra, $1            ; LONGJUMP3
+     sethi    ta, hi20(symbol)      ; HI20
+     ori      ta, ta, lo12(symbol)  ; LO12S0
+     jr5      ta                    ;
+     $1:                            ;
+
+     case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed
+     bnes38   rt, ra, $1           ; LONGJUMP3
+     sethi    ta, hi20(symbol)     ; HI20
+     ori      ta, ta, lo12(symbol) ; LO12S0
+     jr5      ta                   ;
+     $1:                           ; LABEL
+
+     case 3: 4-4-4-2; 1st insn not convertible, 16-bit on,
+     optimize off or optimize for space
+     bne   rt, ra, $1           ; LONGJUMP3
+     sethi ta, hi20(symbol)     ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr5   ta                   ;
+     $1:                        ;
+
+     case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care
+     16-bit off if no INSN16
+     bne   rt, ra, $1           ; LONGJUMP3
+     sethi ta, hi20(symbol)     ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr    ta                   ;
+     $1:                        ;
+
+     case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed
+     16-bit off if no INSN16
+     bne   rt, ra, $1           ; LONGJUMP3
+     sethi ta, hi20(symbol)     ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr    ta                   ;
+     $1:                        ; LABEL */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
+
+  int reloc_off = 0, cond_removed = 0, convertible;
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0, first_size;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc, cond_reloc;
 
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 hi_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else
-           {
-             /* Relax to the following instruction sequence
-                 bltz  rt,   $1 ; LONGCALL2
-                 jal   symbol   ; 25_PCREL
-                 $1
-              */
-             insn = (insn & 0xffff0000) | 4;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             /* This relax is incorrect.  Review, fix and test it.
-                Check 6a726f0f for the oringnal code.  */
-             BFD_ASSERT (0);
-
-             bfd_putb32 (insn, contents + irel->r_offset + 4);
-             insn_len = 8;
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                             R_NDS32_25_PCREL_RELA);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2);
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (i2_irelfn != irelend)
-               {
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_NONE);
-               }
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP1)
-       {
-         /* There are 3 variations for LONGJUMP1
-            case 4-4-2; 16-bit bit on, optimize off or optimize for space
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr5   ta                    ;
+  convertible = IS_1ST_CONVERT (irel->r_addend);
 
-            case 4-4-4; 16-bit off, optimize don't care
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr    ta                    ;
+  if (convertible)
+    first_size = 2;
+  else
+    first_size = 4;
+
+  /* Get all needed relocations.  */
+  hi_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_HI20_RELA, laddr + first_size);
+  lo_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_LO12S0_ORI_RELA,
+                                laddr + first_size + 4);
+
+  for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+    {
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    checked_types[i], laddr);
+      if (cond_irelfn != irelend)
+       break;
+    }
 
-            case 4-4-4; 16-bit on, optimize for speed
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr    ta                    ; INSN16 */
+  if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP3 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         hi_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_HI20_RELA, laddr);
-         lo_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_LO12S0_ORI_RELA, laddr + 4);
-         i1_offset = 8;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             hi_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_20_RELA, laddr);
-             i1_offset = 4;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
+  /* Get the all corresponding instructions.  */
+  if (first_size == 4)
+    {
+      insn = bfd_getb32 (contents + laddr);
+      nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
+    }
+  else
+    {
+      insn16 = bfd_getb16 (contents + laddr);
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
 
-                 continue;
-               }
-           }
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr + i1_offset);
+  if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size
+      && foff < ACCURATE_8BIT_S1 - first_size)
+    {
+      if (!(seq_len & 0x2))
+       {
+         /* Don't convert it to 16-bit now, keep this as relaxable
+            for ``label reloc; INSN1a''6.  */
+         /* Save comp_insn32 to buffer.  */
+         bfd_putb32 (re_insn, contents + irel->r_offset);
+         *insn_len = 4;
+         reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ?
+           R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+         cond_reloc = R_NDS32_INSN16;
+       }
+      else
+       {
+         /* Not optimize for speed; convert sequence to 16-bit.  */
+         /* Save comp_insn16 to buffer.  */
+         bfd_putb16 (re_insn16, contents + irel->r_offset);
+         *insn_len = 2;
+         reloc = R_NDS32_9_PCREL_RELA;
+         cond_reloc = R_NDS32_NONE;
+       }
+      cond_removed = 1;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR1
+          && (foff >= -(ACCURATE_14BIT_S1 - first_size)
+              && foff < ACCURATE_14BIT_S1 - first_size))
+    {
+      /* beqs     label    ; 15_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_15_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+      cond_removed = 1;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1
+          && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz     label ; 17_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_17_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+      cond_removed = 1;
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off
+          && foff < CONSERVATIVE_24BIT_S1 - reloc_off)
+    {
+      /* Relax to one of the following 3 variations
+
+        case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize
+        for space
+        bnes38  rt, $1 ; LONGJUMP2
+        j       label  ; 25_PCREL
+        $1
+
+        case 4-4; 1st insn not convertible, others don't care
+        bne   rt, ra, $1 ; LONGJUMP2
+        j     label      ; 25_PCREL
+        $1
+
+        case 4-4; 1st insn convertible, 16-bit on, optimize for speed
+        bne   rt, ra, $1 ; LONGJUMP2
+        j     label      ; 25_PCREL
+        $1 */
+
+      /* Offset for first instruction.  */
+
+      /* Use j label as second instruction.  */
+      *insn_len = 4 + first_size;
+      insn = INSN_J;
+      bfd_putb32 (insn, contents + hi_irelfn->r_offset);
+      reloc = R_NDS32_LONGJUMP2;
+      cond_reloc = R_NDS32_25_PLTREL;
+    }
+    else
+      return FALSE;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
+    if (cond_removed == 1)
+      {
+       /* Set all relocations.  */
+       irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
+       irel->r_addend = hi_irelfn->r_addend;
+
+       cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
+                                           cond_reloc);
+       cond_irelfn->r_addend = 0;
+       hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                         R_NDS32_NONE);
+      }
+    else
+      {
+       irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+       irel->r_addend = irel->r_addend;
+       hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                         cond_reloc);
+      }
 
-         if (foff >= -0x1000000 && foff < 0x1000000)
-           {
-             /* j     label */
-             if (!insn_opt && insn16_on && foff >= -0x100 && foff < 0x100
-                 && (seq_len & 0x2))
-               {
-                 /* 16-bit on, but not optimized for speed.  */
-                 reloc = R_NDS32_9_PCREL_RELA;
-                 insn16 = INSN_J8;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-               }
-             else
-               {
-                 reloc = R_NDS32_25_PCREL_RELA;
-                 insn = INSN_J;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 4;
-               }
-           }
-         else
-           {
-             continue;
-           }
+  if ((seq_len ^ *insn_len ) & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+      lo_irelfn->r_offset = *insn_len;
+      lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
+                                       R_NDS32_INSN16);
+      lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  else
+    lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
+                                     R_NDS32_NONE);
+  return TRUE;
+}
 
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
+/* Relax LONGCALL4 relocation for nds32_elf_relax_section.  */
 
-         if (insn == 4)
-           {
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16);
-             irel->r_addend = 0;
-           }
-         else
-           irel->r_info =
-             ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+static bfd_boolean
+nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL4.  Support for function cse.
+     sethi ta, hi20(symbol)    ; LONGCALL4/HI20
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jral  ta                  ; PTR_RES/EMPTY/INSN16  */
 
-         hi_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
-         lo_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-         if (i1_irelfn != irelend)
-           {
-             if (!insn_opt
-                 && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-               {
-                 /* The instruction pointed by R_NDS32_INSN16 is already
-                    turned into 16-bit instruction, so the total length
-                    of this sequence is decreased by 2.  */
-                 seq_len = seq_len - 2;
-                 i1_irelfn->r_addend = 0;
-               }
-             i1_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-           }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel;
+  Elf_Internal_Rela *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-         if ((seq_len & 0x2) && ((insn_len & 2) == 0))
-           {
-             insn16 = NDS32_NOP16;
-             bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                             R_NDS32_INSN16);
-             lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-             insn_len += 2;
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP2)
-       {
-         /* There are 3 variations for LONGJUMP2
-            case 2-4;  1st insn convertible, 16-bit on, optimize off or optimize for space
-            bnes38  rt, ra, $1 ; LONGJUMP2
-            j       label      ; 25_PCREL
-            $1:
-
-            case 4-4; 1st insn not convertible
-            bne  rt, ra, $1 ; LONGJUMP2
-            j    label      ; 25_PCREL
-            $1:
-
-            case 4-4; 1st insn convertible, 16-bit on, optimize for speed
-            bne  rt, ra, $1 ; LONGJUMP2/INSN16
-            j    label      ; 25_PCREL
-            $1: */
-
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
-         hi_off = (seq_len == 6) ? 2 : 4;
-         i2_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_25_PCREL_RELA,
-                                        laddr + hi_off);
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         for (i = 0; i < 2; i++)
-           {
-             cond_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            checked_types[i], laddr);
-             if (cond_irelfn != irelend)
-               break;
-           }
-         if (i2_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_HI20_RELA, laddr);
 
-             continue;
-           }
+  if (hi_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr);
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (i1_irelfn != irelend && !insn_opt
-             && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-           {
-             /* The instruction pointed by R_NDS32_INSN16 is already turned
-                into 16-bit instruction, so the total length of this sequence
-                is decreased by 2.  */
-             seq_len = seq_len - 2;
-           }
+  /* This condition only happened when symbol is undefined.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         if (seq_len == 8)
-           {
-             /* possible cases
-                1. range is outside of +/-256 bytes
-                2. optimize is on with INSN16
-                3. optimize is off  */
-             insn_off = 4;
-             insn = bfd_getb32 (contents + laddr);
-             if (!insn16_on)
-               {
-                 /* 16-bit is off, can't convert to 16-bit.  */
-                 comp_insn16 = 0;
-               }
-             else if (N32_OP6 (insn) == N32_OP6_BR1)
-               {
-                 /* beqs     label    ; 15_PCREL (INSN16) */
-                 comp_insn = (insn ^ 0x4000) & 0xffffc000;
-                 i_mask = 0xffffc000;
-                 if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5)
-                   {
-                     /* Insn can be contracted to 16-bit.  */
-                     comp_insn16 =
-                       (insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38;
-                     comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                   }
-                 else
-                   {
-                     /* No conversion.  */
-                     comp_insn16 = 0;
-                   }
-               }
-             else
-               {
-                 comp_insn = (insn ^ 0x10000) & 0xffffc000;
-                 i_mask = 0xffff0000;
-                 if (N32_BR2_SUB (insn) == N32_BR2_BEQZ
-                     || N32_BR2_SUB (insn) == N32_BR2_BNEZ)
-                   {
-                     if (N32_IS_RT3 (insn))
-                       {
-                         /* Insn can be contracted to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38;
-                         comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                       }
-                     else if (N32_RT5 (insn) == REG_R15)
-                       {
-                         /* Insn can be contracted to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38;
-                       }
-                     else
-                       {
-                         /* No conversion.  */
-                         comp_insn16 = 0;
-                       }
-                   }
-                 else
-                   {
-                     /* No conversion.  */
-                     comp_insn16 = 0;
-                   }
-               }
-           }
-         else
-           {
-             /* First instruction is 16-bit.  */
-             insn_off = 2;
-             insn16 = bfd_getb16 (contents + laddr);
-             switch ((insn16 & 0xf000) >> 12)
-               {
-               case 0xc:
-                 /* beqz38 or bnez38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 i_mask = 0xffff0000;
-                 break;
+  /* Relax to: jal symbol; 25_PCREL */
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-               case 0xd:
-                 /* beqs38 or bnes38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNE : INSN_BEQ;
-                 comp_insn |= (((insn16 & 0x0700) >> 8) << 20)
-                   | (REG_R5 << 15);
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQ : INSN_BNE;
-                 insn |= (((insn16 & 0x0700) >> 8) << 20) | (REG_R5 << 15);
-                 i_mask = 0xffffc000;
-                 break;
+  ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_PTR_RESOLVED, irel->r_addend);
+  em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_EMPTY, irel->r_addend);
 
-               case 0xe:
-                 /* beqzS8 or bnezS8 */
-                 comp_insn = (insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= REG_R15 << 20;
-                 comp_insn16 = (insn16 ^ 0x0100) & 0xff00;
-                 insn = (insn16 & 0x0100) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= REG_R15 << 20;
-                 i_mask = 0xffff0000;
-                 break;
+  if (ptr_irel == irelend || em_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL4 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
+  /* Check these is enough space to insert jal in R_NDS32_EMPTY.  */
+  insn = bfd_getb32 (contents + irel->r_addend);
+  if (insn & 0x80000000)
+    return FALSE;
 
-               default:
-                 comp_insn16 = 0;
-                 insn = 0;
-                 break;
-               }
-           }
+  /* Replace the long call with a jal.  */
+  em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info),
+                                 R_NDS32_25_PCREL_RELA);
+  ptr_irel->r_addend = 1;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
+  /* We don't resolve this here but resolve it in relocate_section.  */
+  insn = INSN_JAL;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-         if (comp_insn16
-             && foff >= -0x100 - insn_off && foff < 0x100 - insn_off)
-           {
-             if (insn_opt || seq_len == 8)
-               {
-                 /* Don't convert it to 16-bit now, keep this as relaxable for
-                    ``label reloc; INSN16''.  */
+  irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-                 /* Save comp_insn32 to buffer.  */
-                 insn = comp_insn;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 4;
-                 reloc = (N32_OP6 (comp_insn) == N32_OP6_BR1) ?
-                   R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+  /* If there is function cse, HI20 can not remove now.  */
+  call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_LONGCALL4, laddr);
+  if (call_irel == irelend)
+    {
+      *insn_len = 0;
+      hi_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE);
+    }
 
-                 if (cond_irelfn != irelend)
-                   {
-                     cond_irelfn->r_info =
-                       ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
-                                     R_NDS32_INSN16);
-                     cond_irelfn->r_addend = 0;
-                   }
-               }
-             else
-               {
-                 /* Not optimize for speed; convert sequence to 16-bit.  */
+  insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_INSN16, irel->r_addend);
+  if (insn_irel != irelend)
+    insn_irel->r_info =
+      ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-                 /* Save comp_insn16 to buffer.  */
-                 insn16 = comp_insn16;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-                 reloc = R_NDS32_9_PCREL_RELA;
-               }
+  return TRUE;
+}
 
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc);
-             irel->r_addend = i2_irelfn->r_addend;
+/* Relax LONGCALL5 relocation for nds32_elf_relax_section.  */
 
-             i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                               R_NDS32_NONE);
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR1
-                  && (foff >= -0x4000 - insn_off && foff < 0x4000 - insn_off))
-           {
-             /* beqs     label    ; 15_PCREL */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                          R_NDS32_15_PCREL_RELA);
-             irel->r_addend = i2_irelfn->r_addend;
-             if (i1_irelfn != irelend)
-               i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                                 R_NDS32_NONE);
-
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR2 && foff >= -0x10000 && foff < 0x10000)
-           {
-             /* beqz     label ; 17_PCREL */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                          R_NDS32_17_PCREL_RELA);
-             irel->r_addend = i2_irelfn->r_addend;
-             if (i1_irelfn != irelend)
-               i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                                 R_NDS32_NONE);
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                                   R_NDS32_INSN16);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else
-           continue;
+static bfd_boolean
+nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL5.
+     bltz  rt, .L1     ; LONGCALL5/17_PCREL
+     jal   symbol      ; 25_PCREL
+     .L1:  */
 
-         if (cond_irelfn != irelend)
-           cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
-                                               R_NDS32_NONE);
-
-
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP3)
-       {
-         int reloc_off = 0, cond_removed = 0;
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
-
-         /* There are 5 variations for LONGJUMP3
-            case 1: 2-4-4-2; 1st insn convertible, 16-bit on,
-                             optimize off or optimize for space
-            bnes38   rt, ra, $1            ; LONGJUMP3
-            sethi    ta, hi20(symbol)      ; HI20
-            ori      ta, ta, lo12(symbol)  ; LO12S0
-            jr5      ta                    ;
-            $1:                            ;
-
-            case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed
-            bnes38   rt, ra, $1           ; LONGJUMP3
-            sethi    ta, hi20(symbol)     ; HI20
-            ori      ta, ta, lo12(symbol) ; LO12S0
-            jr5      ta                   ;
-            $1:                           ; LABEL
-
-            case 3: 4-4-4-2; 1st insn not convertible, 16-bit on,
-                             optimize off or optimize for space
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr5   ta                   ;
-            $1:                        ;
-
-            case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care
-            16-bit off if no INSN16
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr    ta                   ;
-            $1:                        ;
-
-            case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed
-            16-bit off if no INSN16
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr    ta                   ; INSN16
-            $1:                        ; LABEL
-          */
-
-         if (convertible)
-           {
-             hi_off = 2;
-             if (insn_opt)
-               reloc_off = 2;
-           }
-         else
-           {
-             hi_off = 4;
-           }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *cond_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-         hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_HI20_RELA,
-                                                  laddr + hi_off);
-         lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_LO12S0_ORI_RELA,
-                                                  laddr + hi_off + 4);
-         i2_offset = 8;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                      R_NDS32_20_RELA,
-                                                      laddr + hi_off);
-             i2_offset = 4;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  cond_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_25_PCREL_RELA, irel->r_addend);
+  if (cond_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL5 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGJUMP3 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
-                 continue;
-               }
-           }
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         i2_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16,
-                                        laddr + hi_off + i2_offset);
-
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
+  if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         /* Set offset adjustment value.  */
-         /* Check instruction type and set complimentary instruction.  */
-         if (hi_off == 2)
-           {
-             /* First instruction is 16-bit.  */
-             insn_off = 2;
-             insn16 = bfd_getb16 (contents + laddr);
-             switch ((insn16 & 0xf000) >> 12)
-               {
-               case 0xc:
-                 /* beqz38 or bnez38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 i_mask = 0xffff0000;
-                 break;
+  /* Relax to  bgezal   rt, label ; 17_PCREL
+     or                bltzal   rt, label ; 17_PCREL */
 
-               case 0xd:
-                 /* beqs38 or bnes38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNE : INSN_BEQ;
-                 comp_insn |= (((insn16 & 0x0700) >> 8) << 20)
-                   | (REG_R5 << 15);
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQ : INSN_BNE;
-                 insn |= (((insn16 & 0x0700) >> 8) << 20) | (REG_R5 << 15);
-                 i_mask = 0xffffc000;
-                 break;
+  /* Convert to complimentary conditional call.  */
+  insn = CONVERT_CONDITION_CALL (insn);
 
-               case 0xe:
-                 /* beqzS8 or bnezS8 */
-                 comp_insn = (insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= REG_R15 << 20;
-                 comp_insn16 = (insn16 ^ 0x0100) & 0xff00;
-                 insn = (insn16 & 0x0100) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= REG_R15 << 20;
-                 i_mask = 0xffff0000;
-                 break;
-               }
-           }
-         else
-           {
-             /* First instruction is 32-bit.  */
-             insn_off = 4;
-             insn = bfd_getb32 (contents + laddr);
-             if (!insn16_on)
-               {
-                 /* 16-bit is off */
-                 comp_insn16 = 0;
-               }
-             else if (N32_OP6 (insn) == N32_OP6_BR1)
-               {
-                 /* +/-16K range */
-                 comp_insn = insn ^ 0x4000;
-                 i_mask = 0xffffc000;
-                 if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5)
-                   {
-                     /* This instruction can turn to 16-bit.  */
-                     comp_insn16 =
-                       (insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38;
-                     comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                   }
-                 else
-                   {
-                     /* no conversion */
-                     comp_insn16 = 0;
-                   }
-               }
-             else
-               {
-                 /* +/-64K range */
-                 comp_insn = insn ^ 0x10000;
-                 i_mask = 0xffff0000;
-                 if (N32_BR2_SUB (insn) == N32_BR2_BEQZ
-                     || N32_BR2_SUB (insn) == N32_BR2_BNEZ)
-                   {
-                     if (N32_IS_RT3 (insn))
-                       {
-                         /* This instruction can turn to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38;
-                         comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                       }
-                     else if (N32_RT5 (insn) == REG_R15)
-                       {
-                         /* This instruction can turn to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNEZS8 : INSN_BEQZS8;
-                       }
-                     else
-                       {
-                         /* No conversion.  */
-                         comp_insn16 = 0;
-                       }
-                   }
-                 else
-                   {
-                     /* No conversion.  */
-                     comp_insn16 = 0;
-                   }
-               }
-           }
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-         if (foff < -0x1000000 && foff >= 0x1000000)
-           continue;
+  /* Modify relocation and contents.  */
+  cond_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA);
 
-         if (i2_irelfn != irelend)
-           {
-             if (insn_opt == 0
-                 && (i2_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-               {
-                 /* The instruction pointed by R_NDS32_INSN16 is already
-                    turned into 16-bit instruction, so the total length
-                    of this sequence is decreased by 2.  */
-                 seq_len = seq_len - 2;
-                 i2_irelfn->r_addend = 0;
-               }
-           }
+  /* Replace the long call with a bgezal.  */
+  bfd_putb32 (insn, contents + cond_irel->r_offset);
+  *insn_len = 0;
 
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
+  /* Clean unnessary relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         if (comp_insn16
-             && foff >= -0x100 - insn_off && foff < 0x100 - insn_off)
-           {
-             if (insn_opt || (seq_len & 0x2) == 0)
-               {
-                 /* Don't convert it to 16-bit now, keep this as relaxable
-                    for ``label reloc; INSN1a''6.  */
-                 /* Save comp_insn32 to buffer.  */
-                 insn = comp_insn;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 4;
-                 reloc = (N32_OP6 (comp_insn) == N32_OP6_BR1) ?
-                   R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
-
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_INSN16);
-               }
-             else
-               {
-                 /* Not optimize for speed; convert sequence to 16-bit.  */
-                 /* Save comp_insn16 to buffer.  */
-                 insn16 = comp_insn16;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-                 reloc = R_NDS32_9_PCREL_RELA;
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_NONE);
-               }
+  cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_17_PCREL_RELA, laddr);
+  cond_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
 
-             /* Change relocs.  */
-             for (i = 0; i < 2; i++)
-               {
-                 cond_irelfn =
-                   find_relocs_at_address_addr (irel, internal_relocs,
-                                                irelend, checked_types[i],
-                                                laddr);
+  return TRUE;
+}
 
-                 if (cond_irelfn != irelend)
-                   {
-                     cond_irelfn->r_info =
-                       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
-                     cond_irelfn->r_addend = hi_irelfn->r_addend;
-                   }
-               }
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             cond_removed = 1;
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR1
-                  && foff >= -0x4000 - insn_off && foff < 0x4000 - insn_off)
-           {
-             /* Relax to `beq  label ; 15_PCREL'.  */
+/* Relax LONGCALL6 relocation for nds32_elf_relax_section.  */
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = R_NDS32_15_PCREL_RELA;
+static bfd_boolean
+nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL6.
+     bltz  rt,   .L1                   ; LONGCALL6/17_PCREL
+     sethi ta,   hi20(symbol)          ; HI20/PTR
+     ori   ta, ta,  lo12(symbol)       ; LO12S0_ORI/PTR
+     jral  ta                          ; PTR_RES/EMPTY/INSN16
+     .L1  */
+
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *em_irel, *cond_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-             /* Change relocs.  */
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 hi_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 if (hi_off == 2)
-                   hi_irelfn->r_offset += 2;
-                 insn_len += 2;
-               }
-             cond_removed = 1;
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR2
-                  && foff >= -0x10000 - insn_off
-                  && foff < 0x10000 - insn_off)
-           {
-             /* Relax to `beqz  label ; 17_PCREL'.  */
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = R_NDS32_17_PCREL_RELA;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_EMPTY, irel->r_addend);
 
-             /* Change relocs.  */
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 if (hi_off == 2)
-                   hi_irelfn->r_offset += 2;
-                 insn_len += 2;
-               }
-             cond_removed = 1;
-           }
-         else if (foff >= -0x1000000 - reloc_off
-                  && foff < 0x1000000 - reloc_off)
-           {
-             /* Relax to one of the following 3 variations
-
-                case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize for space
-                bnes38  rt, $1 ; LONGJUMP2
-                j       label  ; 25_PCREL
-                $1
-
-                case 4-4; 1st insn not convertible, others don't care
-                bne   rt, ra, $1 ; LONGJUMP2
-                j     label      ; 25_PCREL
-                $1
-
-                case 4-4; 1st insn convertible, 16-bit on, optimize for speed
-                bne   rt, ra, $1 ; LONGJUMP2/INSN16
-                j     label      ; 25_PCREL
-                $1
-              */
+  if (em_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-             /* Offset for first instruction.  */
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             if (hi_off == 2)
-               {
-                 /* First instruction is 16-bit.  */
-                 if (hi_irelfn != irelend)
-                   {
-                     /* INSN16 exists so this is optimized for speed.  */
-                     /* Convert this instruction to 32-bit for label alignment.  */
-                     insn = (insn & i_mask) | 4;
-                     bfd_putb32 (insn, contents + irel->r_offset);
-                     insn_len = 8;
-                     hi_irelfn->r_offset += 2;
-                   }
-                 else
-                   {
-                     /* Not optimized for speed.  */
-                     insn16 = (insn16 & 0xff00) | 3;
-                     bfd_putb16 (insn16, contents + irel->r_offset);
-                     insn_len = 6;
-                   }
-               }
-             else
-               {
-                 /* First instruction is 32-bit.  */
-                 insn = (insn & i_mask) | 4;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 8;
-               }
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-             /* Use j label as second instruction.  */
-             insn = INSN_J;
-             bfd_putb32 (insn, contents + irel->r_offset);
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGJUMP2);
-             hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                               R_NDS32_25_PCREL_RELA);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (((seq_len ^ insn_len) & 0x2) != 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                                   R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 lo_irelfn->r_offset = hi_irelfn->r_offset + 4;
-                 insn_len += 2;
-               }
-           }
+  /* Check these is enough space to insert jal in R_NDS32_EMPTY.  */
+  insn = bfd_getb32 (contents + irel->r_addend);
+  if (insn & 0x80000000)
+    return FALSE;
 
-         if (cond_removed)
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 cond_irelfn =
-                   find_relocs_at_address_addr (irel, internal_relocs,
-                                                irelend, checked_types[i],
-                                                laddr);
+  insn = bfd_getb32 (contents + laddr);
+  if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* Relax to  bgezal   rt, label ; 17_PCREL
+        or        bltzal   rt, label ; 17_PCREL */
 
-                 if (cond_irelfn != irelend)
-                   break;
-               }
-             if (cond_irelfn != irelend)
-               {
-                 cond_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
-                 cond_irelfn->r_addend = hi_irelfn->r_addend;
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LOADSTORE)
+      /* Convert to complimentary conditional call.  */
+      *insn_len = 0;
+      insn = CONVERT_CONDITION_CALL (insn);
+      bfd_putb32 (insn, contents + em_irel->r_offset);
+
+      em_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA);
+
+      /* Set resolved relocation.  */
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_PTR_RESOLVED, irel->r_addend);
+      if (cond_irel == irelend)
        {
-         int eliminate_sethi = 0, ls_range_type;
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20,
-             R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20,
-             R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20
-           };
+         (*_bfd_error_handler)
+           ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized"
+            "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+         return FALSE;
+       }
+      cond_irel->r_addend = 1;
 
-         insn_len = seq_len;
+      /* Clear relocations.  */
 
-         for (i = 0; i < 6; i++)
-           {
-             hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                      checked_types[i], laddr);
-             if (hi_irelfn != irelend)
-               break;
-           }
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         if (hi_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_LOADSTORE points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
-             continue;
-           }
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_17_PCREL_RELA, laddr);
+      if (cond_irel != irelend)
+       cond_irel->r_info =
+         ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
 
-         ls_range_type = (irel->r_addend >> 8) & 0x3f;
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_INSN16, irel->r_addend);
+      if (cond_irel != irelend)
+       cond_irel->r_info =
+         ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
 
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
-         switch (ELF32_R_TYPE (hi_irelfn->r_info))
-           {
-           case R_NDS32_HI20_RELA:
-             insn = bfd_getb32 (contents + laddr);
-             access_addr =
-               calculate_memory_address (abfd, hi_irelfn, isymbuf,
-                                         symtab_hdr);
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1)
+    {
+      /* Relax to the following instruction sequence
+        bltz  rt, .L1  ; LONGCALL2/17_PCREL
+        jal   symbol   ; 25_PCREL/PTR_RES
+        .L1  */
+      *insn_len = 4;
+      /* Convert instruction.  */
+      insn = INSN_JAL;
+      bfd_putb32 (insn, contents + em_irel->r_offset);
 
-             if ((ls_range_type & 0x3f) == 0x20)
-               {
-                 if ((access_addr < 0x7f000))
-                   {
-                     eliminate_sethi = 1;
-                     break;
-                   }
-                 else
-                   {
-                     /* This is avoid to relax symbol address which is fixed
-                        relocations.  Ex: _stack.  */
-                     struct elf_link_hash_entry *h;
-                     int indx;
-                     indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info;
-                     if (indx >= 0)
-                       {
-                         h = elf_sym_hashes (abfd)[indx];
-                         if (h && bfd_is_abs_section (h->root.u.def.section))
-                           break;
-                       }
-                   }
-               }
+      /* Convert relocations.  */
+      em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info),
+                                     R_NDS32_25_PCREL_RELA);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL5);
 
-             if (!load_store_relax)
-               continue;
+      /* Set resolved relocation.  */
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_PTR_RESOLVED, irel->r_addend);
+      if (cond_irel == irelend)
+       {
+         (*_bfd_error_handler)
+           ("%B: warning: R_NDS32_LONGCALL6 points to unrecognized"
+            "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+         return FALSE;
+       }
+      cond_irel->r_addend = 1;
 
-             if (((insn >> 20) & 0x1f) == REG_GP)
-               break;
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_INSN16, irel->r_addend);
+      if (cond_irel != irelend)
+       cond_irel->r_info =
+         ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
+    }
+  return TRUE;
+}
 
-             if (ls_range_type & 0x8 || ls_range_type & 0x10)
-               {
-                 range_l = sdata_range[0][0];
-                 range_h = sdata_range[0][1];
-               }
-             else
-               {
-                 range_l = sdata_range[4][0];
-                 range_h = sdata_range[4][1];
-               }
-             break;
+/* Relax LONGJUMP4 relocation for nds32_elf_relax_section.  */
 
-           case R_NDS32_GOT_HI20:
-             access_addr =
-               calculate_got_memory_address (abfd, link_info, hi_irelfn,
-                                             symtab_hdr);
-
-             /* If this symbol is not in .got, the return value will be -1.
-                Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE,
-                a negative offset is allowed.  */
-             if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+static bfd_boolean
+nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGJUMP4.
+     sethi ta, hi20(symbol)    ; LONGJUMP4/HI20
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jr    ta                  ; PTR_RES/INSN16/EMPTY  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-           case R_NDS32_PLT_GOTREL_HI20:
-             access_addr =
-               calculate_plt_memory_address (abfd, link_info, isymbuf,
-                                             hi_irelfn, symtab_hdr);
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-             if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-           case R_NDS32_GOTOFF_HI20:
-             access_addr =
-               calculate_memory_address (abfd, hi_irelfn, isymbuf,
-                                         symtab_hdr);
+  hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_HI20_RELA, laddr);
 
-             if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+  if (hi_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-           case R_NDS32_GOTPC_HI20:
-             for (i1_irelfn = irel;
-                  i1_irelfn->r_offset <= irel->r_offset + 4
-                  && i1_irelfn < irelend; i1_irelfn++)
-               if (ELF32_R_TYPE (i1_irelfn->r_info) == R_NDS32_GOTPC_LO12)
-                 break;
-             if (i1_irelfn == irelend
-                 || i1_irelfn->r_offset != irel->r_offset + 4)
-               continue;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             access_addr = sec->output_section->vma + sec->output_offset
-                           + irel->r_offset;
-             if ((bfd_signed_vma) (local_sda - access_addr) < 0x7f000
-                 && (bfd_signed_vma) (local_sda - access_addr) >= -0x7f000)
-               {
-                 /* Turn into MOVI.  */
-                 insn = bfd_getb32 (contents + laddr + 4);
-                 if (((insn & 0x1f00000) >> 20) != REG_GP)
-                   continue;
-
-                 hi_irelfn->r_addend = ((int) hi_irelfn->r_addend) < -4
-                   ? (hi_irelfn->r_addend + 4) : (hi_irelfn->r_addend);
-                 hi_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_GOTPC20);
-                 irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                                   R_NDS32_NONE);
-                 insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
-                 bfd_putb32 (insn, contents + laddr);
-                 insn_len = 4;
-                 seq_len = 8;
-               }
-             break;
+  if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-           default:
-             continue;
-           }
-         if (eliminate_sethi == 1
-             || (local_sda <= access_addr && (access_addr - local_sda) < range_h)
-             || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
-           {
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-             insn_len = 0;
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA)
-       {
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < 1022 && foff >= 0)
-           {
-             reloc = R_NDS32_10IFCU_PCREL_RELA;
-             insn16 = INSN_IFCALL9;
-             bfd_putb16 (insn16, contents + irel->r_offset);
-             insn_len = 2;
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_10IFCU_PCREL_RELA);
-             *again = TRUE;
+  /* Convert it to "j label", it may be converted to j8 in the final
+     pass of relaxation.  Therefore, we do not consider this currently.  */
+  ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_PTR_RESOLVED, irel->r_addend);
+  em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_EMPTY, irel->r_addend);
 
-             i2_irelfn = find_relocs_at_address (irel, internal_relocs,
-                                                 irelend, R_NDS32_INSN16);
-             if (i2_irelfn < irelend)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + 2);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 i2_irelfn->r_offset += 2;
-                 insn_len += 2;
-               }
-             else
-               {
-                 ((*_bfd_error_handler)
-                  ("%s: 0x%lx: warning: R_NDS32_17IFC points to unrecognized reloc at 0x%lx",
-                   bfd_get_filename (abfd), (long) irel->r_offset));
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA)
-       {
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
+  if (ptr_irel == irelend || em_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP4 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-         insn = bfd_getb32 (contents + laddr);
+  em_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA);
+  ptr_irel->r_addend = 1;
 
-         if (!is_sda_access_insn (insn)
-             && N32_OP6 (insn) != N32_OP6_ORI)
-           continue;
+  /* Write instruction.  */
+  insn = INSN_J;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-         access_addr =
-           calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         insn_len = seq_len = 4;
+  /* Clear relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         /* This is avoid to relax symbol address which is fixed
-            relocations.  Ex: _stack.  */
-         if (N32_OP6 (insn) == N32_OP6_ORI && access_addr >= 0x7f000)
-           {
-             struct elf_link_hash_entry *h;
-             int indx;
-             indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-             if (indx >= 0)
-               {
-                 h = elf_sym_hashes (abfd)[indx];
-                 if (h && bfd_is_abs_section (h->root.u.def.section))
-                   continue;
-               }
-           }
+  /* If there is function cse, HI20 can not remove now.  */
+  call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_LONGJUMP4, laddr);
+  if (call_irel == irelend)
+    {
+      *insn_len = 0;
+      hi_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE);
+    }
 
-         if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < 0x7f000)
-           {
-             reloc = R_NDS32_20_RELA;
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
-             insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
-             bfd_putb32 (insn, contents + laddr);
-           }
-         else if (load_store_relax)
-           {
-             range_l = sdata_range[4][0];
-             range_h = sdata_range[4][1];
-             switch (ELF32_R_TYPE (irel->r_info))
-               {
-               case R_NDS32_LO12S0_RELA:
-                 reloc = R_NDS32_SDA19S0_RELA;
-                 break;
-               case R_NDS32_LO12S1_RELA:
-                 reloc = R_NDS32_SDA18S1_RELA;
-                 break;
-               case R_NDS32_LO12S2_RELA:
-                 reloc = R_NDS32_SDA17S2_RELA;
-                 break;
-               case R_NDS32_LO12S2_DP_RELA:
-                 range_l = sdata_range[0][0];
-                 range_h = sdata_range[0][1];
-                 reloc = R_NDS32_SDA12S2_DP_RELA;
-                 break;
-               case R_NDS32_LO12S2_SP_RELA:
-                 range_l = sdata_range[0][0];
-                 range_h = sdata_range[0][1];
-                 reloc = R_NDS32_SDA12S2_SP_RELA;
-                 break;
-               default:
-                 break;
-               }
-
-             /* There are range_h and range_l because linker has to promise
-                all sections move cross one page together.  */
-             if ((local_sda <= access_addr && (access_addr - local_sda) < range_h)
-                 || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
-               {
-                 if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP)
-                   {
-                     /* Maybe we should add R_NDS32_INSN16 reloc type here
-                        or manually do some optimization.  sethi can't be
-                        eliminated when updating $gp so the relative ori
-                        needs to be preserved.  */
-                     continue;
-                   }
-                 if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info),
-                                               &insn))
-                   continue;
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
-                 bfd_putb32 (insn, contents + laddr);
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12)
-       {
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
-
-         insn = bfd_getb32 (contents + laddr);
-
-         if (N32_OP6 (insn) != N32_OP6_ORI)
-           continue;
+  return TRUE;
+}
 
-         insn_len = seq_len = 4;
-         if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12)
-           {
-             foff = calculate_got_memory_address (abfd, link_info, irel,
-                                                  symtab_hdr) - local_sda;
-             reloc = R_NDS32_GOT20;
-           }
-         else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12)
-           {
-             foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel,
-                                                  symtab_hdr) - local_sda;
-             reloc = R_NDS32_PLT_GOTREL_LO20;
-           }
-         else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12)
-           {
-             foff = calculate_memory_address (abfd, irel, isymbuf,
-                                              symtab_hdr) - local_sda;
-             reloc = R_NDS32_GOTOFF;
-           }
-         else
-           continue;
+/* Relax LONGJUMP5 relocation for nds32_elf_relax_section.  */
 
-         if ((foff < 0x7f000) && (foff >= -0x7f000))
-           {
-             /* Turn into MOVI.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
-             insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
-             bfd_putb32 (insn, contents + laddr);
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PTR)
-       {
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_PTR_RESOLVED, irel->r_addend);
+static bfd_boolean
+nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 2 variations for LONGJUMP5
+     case 2-4;  1st insn convertible, 16-bit on.
+     bnes38  rt, ra, .L1       ; LONGJUMP5/9_PCREL/INSN16
+     j       label             ; 25_PCREL/INSN16
+     $1:
+
+     case 4-4; 1st insn not convertible
+     bne  rt, ra, .L1  ; LONGJUMP5/15_PCREL/INSN16
+     j    label                ; 25_PCREL/INSN16
+     .L1:  */
+
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel,  *irelend;
+  int pic_ext_target = 0;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-         if (i1_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_PTR points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
-             continue;
-           }
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA,
+      R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 };
 
-         if (i1_irelfn->r_addend & 1)
-           {
-             /* Pointed target is relaxed and no longer needs this void *,
-                change the type to NONE.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-             i1_irelfn =
-               find_relocs_at_address (irel, internal_relocs, irelend,
-                                       R_NDS32_PTR_COUNT);
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-             if (i1_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: no R_NDS32_PTR_COUNT coexist with R_NDS32_PTR at 0x%lx.",
-                   abfd, (long) irel->r_offset);
-                 continue;
-               }
+  cond_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_25_PCREL_RELA, irel->r_addend);
+  if (cond_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP5 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-             if (--i1_irelfn->r_addend > 0)
-               continue;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             /* If the PTR_COUNT is already 0, remove current instruction.  */
-             seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset);
-             insn_len = 0;
-           }
-         else
-           continue;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOT_SUFF)
-       {
-         /* FIXME: It's a little trouble to turn JRAL5 to JAL since
-            we need additional space.  It might be help if we could
-            borrow some space from instructions to be eliminated
-            such as sethi, ori, add.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           continue;
+  /* Get the all corresponding instructions.  */
+  insn = bfd_getb32 (contents + laddr);
+  /* Check instruction size.  */
+  if (insn & 0x80000000)
+    {
+      *seq_len = 0;
+      insn16 = insn >> 16;
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
+  else
+    nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
 
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF))
-           continue;
+  if (N32_OP6 (re_insn) == N32_OP6_BR1
+      && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1))
+    {
+      /* beqs label ; 15_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_15_PCREL_RELA;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz label ; 17_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_17_PCREL_RELA;
+    }
+  else if ( N32_OP6 (re_insn) == N32_OP6_BR3
+          && foff >= -CONSERVATIVE_8BIT_S1 && foff < CONSERVATIVE_8BIT_S1)
+    {
+      /* beqc label ; 9_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_WORD_9_PCREL_RELA;
+    }
+  else
+    return FALSE;
 
-         seq_len = insn_len = 4;
-         i1_irelfn =
-           find_relocs_at_address (irel, internal_relocs, irelend,
-                                   R_NDS32_PTR_RESOLVED);
-
-         /* FIXIT 090606
-            The boundary should be reduced since the .plt section hasn't
-            been created and the address of specific entry is still unknown
-            Maybe the range between the function call and the begin of the
-            .text section can be used to decide if the .plt is in the range
-            of function call.  */
-
-         if (N32_OP6 (insn) == N32_OP6_ALU1
-             && N32_SUB5 (insn) == N32_ALU1_ADD_SLLI
-             && N32_SH5 (insn) == 0)
-           {
-             /* Get the value of the symbol referred to by the reloc.  */
-             nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                       &local_sda, FALSE);
-             foff = (bfd_signed_vma) (calculate_plt_memory_address
-                                      (abfd, link_info, isymbuf, irel,
-                                       symtab_hdr) - local_sda);
-             /* This condition only happened when symbol is undefined.  */
-             if (foff == 0)
-               continue;
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc);
 
-             if (foff < -0x3f000 || foff >= 0x3f000)
-                   continue;
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                          R_NDS32_PLT_GOTREL_LO19);
-             /* addi.gp */
-             insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19));
-           }
-         else if (N32_OP6 (insn) == N32_OP6_JREG
-                  && N32_SUB5 (insn) == N32_JREG_JRAL)
+  /* Clean relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+  for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+    {
+      cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (cond_irel != irelend)
+       {
+         if (*seq_len == 0
+             && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16))
            {
-             /* Get the value of the symbol referred to by the reloc.  */
-             foff =
-               calculate_plt_offset (abfd, sec, link_info, isymbuf, irel,
-                                     symtab_hdr);
-             /* This condition only happened when symbol is undefined.  */
-             if (foff == 0)
-               continue;
-             if (foff < -0x1000000 || foff >= 0x1000000)
-               continue;
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL);
-             insn = INSN_JAL;
+             /* If the branch instruction is 2 byte, it cannot remove
+                directly.  Only convert it to nop16 and remove it after
+                checking alignment issue.  */
+             insn16 = NDS32_NOP16;
+             bfd_putb16 (insn16, contents + laddr);
+             cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
            }
          else
-           continue;
-
-         bfd_putb32 (insn, contents + laddr);
-         if (i1_irelfn != irelend)
-           {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
-           }
+           cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                             R_NDS32_NONE);
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_SUFF)
-       {
+    }
+  *insn_len = 0;
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           continue;
+  return TRUE;
+}
 
-         if (nds32_elf_check_dup_relocs
-               (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF))
-           continue;
+/* Relax LONGJUMP6 relocation for nds32_elf_relax_section.  */
 
-         seq_len = insn_len = 4;
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PTR_RESOLVED);
+static bfd_boolean
+nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 5 variations for LONGJUMP6
+     case : 2-4-4-4; 1st insn convertible, 16-bit on.
+     bnes38   rt, ra, .L1              ; LONGJUMP6/15_PCREL/INSN16
+     sethi    ta, hi20(symbol)         ; HI20/PTR
+     ori      ta, ta, lo12(symbol)     ; LO12S0_ORI/PTR
+     jr       ta                       ; PTR_RES/INSN16/EMPTY
+     .L1:
+
+     case : 4-4-4-4; 1st insn not convertible, 16-bit on.
+     bne   rt, ra, .L1         ; LONGJUMP6/15_PCREL/INSN16
+     sethi ta, hi20(symbol)    ; HI20/PTR
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jr    ta                  ; PTR_RES/INSN16/EMPTY
+     .L1:  */
+
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA,
+      R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 };
+
+  int reloc_off = 0, cond_removed = 0;
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel;
+  int pic_ext_target = 0;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-         foff = calculate_got_memory_address (abfd, link_info, irel,
-                                              symtab_hdr) - local_sda;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         if (foff < 0x3f000 && foff >= -0x3f000)
-           {
-             /* Turn LW to LWI.GP.  Change relocation type to R_NDS32_GOT_REL.  */
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA);
-           }
-         else
-           continue;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_EMPTY, irel->r_addend);
 
-         bfd_putb32 (insn, contents + laddr);
-         if (i1_irelfn != irelend)
-           {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_SUFF)
-       {
-         int opc_insn_gotoff;
+  if (em_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP6 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           continue;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF))
-           continue;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         seq_len = insn_len = 4;
+  insn = bfd_getb32 (contents + laddr);
+  /* Check instruction size.  */
+  if (insn & 0x80000000)
+    {
+      *seq_len = 0;
+      insn16 = insn >> 16;
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
+  else
+    nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
 
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PTR_RESOLVED);
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
-         access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         foff = access_addr - local_sda;
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-         if (foff >= 0x3f000 || foff < -0x3f000)
-           continue;
+  if (N32_OP6 (re_insn) == N32_OP6_BR1
+      && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1))
+    {
+      /* beqs     label    ; 15_PCREL */
+      bfd_putb32 (re_insn, contents + em_irel->r_offset);
+      reloc = R_NDS32_15_PCREL_RELA;
+      cond_removed = 1;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz     label ; 17_PCREL */
+      bfd_putb32 (re_insn, contents + em_irel->r_offset);
+      reloc = R_NDS32_17_PCREL_RELA;
+      cond_removed = 1;
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off
+          && foff < CONSERVATIVE_24BIT_S1 - reloc_off)
+    {
+      /* Relax to one of the following 2 variations
 
-         /* Concatenate opcode and sub-opcode for switch case.
-            It may be MEM or ALU1.  */
-         opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff);
-         switch (opc_insn_gotoff)
-           {
-           case (N32_OP6_MEM << 8) | N32_MEM_LW:
-             /* 4-byte aligned.  */
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_SW:
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_LH:
-             /* 2-byte aligned.  */
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_LHS:
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_SH:
-             insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_LB:
-             /* 1-byte aligned.  */
-             insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_LBS:
-             insn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
-             break;
-           case (N32_OP6_MEM << 8) | N32_MEM_SB:
-             insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
-             break;
-           case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD_SLLI:
-             if (N32_SH5 (insn) != 0)
-               continue;
-             insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19));
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
-             break;
-           default:
-             continue;
-           }
+        case 2-4;  1st insn convertible, 16-bit on.
+        bnes38  rt, ra, .L1    ; LONGJUMP5/9_PCREL/INSN16
+        j       label          ; 25_PCREL/INSN16
+        $1:
 
-         bfd_putb32 (insn, contents + laddr);
-         if (i1_irelfn != irelend)
-           {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
-           }
-         if ((i2_irelfn =
-              find_relocs_at_address (irel, internal_relocs, irelend,
-                                      R_NDS32_INSN16)) != irelend)
-           i2_irelfn->r_info =
-             ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_MULCALL_SUFF)
-       {
-         /* The last bit of r_addend indicates its a two instruction block.  */
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PTR_RESOLVED);
-         if ((i1_irelfn != irelend && (i1_irelfn->r_addend & 1))
-             || (nds32_elf_insn_size (abfd, contents, irel->r_offset) != 4
-                 && !(i1_irelfn != irelend && (i1_irelfn->r_addend & 2))))
-           continue;
+        case 4-4; 1st insn not convertible
+        bne  rt, ra, .L1       ; LONGJUMP5/15_PCREL/INSN16
+        j    label             ; 25_PCREL/INSN16
+        .L1:  */
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+      /* Use j label as second instruction.  */
+      insn = INSN_J;
+      reloc = R_NDS32_25_PCREL_RELA;
+      bfd_putb32 (insn, contents + em_irel->r_offset);
+    }
+  else
+    return FALSE;
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           continue;
+  /* Set all relocations.  */
+  em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc);
 
-         if (i1_irelfn != irelend && (i1_irelfn->r_addend & 2))
-           {
-             seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset);
-             seq_len += nds32_elf_insn_size (abfd, contents,
-                                             irel->r_offset + seq_len);
-           }
-         else
-           seq_len = 4;
-         insn_len = 4;
+  cond_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_PTR_RESOLVED, em_irel->r_offset);
+  cond_irel->r_addend = 1;
 
-         insn = INSN_JAL;
-         bfd_putb32 (insn, contents + laddr);
-         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PCREL_RELA);
+  /* Use INSN16 of first branch instruction to distinguish if keeping
+     INSN16 of final instruction or not.  */
+  insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_INSN16, irel->r_offset);
+  if (insn_irel == irelend)
+    {
+      /* Clean the final INSN16.  */
+      insn_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_INSN16, em_irel->r_offset);
+      insn_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                       R_NDS32_NONE);
+    }
+
+  if (cond_removed == 1)
+    {
+      *insn_len = 0;
+
+      /* Clear relocations.  */
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         if (i1_irelfn != irelend)
+      for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+       {
+         cond_irel =
+           find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        checked_types[i], laddr);
+         if (cond_irel != irelend)
            {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
+             if (*seq_len == 0
+                 && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16))
+               {
+                 /* If the branch instruction is 2 byte, it cannot remove
+                    directly.  Only convert it to nop16 and remove it after
+                    checking alignment issue.  */
+                 insn16 = NDS32_NOP16;
+                 bfd_putb16 (insn16, contents + laddr);
+                 cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+               }
+             else
+               cond_irel->r_info =
+                 ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
            }
-         while (i1_irelfn != irelend
-                && irel->r_offset == i1_irelfn->r_offset)
-           i1_irelfn++;
-         for (;
-              i1_irelfn != irelend
-              && i1_irelfn->r_offset < irel->r_offset + 4; i1_irelfn++)
-           i1_irelfn->r_info =
-             ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTBLOCK)
-       {
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PLT_GOTREL_HI20);
+    }
+  else
+    {
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                  R_NDS32_LONGJUMP5);
+    }
 
-         if (i1_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_PLTBLOCK points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
-             continue;
-           }
+  return TRUE;
+}
 
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
-         foff =
-           calculate_plt_offset (abfd, sec, link_info, isymbuf, hi_irelfn,
-                                 symtab_hdr);
+/* Relax LONGJUMP7 relocation for nds32_elf_relax_section.  */
 
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           {
-             foff = (bfd_signed_vma) (calculate_plt_memory_address
-                                      (abfd, link_info, isymbuf, hi_irelfn,
-                                       symtab_hdr) - local_sda);
-             if (foff >= -0x4000 && foff < 0x4000)
-               {
-                 /* addi  $rt, $gp, lo15(Sym - SDA_BASE)
-                    jral  $rt */
+static bfd_boolean
+nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 2 variations for LONGJUMP5
+     case 2-4;  1st insn convertible, 16-bit on.
+     movi55  ta, imm11         ; LONGJUMP7/INSN16
+     beq     rt, ta, label     ; 15_PCREL
+
+     case 4-4; 1st insn not convertible
+     movi55  ta, imm11         ; LONGJUMP7/INSN16
+     beq     rt, ta, label     ; 15_PCREL  */
+
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel,  *irelend, *insn_irel;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16;
+  uint32_t imm11;
 
-                 /* TODO: We can use add.gp here, once ISA V1 is obsolete.  */
-                 insn = N32_TYPE2 (ADDI, N32_RT5 (insn), REG_GP, 0);
-                 bfd_putb32 (insn, contents + irel->r_offset + 8);
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-                 i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                                   R_NDS32_PLT_GOTREL_LO15);
-                 i1_irelfn->r_addend = hi_irelfn->r_addend;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-                 seq_len = 8;
-               }
-             else if (foff >= -0x80000 && foff < 0x80000)
-               {
-                 /* movi $rt, lo20(Sym - SDA_BASE)     PLT_GOTREL_LO20
-                    add  $rt, $gp, $rt                 INSN16
-                    jral $rt                           INSN16 */
-
-                 for (i1_irelfn = irel;
-                      i1_irelfn->r_offset < irel->r_offset + 4; i1_irelfn++)
-                   ;
-                 for (; i1_irelfn->r_offset < irel->r_offset + 8; i1_irelfn++)
-                   if (ELF32_R_TYPE (i1_irelfn->r_info) != R_NDS32_PLT_GOTREL_LO12)
-                     i2_irelfn = i1_irelfn;
-                   else if (ELF32_R_TYPE (i1_irelfn->r_info) != R_NDS32_LABEL)
-                     i1_irelfn->r_info =
-                       ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                     R_NDS32_NONE);
-                 if (i2_irelfn)
-                   {
-                     insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
-                     bfd_putb32 (insn, contents + irel->r_offset + 4);
-                     i2_irelfn->r_info =
-                       ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                     R_NDS32_PLT_GOTREL_LO20);
-                   }
-                 seq_len = 4;
-               }
-             else
-               continue;
+  cond_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_15_PCREL_RELA, irel->r_addend);
+  if (cond_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LONGJUMP7 points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-           }
-         else
-           {
-             /* jal Sym INSN16/25_PLTREL */
-             for (i1_irelfn = irel;
-                  i1_irelfn->r_offset < irel->r_offset + 12; i1_irelfn++)
-               ;
-
-             i2_irelfn = i1_irelfn - 1;
-             i2_irelfn->r_offset = i1_irelfn->r_offset;
-             i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                               R_NDS32_25_PLTREL);
-             i2_irelfn->r_addend = hi_irelfn->r_addend;
-             insn = INSN_JAL;
-             bfd_putb32 (insn, contents + irel->r_offset + 12);
-             seq_len = 12;
-           }
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         insn_len = 0;
-       }
-      else
-       continue;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1
+      || foff >= CONSERVATIVE_8BIT_S1)
+    return FALSE;
 
-      if (seq_len - insn_len > 0)
-       {
-         if (!insert_nds32_elf_blank
-             (&relax_blank_list, irel->r_offset + insn_len,
-              seq_len - insn_len))
-           goto error_return;
-         *again = TRUE;
-       }
+  /* Get the first instruction for its size.  */
+  insn = bfd_getb32 (contents + laddr);
+  if (insn & 0x80000000)
+    {
+      *seq_len = 0;
+      /* Get the immediate from movi55.  */
+      imm11 = N16_IMM5S (insn >> 16);
+    }
+  else
+    {
+      /* Get the immediate from movi.  */
+      imm11 = N32_IMM20S (insn);
     }
 
-  calc_nds32_blank_total (relax_blank_list);
+  /* Get the branch instruction.  */
+  insn = bfd_getb32 (contents + irel->r_addend);
+  /* Convert instruction to BR3.  */
+  if ((insn >> 14) & 0x1)
+    re_insn = N32_BR3 (BNEC, N32_RT5 (insn), imm11, 0);
+  else
+    re_insn = N32_BR3 (BEQC, N32_RT5 (insn), imm11, 0);
 
-  if (table->relax_fp_as_gp)
-    {
-      if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs,
-                                irelend, isymbuf))
-       goto error_return;
+  bfd_putb32 (re_insn, contents + cond_irel->r_offset);
 
-      if (*again == FALSE)
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                   R_NDS32_WORD_9_PCREL_RELA);
+
+  /* Clean relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+  insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_INSN16, irel->r_offset);
+  if (insn_irel != irelend)
+    {
+      if (*seq_len == 0)
        {
-         if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs,
-                                              irelend))
-           goto error_return;
+         /* If the first insntruction is 16bit, convert it to nop16.  */
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + laddr);
+         insn_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
        }
+      else
+       cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                         R_NDS32_NONE);
     }
+  *insn_len = 0;
 
-  if (*again == FALSE)
-    {
-      /* This code block is used to adjust 4-byte alignment by relax a pair
-        of instruction a time.
+  return TRUE;
+}
 
-        It recognizes three types of relocations.
-        1. R_NDS32_LABEL - a aligment.
-        2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit.
-        3. is_16bit_NOP () - remove a 16-bit instruction.
+#define GET_LOADSTORE_RANGE(addend) (((addend) >> 8) & 0x3f)
 
-        FIXME: It seems currently implementation only support 4-byte aligment.
-        We should handle any-aligment.  */
+/* Relax LOADSTORE relocation for nds32_elf_relax_section.  */
 
-      Elf_Internal_Rela *insn_rel = NULL;
-      Elf_Internal_Rela *label_rel = NULL;
-      Elf_Internal_Rela *tmp_rel, tmp2_rel, *tmp3_rel = NULL;
+static bfd_boolean
+nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd,
+                          asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr, int load_store_relax)
+{
+  int eliminate_sethi = 0, range_type, i;
+  bfd_vma local_sda, laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn = NULL, *irelend;
+  bfd_vma access_addr = 0;
+  bfd_vma range_l = 0, range_h = 0;    /* Upper/lower bound.  */
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20,
+      R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20,
+      R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20,
+      R_NDS32_TLS_LE_HI20
+    };
 
-      /* Checking for branch relaxation relies on the relocations to
-        be sorted on 'r_offset'.  This is not guaranteed so we must sort.  */
-      nds32_insertion_sort (internal_relocs, sec->reloc_count,
-                           sizeof (Elf_Internal_Rela), compar_reloc);
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-      nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                               &local_sda, FALSE);
+  /* Get the high part relocation.  */
+  for (i = 0; (unsigned) i < sizeof (checked_types); i++)
+    {
+      hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (hi_irelfn != irelend)
+       break;
+    }
 
-      /* Force R_NDS32_LABEL before R_NDS32_INSN16.  */
-      /* FIXME: Can we generate the right order in assembler?
-               So we don't have to swapping them here.  */
-      for (label_rel = internal_relocs, insn_rel = internal_relocs;
-          label_rel < irelend; label_rel++)
-       {
-         if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL)
-           continue;
+  if (hi_irelfn == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_LOADSTORE points to unrecognized"
+        "reloc at 0x%lx.", abfd, (long) irel->r_offset);
+       return FALSE;
+    }
 
-         /* Find the first reloc has the same offset with label_rel.  */
-         while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset)
-           insn_rel++;
+  range_type = GET_LOADSTORE_RANGE (irel->r_addend);
+  nds32_elf_final_sda_base (sec->output_section->owner,
+                           link_info, &local_sda, FALSE);
 
-         for (;
-              insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset;
-              insn_rel++)
-           /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same
-              address.  */
-           if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16)
-             break;
+  switch (ELF32_R_TYPE (hi_irelfn->r_info))
+    {
+    case R_NDS32_HI20_RELA:
+      insn = bfd_getb32 (contents + laddr);
+      access_addr =
+       calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr);
+
+      if (range_type == NDS32_LOADSTORE_IMM)
+       {
+         struct elf_link_hash_entry *h = NULL;
+         int indx;
 
-         if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset
-             && insn_rel < label_rel)
+         if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info)
            {
-             /* Swap the two reloc if the R_NDS32_INSN16 is before R_NDS32_LABEL.  */
-             memcpy (&tmp2_rel, insn_rel, sizeof (Elf_Internal_Rela));
-             memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela));
-             memcpy (label_rel, &tmp2_rel, sizeof (Elf_Internal_Rela));
+             indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info;
+             h = elf_sym_hashes (abfd)[indx];
            }
-       }
-      label_rel = NULL;
-      insn_rel = NULL;
 
-      /* If there were a sequence of R_NDS32_LABEL end up with .align 2 or higher,
-        remove other R_NDS32_LABEL with lower alignment.
-        If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted,
-        then the R_NDS32_LABEL sequence is broke.  */
-      for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++)
-       {
-         if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL)
+         if ((access_addr < CONSERVATIVE_20BIT)
+             && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0)))
            {
-             if (label_rel == NULL)
-               {
-                 if (tmp_rel->r_addend < 2)
-                   label_rel = tmp_rel;
-                 continue;
-               }
-             else if (tmp_rel->r_addend > 1)
-               {
-                 for (tmp3_rel = label_rel; tmp3_rel < tmp_rel; tmp3_rel++)
-                   {
-                     if (ELF32_R_TYPE (tmp3_rel->r_info) == R_NDS32_LABEL
-                         && tmp3_rel->r_addend < 2)
-                       tmp3_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (tmp3_rel->r_info), R_NDS32_NONE);
-                   }
-                 label_rel = NULL;
-               }
+             eliminate_sethi = 1;
+             break;
            }
-         else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16)
+
+         /* This is avoid to relax symbol address which is fixed
+            relocations.  Ex: _stack.  */
+         if (h && bfd_is_abs_section (h->root.u.def.section))
+           return FALSE;
+       }
+
+      if (!load_store_relax)
+       return FALSE;
+
+      /* Case for set gp register.  */
+      if (N32_RT5 (insn) == REG_GP)
+       break;
+
+      if (range_type == NDS32_LOADSTORE_FLOAT_S
+         || range_type == NDS32_LOADSTORE_FLOAT_S)
+       {
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
+       }
+      else
+       {
+         range_l = sdata_range[1][0];
+         range_h = sdata_range[1][1];
+       }
+      break;
+
+    case R_NDS32_GOT_HI20:
+      access_addr =
+       calculate_got_memory_address (abfd, link_info, hi_irelfn, symtab_hdr);
+
+      /* If this symbol is not in .got, the return value will be -1.
+        Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE,
+        a negative offset is allowed.  */
+      if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
+
+    case R_NDS32_PLT_GOTREL_HI20:
+      access_addr = calculate_plt_memory_address (abfd, link_info, isymbuf,
+                                                 hi_irelfn, symtab_hdr);
+
+      if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
+
+    case R_NDS32_GOTOFF_HI20:
+      access_addr =
+       calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr);
+
+      if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
+
+    case R_NDS32_GOTPC_HI20:
+      /* The access_addr must consider r_addend of hi_irel.  */
+      access_addr = sec->output_section->vma + sec->output_offset
+       + irel->r_offset + hi_irelfn->r_addend;
+
+      if ((bfd_signed_vma) (local_sda - access_addr) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (local_sda - access_addr) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
+
+    case R_NDS32_TLS_LE_HI20:
+      access_addr =
+       calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr);
+      BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+      access_addr -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+      if ((range_type == NDS32_LOADSTORE_IMM)
+         && (bfd_signed_vma) (access_addr) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  /* Delete sethi instruction.  */
+  if (eliminate_sethi == 1
+      || (local_sda <= access_addr && (access_addr - local_sda) < range_h)
+      || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
+    {
+      hi_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+      *insn_len = 0;
+    }
+  return TRUE;
+}
+
+/* Relax LO12 relocation for nds32_elf_relax_section.  */
+
+static void
+nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd,
+                     asection *sec, Elf_Internal_Rela *irel,
+                     Elf_Internal_Rela *internal_relocs, bfd_byte *contents,
+                     Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr)
+{
+  uint32_t insn;
+  bfd_vma local_sda, laddr;
+  unsigned long reloc;
+  bfd_vma access_addr;
+  bfd_vma range_l = 0, range_h = 0;    /* Upper/lower bound.  */
+  Elf_Internal_Rela *irelfn = NULL, *irelend;
+  struct elf_link_hash_entry *h = NULL;
+  int indx;
+
+  /* For SDA base relative relaxation.  */
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  if (!is_sda_access_insn (insn) && N32_OP6 (insn) != N32_OP6_ORI)
+    return;
+
+  access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+
+  if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info)
+    {
+      indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+      h = elf_sym_hashes (abfd)[indx];
+    }
+
+  if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < CONSERVATIVE_20BIT
+      && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0)))
+    {
+      reloc = R_NDS32_20_RELA;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
+      bfd_putb32 (insn, contents + laddr);
+    }
+  /* This is avoid to relax symbol address which is fixed
+     relocations.  Ex: _stack.  */
+  else if (N32_OP6 (insn) == N32_OP6_ORI
+          && h && bfd_is_abs_section (h->root.u.def.section))
+    return;
+  else
+    {
+      range_l = sdata_range[1][0];
+      range_h = sdata_range[1][1];
+      switch (ELF32_R_TYPE (irel->r_info))
+       {
+       case R_NDS32_LO12S0_RELA:
+         reloc = R_NDS32_SDA19S0_RELA;
+         break;
+       case R_NDS32_LO12S1_RELA:
+         reloc = R_NDS32_SDA18S1_RELA;
+         break;
+       case R_NDS32_LO12S2_RELA:
+         reloc = R_NDS32_SDA17S2_RELA;
+         break;
+       case R_NDS32_LO12S2_DP_RELA:
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
+         reloc = R_NDS32_SDA12S2_DP_RELA;
+         break;
+       case R_NDS32_LO12S2_SP_RELA:
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
+         reloc = R_NDS32_SDA12S2_SP_RELA;
+         break;
+       default:
+         return;
+       }
+
+      /* There are range_h and range_l because linker has to promise
+        all sections move cross one page together.  */
+      if ((local_sda <= access_addr && (access_addr - local_sda) < range_h)
+         || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
+       {
+         if (N32_OP6 (insn) == N32_OP6_ORI && N32_RT5 (insn) == REG_GP)
            {
-             if (label_rel
-                 && label_rel->r_offset != tmp_rel->r_offset
-                 && (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs,
-                                          irelend, &insn16)
-                     || is_16bit_NOP (abfd, sec, tmp_rel)))
-               {
-                 label_rel = NULL;
-               }
+             /* Maybe we should add R_NDS32_INSN16 reloc type here
+                or manually do some optimization.  sethi can't be
+                eliminated when updating $gp so the relative ori
+                needs to be preserved.  */
+             return;
            }
+         if (!turn_insn_to_sda_access (insn, ELF32_R_TYPE (irel->r_info),
+                                       &insn))
+           return;
+         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+         bfd_putb32 (insn, contents + laddr);
+
+         irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                          R_NDS32_INSN16);
+         /* SDA17 must keep INSN16 for converting fp_as_gp.  */
+         if (irelfn != irelend && reloc != R_NDS32_SDA17S2_RELA)
+           irelfn->r_info =
+             ELF32_R_INFO (ELF32_R_SYM (irelfn->r_info), R_NDS32_NONE);
+
        }
-      label_rel = NULL;
-      insn_rel = NULL;
+    }
+  return;
+}
 
-      /* Optimized for speed and nothing has not been relaxed.
-        It's time to align labels.
-        We may convert a 16-bit instruction right before a label to
-        32-bit, in order to align the label if necessary
-        all reloc entries has been sorted by r_offset.  */
-      for (irel = internal_relocs; irel < irelend; irel++)
+/* Relax low part of PIC instruction pattern.  */
+
+static void
+nds32_elf_relax_piclo12 (struct bfd_link_info *link_info, bfd *abfd,
+                        asection *sec, Elf_Internal_Rela *irel,
+                        bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                        Elf_Internal_Shdr *symtab_hdr)
+{
+  uint32_t insn;
+  bfd_vma local_sda, laddr;
+  bfd_signed_vma foff;
+  unsigned long reloc;
+
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  if (N32_OP6 (insn) != N32_OP6_ORI)
+    return;
+
+  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12)
+    {
+      foff = calculate_got_memory_address (abfd, link_info, irel,
+                                          symtab_hdr) - local_sda;
+      reloc = R_NDS32_GOT20;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12)
+    {
+      foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel,
+                                          symtab_hdr) - local_sda;
+      reloc = R_NDS32_PLT_GOTREL_LO20;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12)
+    {
+      foff = calculate_memory_address (abfd, irel, isymbuf,
+                                      symtab_hdr) - local_sda;
+      reloc = R_NDS32_GOTOFF;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12)
+    {
+      foff = local_sda - sec->output_section->vma + sec->output_offset
+       + irel->r_offset + irel->r_addend;
+      reloc = R_NDS32_GOTPC20;
+    }
+  else
+    return;
+
+  if ((foff < CONSERVATIVE_20BIT) && (foff >= -CONSERVATIVE_20BIT))
+    {
+      /* Turn into MOVI.  */
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
+      bfd_putb32 (insn, contents + laddr);
+    }
+}
+
+/* Relax low part of LE TLS instruction pattern.  */
+
+static void
+nds32_elf_relax_letlslo12 (struct bfd_link_info *link_info, bfd *abfd,
+                          Elf_Internal_Rela *irel,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  unsigned long reloc;
+
+  laddr = irel->r_offset;
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+  insn = bfd_getb32 (contents + laddr);
+
+  if ( (bfd_signed_vma) (foff) < CONSERVATIVE_20BIT
+      && (bfd_signed_vma) (foff) >= -CONSERVATIVE_20BIT)
+    {
+      /* Pattern sethi-ori transform to movi.  */
+      reloc = R_NDS32_TLS_LE_20;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
+      bfd_putb32 (insn, contents + laddr);
+    }
+}
+
+/* Relax LE TLS calculate address instruction pattern.  */
+
+static void
+nds32_elf_relax_letlsadd (struct bfd_link_info *link_info, bfd *abfd,
+                         asection *sec, Elf_Internal_Rela *irel,
+                         Elf_Internal_Rela *internal_relocs,
+                         bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                         Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
+{
+  /* Local TLS non-pic
+     sethi    ta, hi20(symbol@tpoff)      ; TLS_LE_HI20
+     ori      ta, ta, lo12(symbol@tpoff)  ; TLS_LE_LO12
+     add      ra, ta, tp                  ; TLS_LE_ADD */
+
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+
+  /* The range is +/-16k.  */
+  if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT
+      && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT)
+    {
+      /* Transform add to addi.  */
+      insn = N32_TYPE2 (ADDI, N32_RT5 (insn), N32_RB5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0);
+
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
+       {
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
+       }
+    }
+}
+
+/* Relax LE TLS load store instruction pattern.  */
+
+static void
+nds32_elf_relax_letlsls (struct bfd_link_info *link_info, bfd *abfd,
+                        asection *sec, Elf_Internal_Rela *irel,
+                        Elf_Internal_Rela *internal_relocs,
+                        bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                        Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
+{
+
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  int success = 0;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+
+  switch ((N32_OP6 (insn) << 8) | (insn & 0xff))
+    {
+    case (N32_OP6_MEM << 8) | N32_MEM_LB:
+    case (N32_OP6_MEM << 8) | N32_MEM_SB:
+    case (N32_OP6_MEM << 8) | N32_MEM_LBS:
+      /* The range is +/-16k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT)
+       {
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0);
+         success = 1;
+         break;
+       }
+    case (N32_OP6_MEM << 8) | N32_MEM_LH:
+    case (N32_OP6_MEM << 8) | N32_MEM_SH:
+    case (N32_OP6_MEM << 8) | N32_MEM_LHS:
+      /* The range is +/-32k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S1
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S1)
        {
-         if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16
-             && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL)
-           continue;
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S1);
+         success = 1;
+         break;
+       }
+    case (N32_OP6_MEM << 8) | N32_MEM_LW:
+    case (N32_OP6_MEM << 8) | N32_MEM_SW:
+      /* The range is +/-64k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S2
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S2)
+       {
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S2);
+         success = 1;
+         break;
+       }
+    default:
+      break;
+    }
 
-         /* Search for INSN16 reloc.  */
-         if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16)
-           {
-             if (label_rel)
-               {
-                 /* Previous LABEL reloc exists.  Try to resolve it.  */
-                 if (label_rel->r_offset == irel->r_offset)
-                   {
-                     /* LABEL and INSN are at the same addr.  */
-                     if ((irel->r_offset
-                          - get_nds32_elf_blank_total (&relax_blank_list,
-                                                       irel->r_offset,
-                                                       1)) & 0x02)
-                       {
-                         if (irel->r_addend > 1)
-                           {
-                             /* Force to relax.  */
-                             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                                          R_NDS32_NONE);
-                             if (is_convert_32_to_16
-                                 (abfd, sec, irel, internal_relocs, irelend,
-                                  &insn16))
-                               {
-                                 nds32_elf_write_16 (abfd, contents, irel,
-                                                     internal_relocs, irelend,
-                                                     insn16);
-
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list, irel->r_offset + 2,
-                                      2))
-                                   goto error_return;
-                               }
-                             else if (is_16bit_NOP (abfd, sec, irel))
-                               {
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list, irel->r_offset, 2))
-                                   goto error_return;
-                               }
-                           }
-                         else
-                           {
-                             if (is_convert_32_to_16
-                                 (abfd, sec, irel, internal_relocs, irelend,
-                                  &insn16)
-                                 || is_16bit_NOP (abfd, sec, irel))
-                               insn_rel = irel;
-                           }
-                         label_rel = NULL;
-                         continue;
-                       }
-                     else
-                       {
-                         /* Already aligned, reset LABEL and keep INSN16.  */
-                       }
-                   }
-                 else
-                   {
-                     /* No INSN16 to relax, we don't want to insert 16-bit.  */
-                     /* Nop here, just signal the algorithm is wrong.  */
-                   }
-                 label_rel = NULL;
-               }
-             /* A new INSN16 found, resize the old one.  */
-             else if (insn_rel)
-               {
-                 if (!is_convert_32_to_16
-                     (abfd, sec, irel, internal_relocs, irelend,
-                      &insn16)
-                     && !is_16bit_NOP (abfd, sec, irel))
-                   {
-                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                                  R_NDS32_NONE);
-                     continue;
-                   }
-                 /* Previous INSN16 reloc exists, reduce its size to 16-bit.  */
-                 if (is_convert_32_to_16
-                     (abfd, sec, insn_rel, internal_relocs, irelend,
-                      &insn16))
-                   {
-                     nds32_elf_write_16 (abfd, contents, insn_rel,
-                                         internal_relocs, irelend, insn16);
+  if (success)
+    {
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
+       {
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
+       }
+    }
+}
 
-                     if (!insert_nds32_elf_blank_recalc_total
-                         (&relax_blank_list, insn_rel->r_offset + 2, 2))
-                       goto error_return;
-                   }
-                 else if (is_16bit_NOP (abfd, sec, insn_rel))
-                   {
-                     if (!insert_nds32_elf_blank_recalc_total
-                         (&relax_blank_list, insn_rel->r_offset, 2))
-                       goto error_return;
-                   }
-                 insn_rel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                 R_NDS32_NONE);
-                 insn_rel = NULL;
-               }
+/* Relax PTR relocation for nds32_elf_relax_section.  */
 
-             if (is_convert_32_to_16
-                 (abfd, sec, irel, internal_relocs, irelend, &insn16)
-                 || is_16bit_NOP (abfd, sec, irel))
-               {
-                 insn_rel = irel;
-               }
-             /* Save the new one for later use.  */
-           }
-         /* Search for label.  */
-         else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL)
-           {
-             /* Label on 16-bit instruction, just reset this reloc.  */
-             insn16 = bfd_getb16 (contents + irel->r_offset);
-             if ((irel->r_addend & 0x1f) < 2 && (insn16 & 0x8000))
-               {
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 continue;
-               }
+static bfd_boolean
+nds32_elf_relax_ptr (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                    Elf_Internal_Rela *internal_relocs, int *insn_len,
+                    int *seq_len, bfd_byte *contents)
+{
+  Elf_Internal_Rela *ptr_irel, *irelend, *count_irel, *re_irel;
 
-             if (!optimize && (irel->r_addend & 0x1f) < 2)
-               {
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 continue;
-               }
+  irelend = internal_relocs + sec->reloc_count;
 
-             /* Try to align this label.  */
-             if (insn_rel)
-               {
-                 int force_relax = 0;
+  re_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_PTR_RESOLVED, irel->r_addend);
 
-                 /* If current location is .align 2, we can't relax previous 32-bit inst.  */
-                 /* Or the alignment constraint is broke.  */
-                 if ((irel->r_addend & 0x1f) < 2)
-                   {
-                     /* Label_rel always seats before insn_rel after our sort.  */
+  if (re_irel == irelend)
+    {
+      (*_bfd_error_handler)
+       ("%B: warning: R_NDS32_PTR points to unrecognized reloc at 0x%lx.",
+        abfd, (long) irel->r_offset);
+      return FALSE;
+    }
 
-                     /* INSN16 and LABEL at different location.  */
-                     /* Search for INSN16 at LABEL location.  */
-                     for (tmp_rel = irel;
-                          tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset;
-                          tmp_rel++)
-                       {
-                         if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16)
-                           break;
-                       }
+  if (re_irel->r_addend != 1)
+    return FALSE;
 
-                     if (tmp_rel < irelend
-                         && tmp_rel->r_offset == irel->r_offset)
-                       {
-                         if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16)
-                           {
-                             if (is_convert_32_to_16
-                                 (abfd, sec, tmp_rel, internal_relocs,
-                                  irelend, &insn16)
-                                 || is_16bit_NOP (abfd, sec, tmp_rel))
-                               force_relax = 1;
-                           }
-                       }
-                   }
+  /* Pointed target is relaxed and no longer needs this void *,
+     change the type to NONE.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-                 if ((irel->r_offset
-                      - get_nds32_elf_blank_total (&relax_blank_list,
-                                                   irel->r_offset, 1)) & 0x01)
-                   {
-                     /* Can't align on byte, BIG ERROR.  */
-                   }
-                 else
+  /* Find PTR_COUNT to decide remove it or not.  If PTR_COUNT does
+     not exist, it means only count 1 and remove it directly.  */
+  /* TODO: I hope we can obsolate R_NDS32_COUNT in the future.  */
+  count_irel = find_relocs_at_address (irel, internal_relocs, irelend,
+                                      R_NDS32_PTR_COUNT);
+  ptr_irel = find_relocs_at_address (irel, internal_relocs, irelend,
+                                    R_NDS32_PTR);
+  if (count_irel != irelend)
+    {
+      if (--count_irel->r_addend > 0)
+       return FALSE;
+    }
+
+  if (ptr_irel != irelend)
+    return FALSE;
+
+  /* If the PTR_COUNT is already 0, remove current instruction.  */
+  *seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset);
+  *insn_len = 0;
+  return TRUE;
+}
+
+/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section.  */
+
+static void
+nds32_elf_relax_pltgot_suff (struct bfd_link_info *link_info, bfd *abfd,
+                            asection *sec, Elf_Internal_Rela *irel,
+                            Elf_Internal_Rela *internal_relocs,
+                            bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                            Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
+{
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  /* FIXME: It's a little trouble to turn JRAL5 to JAL since
+     we need additional space.  It might be help if we could
+     borrow some space from instructions to be eliminated
+     such as sethi, ori, add.  */
+  if (insn & 0x80000000)
+    return;
+
+  if (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF))
+    return;
+
+  i1_irelfn =
+    find_relocs_at_address (irel, internal_relocs, irelend,
+                           R_NDS32_PTR_RESOLVED);
+
+  /* FIXIT 090606
+     The boundary should be reduced since the .plt section hasn't
+     been created and the address of specific entry is still unknown
+     Maybe the range between the function call and the begin of the
+     .text section can be used to decide if the .plt is in the range
+     of function call.  */
+
+  if (N32_OP6 (insn) == N32_OP6_ALU1
+      && N32_SUB5 (insn) == N32_ALU1_ADD)
+    {
+      /* Get the value of the symbol referred to by the reloc.  */
+      nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                               &local_sda, FALSE);
+      foff = (bfd_signed_vma) (calculate_plt_memory_address
+                              (abfd, link_info, isymbuf, irel,
+                               symtab_hdr) - local_sda);
+      /* This condition only happened when symbol is undefined.  */
+      if (foff == 0)
+       return;
+
+      if (foff < -CONSERVATIVE_19BIT || foff >= CONSERVATIVE_19BIT)
+       return;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                  R_NDS32_PLT_GOTREL_LO19);
+      /* addi.gp */
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19));
+    }
+  else if (N32_OP6 (insn) == N32_OP6_JREG
+          && N32_SUB5 (insn) == N32_JREG_JRAL)
+    {
+      /* Get the value of the symbol referred to by the reloc.  */
+      foff =
+       calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, symtab_hdr);
+      /* This condition only happened when symbol is undefined.  */
+      if (foff == 0)
+       return;
+      if (foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1)
+       return;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL);
+      insn = INSN_JAL;
+    }
+  else
+    return;
+
+  bfd_putb32 (insn, contents + laddr);
+  if (i1_irelfn != irelend)
+    {
+      i1_irelfn->r_addend |= 1;
+      *again = TRUE;
+    }
+}
+
+/* Relax GOT_SUFF relocation for nds32_elf_relax_section.  */
+
+static void
+nds32_elf_relax_got_suff (struct bfd_link_info *link_info, bfd *abfd,
+                         asection *sec, Elf_Internal_Rela *irel,
+                         Elf_Internal_Rela *internal_relocs,
+                         bfd_byte *contents, Elf_Internal_Shdr *symtab_hdr,
+                         bfd_boolean *again)
+{
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  if (insn & 0x80000000)
+    return;
+
+  if (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF))
+    return;
+
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  foff = calculate_got_memory_address (abfd, link_info, irel,
+                                      symtab_hdr) - local_sda;
+
+  if (foff < CONSERVATIVE_19BIT && foff >= -CONSERVATIVE_19BIT)
+    {
+      /* Turn LW to LWI.GP.  Change relocation type to R_NDS32_GOT_REL.  */
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA);
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
+       {
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
+       }
+    }
+}
+
+/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section.  */
+
+static void
+nds32_elf_relax_gotoff_suff (struct bfd_link_info *link_info, bfd *abfd,
+                            asection *sec, Elf_Internal_Rela *irel,
+                            Elf_Internal_Rela *internal_relocs,
+                            bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                            Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
+{
+  int opc_insn_gotoff;
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *i2_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  if (insn & 0x80000000)
+    return;
+
+  if (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF))
+    return;
+
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  foff = foff - local_sda;
+
+  if (foff >= CONSERVATIVE_19BIT || foff < -CONSERVATIVE_19BIT)
+    return;
+
+  /* Concatenate opcode and sub-opcode for switch case.
+     It may be MEM or ALU1.  */
+  opc_insn_gotoff = (N32_OP6 (insn) << 8) | (insn & 0xff);
+  switch (opc_insn_gotoff)
+    {
+    case (N32_OP6_MEM << 8) | N32_MEM_LW:
+      /* 4-byte aligned.  */
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_SW:
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (7, 17, 3));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA17S2_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_LH:
+      /* 2-byte aligned.  */
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_LHS:
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_SH:
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA18S1_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_LB:
+      /* 1-byte aligned.  */
+      insn = N32_TYPE1 (LBGP, N32_RT5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_LBS:
+      insn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_SB:
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD:
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    default:
+      return;
+    }
+
+  bfd_putb32 (insn, contents + laddr);
+  if (i1_irelfn != irelend)
+    {
+      i1_irelfn->r_addend |= 1;
+      *again = TRUE;
+    }
+  if ((i2_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                          R_NDS32_INSN16)) != irelend)
+    i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+
+}
+
+static bfd_boolean
+nds32_relax_adjust_label (bfd *abfd, asection *sec,
+                         Elf_Internal_Rela *internal_relocs,
+                         bfd_byte *contents,
+                         nds32_elf_blank_t **relax_blank_list,
+                         int optimize, int opt_size)
+{
+  /* This code block is used to adjust 4-byte alignment by relax a pair
+     of instruction a time.
+
+     It recognizes three types of relocations.
+     1. R_NDS32_LABEL - a aligment.
+     2. R_NDS32_INSN16 - relax a 32-bit instruction to 16-bit.
+     3. is_16bit_NOP () - remove a 16-bit instruction.  */
+
+  /* TODO: It seems currently implementation only support 4-byte aligment.
+     We should handle any-aligment.  */
+
+  Elf_Internal_Rela *insn_rel = NULL, *label_rel = NULL, *irel;
+  Elf_Internal_Rela *tmp_rel, *tmp2_rel = NULL;
+  Elf_Internal_Rela rel_temp;
+  Elf_Internal_Rela *irelend;
+  bfd_vma address;
+  uint16_t insn16;
+
+  /* Checking for branch relaxation relies on the relocations to
+     be sorted on 'r_offset'.  This is not guaranteed so we must sort.  */
+  nds32_insertion_sort (internal_relocs, sec->reloc_count,
+                       sizeof (Elf_Internal_Rela), compar_reloc);
+
+  irelend = internal_relocs + sec->reloc_count;
+
+  /* Force R_NDS32_LABEL before R_NDS32_INSN16.  */
+  /* FIXME: Can we generate the right order in assembler?
+     So we don't have to swapping them here.  */
+
+  for (label_rel = internal_relocs, insn_rel = internal_relocs;
+       label_rel < irelend; label_rel++)
+    {
+      if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL)
+       continue;
+
+      /* Find the first reloc has the same offset with label_rel.  */
+      while (insn_rel < irelend && insn_rel->r_offset < label_rel->r_offset)
+       insn_rel++;
+
+      for (;insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset;
+          insn_rel++)
+       /* Check if there were R_NDS32_INSN16 and R_NDS32_LABEL at the same
+          address.  */
+       if (ELF32_R_TYPE (insn_rel->r_info) == R_NDS32_INSN16)
+         break;
+
+      if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset
+         && insn_rel < label_rel)
+       {
+         /* Swap the two reloc if the R_NDS32_INSN16 is
+            before R_NDS32_LABEL.  */
+         memcpy (&rel_temp, insn_rel, sizeof (Elf_Internal_Rela));
+         memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela));
+         memcpy (label_rel, &rel_temp, sizeof (Elf_Internal_Rela));
+       }
+    }
+
+  label_rel = NULL;
+  insn_rel = NULL;
+  /* If there were a sequence of R_NDS32_LABEL end up with .align 2
+     or higher, remove other R_NDS32_LABEL with lower alignment.
+     If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted,
+     then the R_NDS32_LABEL sequence is broke.  */
+  for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++)
+    {
+      if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL)
+       {
+         if (label_rel == NULL)
+           {
+             if (tmp_rel->r_addend < 2)
+               label_rel = tmp_rel;
+             continue;
+           }
+         else if (tmp_rel->r_addend > 1)
+           {
+             /* Remove all LABEL relocation from label_rel to tmp_rel
+                including relocations with same offset as tmp_rel.  */
+             for (tmp2_rel = label_rel; tmp2_rel < tmp_rel
+                  || tmp2_rel->r_offset == tmp_rel->r_offset; tmp2_rel++)
+               {
+                 if (ELF32_R_TYPE (tmp2_rel->r_info) == R_NDS32_LABEL
+                     && tmp2_rel->r_addend < 2)
+                   tmp2_rel->r_info =
+                     ELF32_R_INFO (ELF32_R_SYM (tmp2_rel->r_info),
+                                   R_NDS32_NONE);
+               }
+             label_rel = NULL;
+           }
+       }
+      else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16 && label_rel)
+       {
+         /* A new INSN16 which can be converted, so clear label_rel.  */
+         if (is_convert_32_to_16 (abfd, sec, tmp_rel, internal_relocs,
+                                  irelend, &insn16)
+             || is_16bit_NOP (abfd, sec, tmp_rel))
+           label_rel = NULL;
+       }
+    }
+
+  label_rel = NULL;
+  insn_rel = NULL;
+  /* Optimized for speed and nothing has not been relaxed.
+     It's time to align labels.
+     We may convert a 16-bit instruction right before a label to
+     32-bit, in order to align the label if necessary
+     all reloc entries has been sorted by r_offset.  */
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16
+         && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL)
+       continue;
+
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16)
+       {
+         /* A new INSN16 found, resize the old one.  */
+         if (is_convert_32_to_16
+             (abfd, sec, irel, internal_relocs, irelend, &insn16)
+             || is_16bit_NOP (abfd, sec, irel))
+           {
+             if (insn_rel)
+               {
+                 /* Previous INSN16 reloc exists, reduce its
+                    size to 16-bit.  */
+                 if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs,
+                                          irelend, &insn16))
                    {
-                     if (force_relax
-                         || ((irel->r_offset
-                              - get_nds32_elf_blank_total
-                                  (&relax_blank_list, irel->r_offset, 1))
-                             & 0x02)
-                         || irel->r_addend == 1)
-                       {
-                         if (insn_rel != NULL)
-                           {
-                             /* Label not aligned.  */
-                             /* Previous reloc exists, reduce its size to 16-bit.  */
-                             if (is_convert_32_to_16
-                                 (abfd, sec, insn_rel, internal_relocs,
-                                  irelend, &insn16))
-                               {
-                                 nds32_elf_write_16 (abfd, contents, insn_rel,
-                                                     internal_relocs, irelend,
-                                                     insn16);
-
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list,
-                                      insn_rel->r_offset + 2, 2))
-                                   goto error_return;
-                               }
-                             else if (is_16bit_NOP (abfd, sec, insn_rel))
-                               {
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list, insn_rel->r_offset,
-                                      2))
-                                   goto error_return;
-                               }
-                             else
-                               {
-                                 goto error_return;
-                               }
-                           }
-                       }
+                     nds32_elf_write_16 (abfd, contents, insn_rel,
+                                         internal_relocs, irelend, insn16);
+
+                     if (!insert_nds32_elf_blank_recalc_total
+                         (relax_blank_list, insn_rel->r_offset + 2, 2))
+                       return FALSE;
+                   }
+                 else if (is_16bit_NOP (abfd, sec, insn_rel))
+                   {
+                     if (!insert_nds32_elf_blank_recalc_total
+                         (relax_blank_list, insn_rel->r_offset, 2))
+                       return FALSE;
+                   }
+                 insn_rel->r_info =
+                   ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), R_NDS32_NONE);
+               }
+             /* Save the new one for later use.  */
+             insn_rel = irel;
+           }
+         else
+           irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                        R_NDS32_NONE);
+       }
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL)
+       {
+         /* Search for label.  */
+         int force_relax = 0;
+
+         /* Label on 16-bit instruction or optimization
+            needless, just reset this reloc.  */
+         insn16 = bfd_getb16 (contents + irel->r_offset);
+         if ((irel->r_addend & 0x1f) < 2 && (!optimize || (insn16 & 0x8000)))
+           {
+             irel->r_info =
+               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+             continue;
+           }
+
+         address =
+           irel->r_offset - get_nds32_elf_blank_total (relax_blank_list,
+                                                       irel->r_offset, 1);
+
+         if (!insn_rel)
+           {
+             /* Check if there is case which can not be aligned.  */
+             if (irel->r_addend == 2 && address & 0x2)
+               return FALSE;
+             continue;
+           }
+
+         /* Try to align this label.  */
+
+         if ((irel->r_addend & 0x1f) < 2)
+           {
+             /* Check if there is a INSN16 at the same address.
+                Label_rel always seats before insn_rel after
+                our sort.  */
+
+             /* Search for INSN16 at LABEL location.  If INSN16 is at
+                same location and this LABEL alignment is lower than 2,
+                the INSN16 can be converted to 2-byte.  */
+             for (tmp_rel = irel;
+                  tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset;
+                  tmp_rel++)
+               {
+                 if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16
+                     && (is_convert_32_to_16
+                         (abfd, sec, tmp_rel, internal_relocs,
+                          irelend, &insn16)
+                         || is_16bit_NOP (abfd, sec, tmp_rel)))
+                   {
+                     force_relax = 1;
+                     break;
+                   }
+               }
+           }
+
+         if (force_relax || irel->r_addend == 1 || address & 0x2)
+           {
+             /* Label not aligned.  */
+             /* Previous reloc exists, reduce its size to 16-bit.  */
+             if (is_convert_32_to_16 (abfd, sec, insn_rel,
+                                      internal_relocs, irelend, &insn16))
+               {
+                 nds32_elf_write_16 (abfd, contents, insn_rel,
+                                     internal_relocs, irelend, insn16);
+
+                 if (!insert_nds32_elf_blank_recalc_total
+                     (relax_blank_list, insn_rel->r_offset + 2, 2))
+                   return FALSE;
+               }
+             else if (is_16bit_NOP (abfd, sec, insn_rel))
+               {
+                 if (!insert_nds32_elf_blank_recalc_total
+                     (relax_blank_list, insn_rel->r_offset, 2))
+                   return FALSE;
+               }
+
+           }
+         /* INSN16 reloc is used.  */
+         insn_rel = NULL;
+       }
+    }
+
+  address =
+    sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0);
+  if (insn_rel && (address & 0x2 || opt_size))
+    {
+      if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs,
+                              irelend, &insn16))
+       {
+         nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs,
+                             irelend, insn16);
+         if (!insert_nds32_elf_blank_recalc_total
+             (relax_blank_list, insn_rel->r_offset + 2, 2))
+           return FALSE;
+         insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
+                                          R_NDS32_NONE);
+       }
+      else if (is_16bit_NOP (abfd, sec, insn_rel))
+       {
+         if (!insert_nds32_elf_blank_recalc_total
+             (relax_blank_list, insn_rel->r_offset, 2))
+           return FALSE;
+         insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
+                                          R_NDS32_NONE);
+       }
+    }
+  insn_rel = NULL;
+  return TRUE;
+}
+
+/* Pick relaxation round.  */
+
+static int
+nds32_elf_pick_relax (bfd_boolean init, asection *sec, bfd_boolean *again,
+                     struct elf_nds32_link_hash_table *table,
+                     struct bfd_link_info *link_info)
+{
+  static asection *final_sec;
+  static bfd_boolean set = FALSE;
+  static bfd_boolean first = TRUE;
+  int round_table[] = {
+      NDS32_RELAX_NORMAL_ROUND,
+      NDS32_RELAX_JUMP_IFC_ROUND,
+      NDS32_RELAX_EX9_BUILD_ROUND,
+      NDS32_RELAX_EX9_REPLACE_ROUND,
+  };
+  static int pass = 0;
+  static int relax_round;
+
+  if (first)
+    {
+      /* Run an empty run to get the final section.  */
+      relax_round = NDS32_RELAX_EMPTY_ROUND;
+
+      /* It has to enter relax again because we can
+        not make sure what the final turn is.  */
+      *again = TRUE;
+      first = FALSE;
+    }
+
+  if (!set && *again)
+    {
+      /* It is reentered when again is FALSE.  */
+      final_sec = sec;
+      return relax_round;
+    }
+
+  /* The second round begins.  */
+  set = TRUE;
+
+  relax_round = round_table[pass];
+
+  if (!init && final_sec == sec)
+    {
+      switch (relax_round)
+       {
+       case NDS32_RELAX_NORMAL_ROUND:
+         if (!*again)
+           {
+             /* Normal relaxation done.  */
+             if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON)
+               {
+                 pass++;
+                 *again = TRUE;
+               }
+             else if (table->target_optimize & NDS32_RELAX_EX9_ON)
+               {
+                 pass += 2;    /* NDS32_RELAX_EX9_BUILD_ROUND */
+                 *again = TRUE;
+               }
+             else if (table->ex9_import_file)
+               {
+                 /* Import ex9 table.  */
+                 if (table->update_ex9_table)
+                   pass += 2;  /* NDS32_RELAX_EX9_BUILD_ROUND */
+                 else
+                   pass += 3;  /* NDS32_RELAX_EX9_REPLACE_ROUND */
+                 nds32_elf_ex9_import_table (link_info);
+                 *again = TRUE;
+               }
+           }
+         break;
+       case NDS32_RELAX_JUMP_IFC_ROUND:
+         if (!nds32_elf_ifc_finish (link_info))
+           (*_bfd_error_handler) (_("error: Jump IFC Fail."));
+         if (table->target_optimize & NDS32_RELAX_EX9_ON)
+           {
+             pass++;
+             *again = TRUE;
+           }
+         break;
+       case NDS32_RELAX_EX9_BUILD_ROUND:
+         nds32_elf_ex9_finish (link_info);
+         pass++;
+         *again = TRUE;
+         break;
+       case NDS32_RELAX_EX9_REPLACE_ROUND:
+         if (table->target_optimize & NDS32_RELAX_JUMP_IFC_ON)
+           {
+             /* Do jump IFC optimization again.  */
+             if (!nds32_elf_ifc_finish (link_info))
+               (*_bfd_error_handler) (_("error: Jump IFC Fail."));
+           }
+         break;
+       default:
+         break;
+       }
+    }
+
+  return relax_round;
+}
+
+static bfd_boolean
+nds32_elf_relax_section (bfd *abfd, asection *sec,
+                        struct bfd_link_info *link_info, bfd_boolean *again)
+{
+  nds32_elf_blank_t *relax_blank_list = NULL;
+  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Rela *internal_relocs;
+  Elf_Internal_Rela *irel;
+  Elf_Internal_Rela *irelend;
+  Elf_Internal_Sym *isymbuf = NULL;
+  bfd_byte *contents = NULL;
+  bfd_boolean result = TRUE;
+  int optimize = 0;
+  int opt_size = 0;
+  uint32_t insn;
+  uint16_t insn16;
+
+  /* Target dependnet option.  */
+  struct elf_nds32_link_hash_table *table;
+  int load_store_relax;
+  int relax_round;
+
+  relax_blank_list = NULL;
+
+  *again = FALSE;
+
+  /* Nothing to do for
+   * relocatable link or
+   * non-relocatable section or
+   * non-code section or
+   * empty content or
+   * no reloc entry.  */
+  if (link_info->relocatable
+      || (sec->flags & SEC_RELOC) == 0
+      || (sec->flags & SEC_EXCLUDE) == 1
+      || (sec->flags & SEC_CODE) == 0
+      || sec->size == 0)
+    return TRUE;
+
+  /* 09.12.11 Workaround.  */
+  /*  We have to adjust align for R_NDS32_LABEL if needed.
+      The adjust approach only can fix 2-byte align once.  */
+  if (sec->alignment_power > 2)
+    return TRUE;
+
+  /* The optimization type to do.  */
+
+  table = nds32_elf_hash_table (link_info);
+  relax_round = nds32_elf_pick_relax (TRUE, sec, again, table, link_info);
+  switch (relax_round)
+    {
+    case NDS32_RELAX_JUMP_IFC_ROUND:
+      /* Here is the entrance of ifc jump relaxation.  */
+      if (!nds32_elf_ifc_calc (link_info, abfd, sec))
+       return FALSE;
+      nds32_elf_pick_relax (FALSE, sec, again, table, link_info);
+      return TRUE;
+
+    case NDS32_RELAX_EX9_BUILD_ROUND:
+      /* Here is the entrance of ex9 relaxation.  There are two pass of
+        ex9 relaxation.  The one is to traverse all instructions and build
+        the hash table.  The other one is to compare instructions and replace
+        it by ex9.it.  */
+      if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info))
+       return FALSE;
+      nds32_elf_pick_relax (FALSE, sec, again, table, link_info);
+      return TRUE;
+
+    case NDS32_RELAX_EX9_REPLACE_ROUND:
+      if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec))
+       return FALSE;
+      return TRUE;
+
+    case NDS32_RELAX_EMPTY_ROUND:
+      nds32_elf_pick_relax (FALSE, sec, again, table, link_info);
+      return TRUE;
+
+    case NDS32_RELAX_NORMAL_ROUND:
+    default:
+      if (sec->reloc_count == 0)
+       return TRUE;
+      break;
+    }
+
+  /* The begining of general relaxation.  */
+
+  if (is_SDA_BASE_set == 0)
+    {
+      bfd_vma gp;
+      is_SDA_BASE_set = 1;
+      nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                               &gp, FALSE);
+      relax_range_measurement (abfd);
+    }
+
+  if (is_ITB_BASE_set == 0)
+    {
+      /* Set the _ITB_BASE_.  */
+      if (!nds32_elf_ex9_itb_base (link_info))
+       {
+         (*_bfd_error_handler) (_("%B: error: Cannot set _ITB_BASE_"), abfd);
+         bfd_set_error (bfd_error_bad_value);
+       }
+    }
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  /* Relocations MUST be kept in memory, because relaxation adjust them.  */
+  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+                                              TRUE /* keep_memory */);
+  if (internal_relocs == NULL)
+    goto error_return;
+
+  irelend = internal_relocs + sec->reloc_count;
+  irel = find_relocs_at_address (internal_relocs, internal_relocs,
+                                irelend, R_NDS32_RELAX_ENTRY);
+
+  if (irel == irelend)
+    return TRUE;
+
+  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY)
+    {
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG)
+       return TRUE;
+
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG)
+       optimize = 1;
+
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG)
+       opt_size = 1;
+    }
+
+  load_store_relax = table->load_store_relax;
+
+  /* Get symbol table and section content.  */
+  if (!nds32_get_section_contents (abfd, sec, &contents)
+      || !nds32_get_local_syms (abfd, sec, &isymbuf))
+    goto error_return;
+
+  /* Do relax loop only when finalize is not done.
+     Take care of relaxable relocs except INSN16.  */
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      int seq_len;             /* Original length of instruction sequence.  */
+      int insn_len = 0;                /* Final length of instruction sequence.  */
+      bfd_boolean removed;
+
+      insn = 0;
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
+         && (irel->r_addend & 0x1f) >= 2)
+       optimize = 1;
+
+      /* Relocation Types
+        R_NDS32_LONGCALL1      53
+        R_NDS32_LONGCALL2      54
+        R_NDS32_LONGCALL3      55
+        R_NDS32_LONGJUMP1      56
+        R_NDS32_LONGJUMP2      57
+        R_NDS32_LONGJUMP3      58
+        R_NDS32_LOADSTORE      59  */
+      if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
+         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE)
+       seq_len = GET_SEQ_LEN (irel->r_addend);
+
+      /* Relocation Types
+        R_NDS32_LONGCALL4      107
+        R_NDS32_LONGCALL5      108
+        R_NDS32_LONGCALL6      109
+        R_NDS32_LONGJUMP4      110
+        R_NDS32_LONGJUMP5      111
+        R_NDS32_LONGJUMP6      112
+        R_NDS32_LONGJUMP7      113  */
+      else if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL4
+              && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP7)
+       seq_len = 4;
+
+       /* Relocation Types
+        R_NDS32_LO12S0_RELA            30
+        R_NDS32_LO12S1_RELA            29
+        R_NDS32_LO12S2_RELA            28
+        R_NDS32_LO12S2_SP_RELA         71
+        R_NDS32_LO12S2_DP_RELA         70
+        R_NDS32_GOT_LO12               46
+        R_NDS32_GOTOFF_LO12            50
+        R_NDS32_PLTREL_LO12            65
+        R_NDS32_PLT_GOTREL_LO12        67
+        R_NDS32_17IFC_PCREL_RELA       96
+        R_NDS32_GOT_SUFF               193
+        R_NDS32_GOTOFF_SUFF            194
+        R_NDS32_PLT_GOT_SUFF           195
+        R_NDS32_MULCALL_SUFF           196
+        R_NDS32_PTR                    197  */
+      else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA
+               && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA)
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12
+              || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF
+                  && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR)
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_ADD
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LS)
+       seq_len = 0;
+      else
+       continue;
+
+      insn_len = seq_len;
+      removed = FALSE;
+
+      switch (ELF32_R_TYPE (irel->r_info))
+       {
+       case R_NDS32_LONGCALL1:
+         removed = nds32_elf_relax_longcall1 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL2:
+         removed = nds32_elf_relax_longcall2 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL3:
+         removed = nds32_elf_relax_longcall3 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP1:
+         removed = nds32_elf_relax_longjump1 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP2:
+         removed = nds32_elf_relax_longjump2 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP3:
+         removed = nds32_elf_relax_longjump3 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL4:
+         removed = nds32_elf_relax_longcall4 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL5:
+         removed = nds32_elf_relax_longcall5 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL6:
+         removed = nds32_elf_relax_longcall6 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP4:
+         removed = nds32_elf_relax_longjump4 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP5:
+         removed = nds32_elf_relax_longjump5 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP6:
+         removed = nds32_elf_relax_longjump6 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP7:
+         removed = nds32_elf_relax_longjump7 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LOADSTORE:
+         removed = nds32_elf_relax_loadstore (link_info, abfd, sec, irel,
+                                              internal_relocs, &insn_len,
+                                              contents, isymbuf, symtab_hdr,
+                                              load_store_relax);
+         break;
+       case R_NDS32_LO12S0_RELA:
+       case R_NDS32_LO12S1_RELA:
+       case R_NDS32_LO12S2_DP_RELA:
+       case R_NDS32_LO12S2_SP_RELA:
+       case R_NDS32_LO12S2_RELA:
+         /* Relax for low part.  */
+         nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs,
+                               contents, isymbuf, symtab_hdr);
+
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOT_LO12:
+       case R_NDS32_GOTOFF_LO12:
+       case R_NDS32_PLTREL_LO12:
+       case R_NDS32_PLT_GOTREL_LO12:
+       case R_NDS32_GOTPC_LO12:
+         /* Relax for PIC gp-relative low part.  */
+         nds32_elf_relax_piclo12 (link_info, abfd, sec, irel, contents,
+                                  isymbuf, symtab_hdr);
 
-                     if (force_relax)
-                       {
-                         label_rel = irel;
-                       }
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_LO12:
+         /* Relax for LE TLS low part.  */
+         nds32_elf_relax_letlslo12 (link_info, abfd, irel, contents,
+                                    isymbuf, symtab_hdr);
 
-                     /* INSN16 reloc is used.  */
-                     insn_rel = NULL;
-                   }
-               }
-           }
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_ADD:
+         nds32_elf_relax_letlsadd (link_info, abfd, sec, irel, internal_relocs,
+                                   contents, isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_LS:
+         nds32_elf_relax_letlsls (link_info, abfd, sec, irel, internal_relocs,
+                                  contents, isymbuf, symtab_hdr, again);
+         continue;
+       case R_NDS32_PTR:
+         removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs,
+                                        &insn_len, &seq_len, contents);
+         break;
+       case R_NDS32_PLT_GOT_SUFF:
+         nds32_elf_relax_pltgot_suff (link_info, abfd, sec, irel,
+                                      internal_relocs, contents,
+                                      isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOT_SUFF:
+         nds32_elf_relax_got_suff (link_info, abfd, sec, irel,
+                                   internal_relocs, contents,
+                                   symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOTOFF_SUFF:
+         nds32_elf_relax_gotoff_suff (link_info, abfd, sec, irel,
+                                      internal_relocs, contents,
+                                      isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       default:
+         continue;
+
+       }
+      if (removed && seq_len - insn_len > 0)
+       {
+         if (!insert_nds32_elf_blank
+             (&relax_blank_list, irel->r_offset + insn_len,
+              seq_len - insn_len))
+           goto error_return;
+         *again = TRUE;
        }
+    }
+
+  calc_nds32_blank_total (relax_blank_list);
+
+  if (table->relax_fp_as_gp)
+    {
+      if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs,
+                                irelend, isymbuf))
+       goto error_return;
 
-      if (insn_rel)
+      if (*again == FALSE)
        {
-         if (((sec->size - get_nds32_elf_blank_total (&relax_blank_list, sec->size, 0))
-              - ((sec->size - get_nds32_elf_blank_total (&relax_blank_list, sec->size, 0))
-                 & (0xffffffff << sec->alignment_power)) == 2)
-             || optimize_for_space)
-           {
-             if (is_convert_32_to_16
-                 (abfd, sec, insn_rel, internal_relocs, irelend,
-                  &insn16))
-               {
-                 nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs,
-                                     irelend, insn16);
-                 if (!insert_nds32_elf_blank_recalc_total
-                     (&relax_blank_list, insn_rel->r_offset + 2, 2))
-                   goto error_return;
-                 insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                                  R_NDS32_NONE);
-               }
-             else if (is_16bit_NOP (abfd, sec, insn_rel))
-               {
-                 if (!insert_nds32_elf_blank_recalc_total
-                     (&relax_blank_list, insn_rel->r_offset, 2))
-                   goto error_return;
-                 insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                                  R_NDS32_NONE);
-               }
-           }
-         insn_rel = NULL;
+         if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs,
+                                              irelend))
+           goto error_return;
        }
     }
-    /* It doesn't matter optimize_for_space_no_align anymore.
+
+  nds32_elf_pick_relax (FALSE, sec, again, table, link_info);
+
+  if (*again == FALSE)
+    {
+      if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents,
+                                    &relax_blank_list, optimize, opt_size))
+       goto error_return;
+    }
+
+  /* It doesn't matter optimize_for_space_no_align anymore.
        If object file is assembled with flag '-Os',
        the we don't adjust jump-destination on 4-byte boundary.  */
 
@@ -10984,8 +12325,8 @@ nds32_elf_relax_section (bfd *abfd, asection *sec,
          sec->size += 4;
        }
 
-      tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                       R_NDS32_RELAX_ENTRY);
+      tmp_rel = find_relocs_at_address (internal_relocs, internal_relocs,
+                                       irelend, R_NDS32_RELAX_ENTRY);
       if (tmp_rel != irelend)
        tmp_rel->r_addend |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG;
 
@@ -11096,8 +12437,9 @@ bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info,
    optimization.  */
 
 #define FAG_THRESHOLD  3       /* At least 3 gp-access.  */
-#define FAG_BUMPER     8       /* Leave some space to avoid aligment issues.  */
-#define FAG_WINDOW     (512 - FAG_BUMPER)  /* lwi37.fp covers 512 bytes.  */
+/* lwi37.fp covers 508 bytes, but there may be 32-byte padding between
+   the read-only section and read-write section.  */
+#define FAG_WINDOW     (508 - 32)
 
 /* An nds32_fag represent a gp-relative access.
    We find best fp-base by using a sliding window
@@ -11204,19 +12546,13 @@ nds32_fag_free_list (struct nds32_fag *head)
     }
 }
 
-static bfd_boolean
-nds32_fag_isempty (struct nds32_fag *head)
-{
-  return head->next == NULL;
-}
-
 /* Find the best fp-base address.
    The relocation associated with that address is returned,
    so we can track the symbol instead of a fixed address.
 
    When relaxation, the address of an datum may change,
    because a text section is shrinked, so the data section
-   moves forward. If the aligments of text and data section
+   moves forward.  If the aligments of text and data section
    are different, their distance may change too.
    Therefore, tracking a fixed address is not appriate.  */
 
@@ -11235,8 +12571,11 @@ nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp)
      and accumulate following fags which are inside the window,
      untill we each the end.  */
 
-  if (nds32_fag_isempty (head))
-    return 0;
+  if (head->next == NULL)
+    {
+      *bestpp = NULL;
+      return 0;
+    }
 
   /* Initialize base.  */
   base = head->next;
@@ -11250,22 +12589,22 @@ nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp)
 
   /* Record the best base in each iteration.  */
   while (base->next)
-   {
-     accu -= base->count;
-     base = base->next;
-     /* Account fags in window.  */
-     for (/* Nothing.  */;
-         last && last->addr < base->addr + FAG_WINDOW;
-         last = last->next)
-       accu += last->count;
-
-     /* A better fp-base?  */
-     if (accu > baccu)
-       {
-        best = base;
-        baccu = accu;
-       }
-   }
+    {
+      accu -= base->count;
+      base = base->next;
+      /* Account fags in window.  */
+      for (/* Nothing.  */;
+          last && last->addr < base->addr + FAG_WINDOW;
+          last = last->next)
+       accu += last->count;
+
+      /* A better fp-base?  */
+      if (accu > baccu)
+       {
+         best = base;
+         baccu = accu;
+       }
+    }
 
   if (bestpp)
     *bestpp = best;
@@ -11291,8 +12630,8 @@ nds32_fag_mark_relax (struct bfd_link_info *link_info,
   nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
   best_fpbase = best_fag->addr;
 
-  if (best_fpbase > gp + sdata_range[4][1]
-      || best_fpbase < gp - sdata_range[4][0])
+  if (best_fpbase > gp + sdata_range[1][1]
+      || best_fpbase < gp - sdata_range[1][0])
     return FALSE;
 
   /* Mark these inside the window R_NDS32_INSN16_FP7U2_FLAG flag,
@@ -11322,6 +12661,34 @@ nds32_fag_mark_relax (struct bfd_link_info *link_info,
   return TRUE;
 }
 
+/* Reset INSN16 to clean fp as gp.  */
+
+static void
+nds32_fag_unmark_relax (struct nds32_fag *fag,
+                       Elf_Internal_Rela *internal_relocs,
+                       Elf_Internal_Rela *irelend)
+{
+  struct nds32_fag *ifag;
+  int i;
+  Elf_Internal_Rela *insn16_rel;
+  Elf_Internal_Rela *fag_rel;
+
+  for (ifag = fag; ifag; ifag = ifag->next)
+    {
+      for (i = 0; i < ifag->count; i++)
+       {
+         fag_rel = ifag->relas[i];
+
+         /* Restore the INSN16 relocation.  */
+         insn16_rel = find_relocs_at_address
+           (fag_rel, internal_relocs, irelend, R_NDS32_INSN16);
+
+         if (insn16_rel != irelend)
+           insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG;
+       }
+    }
+}
+
 /* This is the main function of fp-as-gp optimization.
    It should be called by relax_section.  */
 
@@ -11337,6 +12704,7 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info,
   struct nds32_fag fag_head;
   Elf_Internal_Shdr *symtab_hdr;
   bfd_byte *contents;
+  bfd_boolean ifc_inside = FALSE;
 
   /* FIXME: Can we bfd_elf_link_read_relocs for the relocs?  */
 
@@ -11385,12 +12753,13 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info,
 
          begin_rel = irel;
          nds32_fag_init (&fag_head);
+         ifc_inside = FALSE;
        }
       else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END
               && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG))
        {
          int accu;
-         struct nds32_fag *best_fag;
+         struct nds32_fag *best_fag, *tmp_fag;
          int dist;
 
          /* End of the region.
@@ -11404,6 +12773,10 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info,
 
          accu = nds32_fag_find_base (&fag_head, &best_fag);
 
+         /* Clean FP7U2_FLAG because they may set ever.  */
+         tmp_fag = fag_head.next;
+         nds32_fag_unmark_relax (tmp_fag, internal_relocs, irelend);
+
          /* Check if it is worth, and FP_BASE is near enough to SDA_BASE.  */
          if (accu < FAG_THRESHOLD
              || !nds32_fag_mark_relax (link_info, abfd, best_fag,
@@ -11426,13 +12799,14 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info,
          BFD_ASSERT (dist > 0 && dist < 0xffffff);
          /* Use high 16 bits of addend to record the _FP_BASE_ matched
             relocation.  And get the base value when relocating.  */
+         begin_rel->r_addend &= (0x1 << 16) - 1;
          begin_rel->r_addend |= dist << 16;
 
          nds32_fag_free_list (&fag_head);
          begin_rel = NULL;
        }
 
-      if (begin_rel == NULL)
+      if (begin_rel == NULL || ifc_inside)
        /* Skip if we are not in the region of fp-as-gp.  */
        continue;
 
@@ -11456,6 +12830,12 @@ nds32_relax_fp_as_gp (struct bfd_link_info *link_info,
        {
          begin_rel = NULL;
        }
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_10IFCU_PCREL_RELA)
+       {
+         /* Suppress fp as gp when encounter ifc.  */
+         ifc_inside = TRUE;
+       }
     }
 
   return TRUE;
@@ -11559,6 +12939,138 @@ error_return:
   result = FALSE;
   goto finish;
 }
+
+/* This is a version of bfd_generic_get_relocated_section_contents.
+   We need this variety because relaxation will modify the dwarf
+   infomation.  When there is undefined symbol reference error mesage,
+   linker need to dump line number where the symbol be used.  However
+   the address is be relaxed, it can not get the original dwarf contents.
+   The variety only modify function call for reading in the section.  */
+
+static bfd_byte *
+nds32_elf_get_relocated_section_contents (bfd *abfd,
+                                         struct bfd_link_info *link_info,
+                                         struct bfd_link_order *link_order,
+                                         bfd_byte *data,
+                                         bfd_boolean relocatable,
+                                         asymbol **symbols)
+{
+  bfd *input_bfd = link_order->u.indirect.section->owner;
+  asection *input_section = link_order->u.indirect.section;
+  long reloc_size;
+  arelent **reloc_vector;
+  long reloc_count;
+
+  reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+  if (reloc_size < 0)
+    return NULL;
+
+  /* Read in the section.  */
+  if (!nds32_get_section_contents (input_bfd, input_section, &data))
+    return NULL;
+
+  if (reloc_size == 0)
+    return data;
+
+  reloc_vector = (arelent **) bfd_malloc (reloc_size);
+  if (reloc_vector == NULL)
+    return NULL;
+
+  reloc_count = bfd_canonicalize_reloc (input_bfd, input_section,
+                                       reloc_vector, symbols);
+  if (reloc_count < 0)
+    goto error_return;
+
+  if (reloc_count > 0)
+    {
+      arelent **parent;
+      for (parent = reloc_vector; *parent != NULL; parent++)
+       {
+         char *error_message = NULL;
+         asymbol *symbol;
+         bfd_reloc_status_type r;
+
+         symbol = *(*parent)->sym_ptr_ptr;
+         if (symbol->section && discarded_section (symbol->section))
+           {
+             bfd_byte *p;
+             static reloc_howto_type none_howto
+               = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL,
+                        "unused", FALSE, 0, 0, FALSE);
+
+             p = data + (*parent)->address * bfd_octets_per_byte (input_bfd);
+             _bfd_clear_contents ((*parent)->howto, input_bfd, input_section,
+                                  p);
+             (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+             (*parent)->addend = 0;
+             (*parent)->howto = &none_howto;
+             r = bfd_reloc_ok;
+           }
+         else
+           r = bfd_perform_relocation (input_bfd, *parent, data,
+                                       input_section,
+                                       relocatable ? abfd : NULL,
+                                       &error_message);
+
+         if (relocatable)
+           {
+             asection *os = input_section->output_section;
+
+             /* A partial link, so keep the relocs.  */
+             os->orelocation[os->reloc_count] = *parent;
+             os->reloc_count++;
+           }
+
+         if (r != bfd_reloc_ok)
+           {
+             switch (r)
+               {
+               case bfd_reloc_undefined:
+                 if (!((*link_info->callbacks->undefined_symbol)
+                       (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                        input_bfd, input_section, (*parent)->address, TRUE)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_dangerous:
+                 BFD_ASSERT (error_message != NULL);
+                 if (!((*link_info->callbacks->reloc_dangerous)
+                       (link_info, error_message, input_bfd, input_section,
+                        (*parent)->address)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_overflow:
+                 if (!((*link_info->callbacks->reloc_overflow)
+                       (link_info, NULL,
+                        bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                        (*parent)->howto->name, (*parent)->addend,
+                        input_bfd, input_section, (*parent)->address)))
+                   goto error_return;
+                 break;
+               case bfd_reloc_outofrange:
+                 /* PR ld/13730:
+                    This error can result when processing some partially
+                    complete binaries.  Do not abort, but issue an error
+                    message instead.  */
+                 link_info->callbacks->einfo
+                   (_("%X%P: %B(%A): relocation \"%R\" goes out of range\n"),
+                    abfd, input_section, * parent);
+                 goto error_return;
+
+               default:
+                 abort ();
+                 break;
+               }
+           }
+       }
+    }
+
+  free (reloc_vector);
+  return data;
+
+error_return:
+  free (reloc_vector);
+  return NULL;
+}
 \f
 /* Link-time IFC relaxation.
    In this optimization, we chains jump instructions
@@ -11682,7 +13194,7 @@ nds32_elf_ifc_calc (struct bfd_link_info *info,
   Elf_Internal_Rela *irel;
   Elf_Internal_Shdr *symtab_hdr;
   bfd_byte *contents = NULL;
-  unsigned long insn, insn_with_reg;
+  uint32_t insn, insn_with_reg;
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
   struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
@@ -11788,9 +13300,9 @@ nds32_elf_ifc_filter (struct bfd_link_info *info)
        }
       else
        {
-         /* Global symbol.  We have to get the absolute address
-            and decide whether to keep it or not.*/
-
+         /* Global symbol.  */
+         /* We have to get the absolute address and decide
+            whether to keep it or not.  */
          while (irel_ptr)
            {
              address = (irel_ptr->irel->r_offset
@@ -11803,11 +13315,13 @@ nds32_elf_ifc_filter (struct bfd_link_info *info)
          irel_ptr = ptr->irel_head;
          while (irel_ptr)
            {
+             /* Sort by address.  */
              struct elf_nds32_ifc_irel_list *irel_dest = irel_ptr;
              struct elf_nds32_ifc_irel_list *irel_temp = irel_ptr;
              struct elf_nds32_ifc_irel_list *irel_ptr_prev = NULL;
              struct elf_nds32_ifc_irel_list *irel_dest_prev = NULL;
 
+             /* Get the smallest one.  */
              while (irel_temp->next)
                {
                  if (irel_temp->next->addr < irel_dest->addr)
@@ -11817,6 +13331,7 @@ nds32_elf_ifc_filter (struct bfd_link_info *info)
                    }
                  irel_temp = irel_temp->next;
                }
+
              if (irel_dest != irel_ptr)
                {
                  if (irel_ptr_prev)
@@ -11846,7 +13361,7 @@ nds32_elf_ifc_filter (struct bfd_link_info *info)
            }
        }
 
-       /* Ex9 enable. Reserve it for ex9.  */
+       /* Ex9 enable.  Reserve it for ex9.  */
       if ((target_optimize & NDS32_RELAX_EX9_ON)
          && ptr->irel_head != irel_keeper)
        ptr->enable = 0;
@@ -11932,7 +13447,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
       /* Traverse the ifc gather list, and replace the
         filter entries by ifcall9.  */
       if ((!(relax_status & NDS32_RELAX_JUMP_IFC_DONE) && ptr->enable == 1)
-         || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE) && ptr->ex9_enable == 1))
+         || ((relax_status & NDS32_RELAX_JUMP_IFC_DONE)
+             && ptr->ex9_enable == 1))
        {
          irel_ptr = ptr->irel_head;
          if (ptr->h == NULL)
@@ -11942,17 +13458,19 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
                (ptr->sec->owner, ptr->sec, NULL, NULL, TRUE /* keep_memory */);
              irelend = internal_relocs + ptr->sec->reloc_count;
 
-             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, &contents))
+             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec,
+                                              &contents))
                return FALSE;
 
              while (irel_ptr)
                {
                  if (irel_ptr->keep == 0 && irel_ptr->next)
                    {
-                     /* The one can be replaced. We have to check whether
+                     /* The one can be replaced.  We have to check whether
                         there is any alignment point in the region.  */
                      irel = irel_ptr->irel;
-                     while (((irel_ptr->next->keep == 0 && irel < irel_ptr->next->irel)
+                     while (((irel_ptr->next->keep == 0
+                              && irel < irel_ptr->next->irel)
                              || (irel_ptr->next->keep == 1 && irel < irelend))
                             && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
                                  && (irel->r_addend & 0x1f) == 2))
@@ -11960,9 +13478,9 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
                      if (irel >= irelend
                          || !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
                               && (irel->r_addend & 0x1f) == 2
-                              && ((irel->r_offset
-                                   - get_nds32_elf_blank_total
-                                       (&relax_blank_list, irel->r_offset, 1)) & 0x02) == 0))
+                              && ((irel->r_offset - get_nds32_elf_blank_total
+                                   (&relax_blank_list, irel->r_offset, 1))
+                                  & 0x02) == 0))
                        {
                          /* Replace by ifcall9.  */
                          bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
@@ -11970,7 +13488,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
                              (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2))
                            return FALSE;
                          irel_ptr->irel->r_info =
-                           ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN);
+                           ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info),
+                                         R_NDS32_10IFCU_PCREL_RELA);
                        }
                    }
                  irel_ptr = irel_ptr->next;
@@ -12029,7 +13548,8 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
                                                         irel_ptr->sec,
                                                         relax_blank_list);
                          irel_ptr->irel->r_info =
-                           ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN);
+                           ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info),
+                                         R_NDS32_10IFCU_PCREL_RELA);
                          relax_blank_list = NULL;
                        }
                    }
@@ -12046,7 +13566,7 @@ nds32_elf_ifc_replace (struct bfd_link_info *info)
 
 /* Relocate ifcall.  */
 
-bfd_boolean
+static bfd_boolean
 nds32_elf_ifc_reloc (void)
 {
   struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
@@ -12054,14 +13574,20 @@ nds32_elf_ifc_reloc (void)
   struct elf_nds32_ifc_irel_list *irel_keeper = NULL;
   bfd_vma relocation, address;
   unsigned short insn16;
-
   bfd_byte *contents = NULL;
+  static bfd_boolean done = FALSE;
+
+  if (done)
+    return TRUE;
+
+  done = TRUE;
 
   while (ptr)
     {
+      /* Check the entry is enable ifcall.  */
       if (ptr->enable == 1 || ptr->ex9_enable == 1)
        {
-         /* Check the entry is enable ifcall.  */
+         /* Get the reserve jump.  */
          irel_ptr = ptr->irel_head;
          while (irel_ptr)
            {
@@ -12083,7 +13609,7 @@ nds32_elf_ifc_reloc (void)
              while (irel_ptr)
                {
                  if (irel_ptr->keep == 0
-                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN)
+                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA)
                    {
                      relocation = irel_keeper->irel->r_offset;
                      relocation = relocation - irel_ptr->irel->r_offset;
@@ -12114,7 +13640,9 @@ nds32_elf_ifc_reloc (void)
                          if (!irel_keeper)
                            return FALSE;
                        }
-
+                     irel_ptr->irel->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info),
+                                     R_NDS32_NONE);
                      insn16 = INSN_IFCALL9 | (relocation >> 1);
                      bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
                    }
@@ -12127,8 +13655,9 @@ nds32_elf_ifc_reloc (void)
              while (irel_ptr)
                {
                  if (irel_ptr->keep == 0
-                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN)
+                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_10IFCU_PCREL_RELA)
                    {
+                     /* Get the distance between ifcall and jump.  */
                      relocation = (irel_keeper->irel->r_offset
                                    + irel_keeper->sec->output_section->vma
                                    + irel_keeper->sec->output_offset);
@@ -12136,6 +13665,8 @@ nds32_elf_ifc_reloc (void)
                                 + irel_ptr->sec->output_section->vma
                                 + irel_ptr->sec->output_offset);
                      relocation = relocation - address;
+
+                     /* The distance is over ragne, find callee again.  */
                      while (irel_keeper && relocation > 1022)
                        {
                          irel_keeper = irel_keeper->next;
@@ -12170,10 +13701,13 @@ nds32_elf_ifc_reloc (void)
                            return FALSE;
                        }
                      if (!nds32_get_section_contents
-                            (irel_ptr->sec->owner, irel_ptr->sec, &contents))
-                         return FALSE;
-                       insn16 = INSN_IFCALL9 | (relocation >> 1);
-                       bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
+                         (irel_ptr->sec->owner, irel_ptr->sec, &contents))
+                       return FALSE;
+                     insn16 = INSN_IFCALL9 | (relocation >> 1);
+                     bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
+                     irel_ptr->irel->r_info =
+                       ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info),
+                                     R_NDS32_NONE);
                    }
                  irel_ptr =irel_ptr->next;
                }
@@ -12569,92 +14103,31 @@ static void
 nds32_elf_order_insn_times (struct bfd_link_info *info)
 {
   struct elf_nds32_insn_times_entry *ex9_insn;
-  struct elf_nds32_insn_times_entry *temp;
+  struct elf_nds32_insn_times_entry *temp = NULL;
   struct elf_nds32_link_hash_table *table;
-  char *insn;
   int ex9_limit;
-  int number = 0, total = 0;
-  struct bfd_link_hash_entry *bh;
+  int number = 0;
+
+  if (ex9_insn_head == NULL)
+    return;
 
 /* The max number of entries is 512.  */
   ex9_insn = ex9_insn_head;
   table = nds32_elf_hash_table (info);
   ex9_limit = table->ex9_limit;
 
-  /* Get the minimun one of ex9 list and limitation.  */
-  while (ex9_insn)
-    {
-      total++;
-      ex9_insn = ex9_insn->next;
-    }
-  total = MIN (total, ex9_limit);
-
-  temp = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-  temp->string = bfd_malloc (sizeof (char) * 10);
-  temp->times = 0;
-  temp->sec = NULL;
-  temp->m_list = NULL;
-  temp->irel = NULL;
-  temp->next = NULL;
-  /* Since the struct elf_nds32_insn_times_entry string is const char,
-     it has to allocate another space to write break 0xea.  */
-  insn = bfd_malloc (sizeof (char) * 10);
-  snprintf (insn, sizeof (char) * 10, "%08x", INSN_BREAK_EA);
-  temp->string = (const char *) insn;
-
   ex9_insn = ex9_insn_head;
 
-  while (ex9_insn != NULL && number <= ex9_limit)
+  while (ex9_insn != NULL && number < ex9_limit)
     {
-      /* Save 234th entry for break 0xea, because trace32 need to use
-        break16 0xea.  If the number of entry is less than 234, adjust
-        the address of _ITB_BASE_ backward.  */
-      if (total < 234)
-       {
-         ex9_insn->order = number + 234 - total;
-         if (!ex9_insn->next)
-           {
-             /* Link break 0xea entry into list.  */
-             ex9_insn->next = temp;
-             temp->next = NULL;
-             temp ->order = number + 235 - total;
-             ex9_insn = NULL;
-             break;
-           }
-       }
-      else
-       ex9_insn->order = number;
-
+      ex9_insn->order = number;
       number++;
-
-      if (number == 234)
-       {
-         /* Link break 0xea entry into list.  */
-         temp->next = ex9_insn->next;
-         ex9_insn->next = temp;
-         temp->order = number;
-         number++;
-         ex9_insn = ex9_insn->next;
-       }
-
-      if (number > ex9_limit)
-       {
-         temp = ex9_insn;
-         ex9_insn = ex9_insn->next;
-         temp->next = NULL;
-         break;
-       }
+      temp = ex9_insn;
       ex9_insn = ex9_insn->next;
     }
 
-  if (total < 234)
-    {
-      /* Adjust the address of _ITB_BASE_.  */
-      bh = bfd_link_hash_lookup (info->hash, "_ITB_BASE_",
-                                FALSE, FALSE, FALSE);
-      if (bh)
-       bh->u.def.value = (total - 234) * 4;
-    }
+  if (ex9_insn && temp)
+    temp->next = NULL;
 
   while (ex9_insn != NULL)
     {
@@ -12692,13 +14165,7 @@ nds32_elf_ex9_build_itable (struct bfd_link_info *link_info)
          table_sec->size = number * 4;
 
          if (number == 0)
-           {
-             /* There is no insntruction effective enough to convert to ex9.
-                Only add break 0xea into ex9 table.  */
-             table_sec->size = 4;
-             bfd_putb32 ((bfd_vma) INSN_BREAK_EA, (char *) contents);
-             return;
-           }
+           return;
 
          elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST;
          number = 0;
@@ -12719,7 +14186,7 @@ nds32_elf_ex9_build_itable (struct bfd_link_info *link_info)
 
 static void
 nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel,
-                            unsigned long insn, unsigned long *insn_with_reg)
+                            uint32_t insn, uint32_t *insn_with_reg)
 {
   reloc_howto_type *howto = NULL;
 
@@ -12864,8 +14331,7 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info,
                               && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG))
                        nested_loop = FALSE;
                    }
-                 else if (relax_blank_list
-                          && ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL
+                 else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_LABEL
                           && ((*irel)->r_addend & 0x1f) == 2)
                    {
                      /* Alignment exist in the region.  */
@@ -12888,7 +14354,7 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info,
          break;
 
        case R_NDS32_LABEL:
-         if (relax_blank_list && ((*irel)->r_addend & 0x1f) == 2)
+         if (((*irel)->r_addend & 0x1f) == 2)
            {
              /* Check this point is align and decide to do ex9 or not.  */
              result |= CLEAN_PRE;
@@ -12948,7 +14414,8 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info,
        default:
          /* Not support relocations.  */
          if (ELF32_R_TYPE ((*irel)->r_info) < ARRAY_SIZE (nds32_elf_howto_table)
-             && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_NONE)
+             && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_NONE
+             && ELF32_R_TYPE ((*irel)->r_info) != R_NDS32_INSN16)
            {
              /* Note: To optimize aggressively, it maybe can ignore R_NDS32_INSN16 here.
                 But we have to consider if there is any side-effect.  */
@@ -12983,6 +14450,27 @@ nds32_elf_ex9_relocation_check (struct bfd_link_info *info,
   return result;
 }
 
+/* Replace with ex9 instruction.  */
+
+static bfd_boolean
+nds32_elf_ex9_push_insn (uint16_t insn16, bfd_byte *contents, bfd_vma pre_off,
+                        nds32_elf_blank_t **relax_blank_list,
+                        struct elf_nds32_irel_entry *pre_irel_ptr,
+                        struct elf_nds32_irel_entry **irel_list)
+{
+  if (insn16 != 0)
+    {
+      /* Implement the ex9 relaxation.  */
+      bfd_putb16 (insn16, contents + pre_off);
+      if (!insert_nds32_elf_blank_recalc_total (relax_blank_list,
+                                               pre_off + 2, 2))
+       return FALSE;
+      if (pre_irel_ptr != NULL)
+       nds32_elf_insert_irel_entry (irel_list, pre_irel_ptr);
+    }
+  return TRUE;
+}
+
 /* Replace input file instruction which is in ex9 itable.  */
 
 static bfd_boolean
@@ -12990,11 +14478,11 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
 {
   struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head;
   bfd_byte *contents = NULL;
-  long unsigned int off;
-  unsigned short insn16, insn_ex9;
+  bfd_vma off;
+  uint16_t insn16, insn_ex9;
   /* `pre_*' are used to track previous instruction that can use ex9.it.  */
-  unsigned int pre_off = -1;
-  unsigned short pre_insn16 = 0;
+  bfd_vma pre_off = -1;
+  uint16_t pre_insn16 = 0;
   struct elf_nds32_irel_entry *pre_irel_ptr = NULL;
   Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *irel;
@@ -13002,30 +14490,32 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Sym *isym = NULL;
   nds32_elf_blank_t *relax_blank_list = NULL;
-  unsigned long insn = 0;
-  unsigned long insn_with_reg = 0;
-  unsigned long it_insn;
-  unsigned long it_insn_with_reg;
+  uint32_t insn = 0;
+  uint32_t insn_with_reg = 0;
+  uint32_t it_insn;
+  uint32_t it_insn_with_reg;
   unsigned long r_symndx;
   asection *isec;
   struct elf_nds32_irel_entry *irel_list = NULL;
   struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (abfd);
   int data_flag, do_replace, save_irel;
+  struct elf_link_hash_entry_list *h_list;
+
 
   /* Load section instructions, relocations, and symbol table.  */
   if (!nds32_get_section_contents (abfd, sec, &contents)
       || !nds32_get_local_syms (abfd, sec, &isym))
     return FALSE;
-  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
-                                              TRUE /* keep_memory */);
+  internal_relocs =
+    _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, TRUE /* keep_memory */);
   irelend = internal_relocs + sec->reloc_count;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
   off = 0;
 
   /* Check if the object enable ex9.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  irel = find_relocs_at_address (internal_relocs, internal_relocs,
+                                irelend, R_NDS32_RELAX_ENTRY);
 
   /* Check this section trigger ex9 relaxation.  */
   if (irel == NULL
@@ -13051,19 +14541,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
                                                  relax_blank_list, sec,
                                                  &off, contents);
       if (data_flag & PUSH_PRE)
-       {
-         if (pre_insn16 != 0)
-           {
-             /* Implement the ex9 relaxation.  */
-             bfd_putb16 (pre_insn16, contents + pre_off);
-             if (!insert_nds32_elf_blank_recalc_total
-                 (&relax_blank_list, pre_off + 2, 2))
-               return FALSE;
-             if (pre_irel_ptr != NULL)
-               nds32_elf_insert_irel_entry (&irel_list,
-                                            pre_irel_ptr);
-           }
-       }
+       if (!nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off,
+                                     &relax_blank_list, pre_irel_ptr,
+                                     &irel_list))
+         return FALSE;
 
       if (data_flag & CLEAN_PRE)
        {
@@ -13102,10 +14583,12 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
              nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg);
 
              if (ex9_insn->irel != NULL)
-                 nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, &it_insn_with_reg);
+               nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn,
+                                            &it_insn_with_reg);
 
              if (ex9_insn->irel != NULL
-                 && ELF32_R_TYPE (irel->r_info) == ELF32_R_TYPE (ex9_insn->irel->r_info)
+                 && (ELF32_R_TYPE (irel->r_info) ==
+                     ELF32_R_TYPE (ex9_insn->irel->r_info))
                  && (insn_with_reg == it_insn_with_reg))
                {
                  /* Insn relocation and format is the same as table entry.  */
@@ -13146,13 +14629,12 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
                          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
                          if (ex9_insn->m_list)
                            {
-                             struct elf_link_hash_entry_list *h_list;
-
                              h_list = ex9_insn->m_list->h_list;
                              while (h_list)
                                {
                                  if (h == h_list->h
-                                     && ex9_insn->m_list->irel->r_addend == irel->r_addend)
+                                     && (ex9_insn->m_list->irel->r_addend ==
+                                         irel->r_addend))
                                    {
                                      do_replace = 1;
                                      save_irel = 1;
@@ -13190,12 +14672,13 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
 
                          while (m_list)
                            {
-                             struct elf_link_hash_entry_list *h_list = m_list->h_list;
+                             h_list = m_list->h_list;
 
                              while (h_list)
                                {
                                  if (h == h_list->h
-                                     && m_list->irel->r_addend == irel->r_addend)
+                                     && (m_list->irel->r_addend
+                                         == irel->r_addend))
                                    {
                                      do_replace = 1;
                                      save_irel = 1;
@@ -13234,19 +14717,19 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
                          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
                          if ((h->root.type == bfd_link_hash_defined
                               || h->root.type == bfd_link_hash_defweak)
-                             && (h->root.u.def.section != NULL
-                                 && h->root.u.def.section->output_section != NULL)
+                             && h->root.u.def.section != NULL
+                             && h->root.u.def.section->output_section != NULL
                              && h->root.u.def.section->gc_mark == 1
-                             && strcmp (h->root.u.def.section->name,
-                                        BFD_ABS_SECTION_NAME) == 0
+                             && bfd_is_abs_section (h->root.u.def.section)
                              && h->root.u.def.value > sec->size)
                            {
-                             relocation = (h->root.u.def.value +
-                                           h->root.u.def.section->output_section->vma +
-                                           h->root.u.def.section->output_offset);
+                             relocation = h->root.u.def.value +
+                               h->root.u.def.section->output_section->vma +
+                               h->root.u.def.section->output_offset;
                              relocation += irel->r_addend;
-                             insn = insn_with_reg | ((relocation >> 1) & 0xffffff);
-                             snprintf (code, sizeof (code), "%08lx", insn);
+                             insn = insn_with_reg
+                               | ((relocation >> 1) & 0xffffff);
+                             snprintf (code, sizeof (code), "%08x", insn);
                              if (strcmp (code, ex9_insn->string) == 0)
                                {
                                  do_replace = 1;
@@ -13257,7 +14740,8 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
                    }
                }
              else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
-                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END)
+                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END
+                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE)
                {
                  /* These relocations do not have to relocate contens, so it can
                     be regard as instruction without relocation.  */
@@ -13283,15 +14767,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
                insn_ex9 = INSN_EX9_IT_1;
              insn16 = insn_ex9 | ex9_insn->order;
 
-             if (pre_insn16 != 0)
-               {
-                 bfd_putb16 (pre_insn16, contents + pre_off);
-                 if (!insert_nds32_elf_blank_recalc_total
-                     (&relax_blank_list, pre_off + 2, 2))
-                   return FALSE;
-                 if (pre_irel_ptr != NULL)
-                   nds32_elf_insert_irel_entry (&irel_list, pre_irel_ptr);
-               }
+             /* Insert ex9 instruction.  */
+             nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off,
+                                      &relax_blank_list, pre_irel_ptr,
+                                      &irel_list);
              pre_off = off;
              pre_insn16 = insn16;
 
@@ -13313,16 +14792,10 @@ nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asecti
       off += 4;
     }
 
-  if (pre_insn16 != 0)
-    {
-      /* Implement the ex9 relaxation.  */
-      bfd_putb16 (pre_insn16, contents + pre_off);
-      if (!insert_nds32_elf_blank_recalc_total
-         (&relax_blank_list, pre_off + 2, 2))
-       return FALSE;
-      if (pre_irel_ptr != NULL)
-       nds32_elf_insert_irel_entry (&irel_list, pre_irel_ptr);
-    }
+  /* Insert ex9 instruction.  */
+  nds32_elf_ex9_push_insn (pre_insn16, contents, pre_off,
+                          &relax_blank_list, pre_irel_ptr,
+                          &irel_list);
 
   /* Delete the redundant code.  */
   if (relax_blank_list)
@@ -13416,8 +14889,6 @@ nds32_elf_ex9_total_relax (struct bfd_link_info *info)
 void
 nds32_elf_ex9_finish (struct bfd_link_info *link_info)
 {
-  struct elf_nds32_link_hash_table *table;
-
   nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times);
   nds32_elf_order_insn_times (link_info);
   nds32_elf_ex9_total_relax (link_info);
@@ -13425,9 +14896,6 @@ nds32_elf_ex9_finish (struct bfd_link_info *link_info)
   nds32_elf_code_hash_traverse (nds32_elf_count_insn_times);
   nds32_elf_order_insn_times (link_info);
   nds32_elf_ex9_build_itable (link_info);
-  table = nds32_elf_hash_table (link_info);
-  if (table)
-    table->relax_round = NDS32_RELAX_EX9_REPLACE_ROUND;
 }
 
 /* Relocate the entries in ex9 table.  */
@@ -13438,19 +14906,21 @@ nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr,
 {
   Elf_Internal_Sym *isym = NULL;
   bfd_vma relocation = -1;
+  struct elf_link_hash_entry *h;
 
   if (ptr->m_list != NULL)
     {
       /* Global symbol.  */
-      if ((ptr->m_list->h_list->h->root.type == bfd_link_hash_defined
-          || ptr->m_list->h_list->h->root.type == bfd_link_hash_defweak)
-         && (ptr->m_list->h_list->h->root.u.def.section != NULL
-             && ptr->m_list->h_list->h->root.u.def.section->output_section != NULL))
+      h = ptr->m_list->h_list->h;
+      if ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section != NULL
+         && h->root.u.def.section->output_section != NULL)
        {
 
-         relocation = (ptr->m_list->h_list->h->root.u.def.value +
-                       ptr->m_list->h_list->h->root.u.def.section->output_section->vma +
-                       ptr->m_list->h_list->h->root.u.def.section->output_offset);
+         relocation = h->root.u.def.value +
+           h->root.u.def.section->output_section->vma +
+           h->root.u.def.section->output_offset;
          relocation += ptr->m_list->irel->r_addend;
        }
       else
@@ -13505,7 +14975,7 @@ nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr,
 void
 nds32_elf_ex9_import_table (struct bfd_link_info *info)
 {
-  int count = 0, num = 1;
+  int num = 0;
   bfd_byte *contents;
   unsigned long insn;
   FILE *ex9_import_file;
@@ -13514,30 +14984,21 @@ nds32_elf_ex9_import_table (struct bfd_link_info *info)
 
   table = nds32_elf_hash_table (info);
   ex9_import_file = table->ex9_import_file;
+  rewind (table->ex9_import_file);
 
   contents = bfd_malloc (sizeof (bfd_byte) * 4);
 
-  /* Count the number of input file instructions.  */
-  while (!feof (ex9_import_file))
-    {
-      fgetc (ex9_import_file);
-      count++;
-    }
-  count = count / 4;
-  rewind (ex9_import_file);
   /* Read instructions from the input file and build the list.  */
-  while (count != 0)
+  while (!feof (ex9_import_file))
     {
       char *code;
       struct elf_nds32_insn_times_entry *ptr;
       size_t nread;
 
       nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file);
-      if (nread < sizeof (bfd_byte) * 4)
-       {
-         (*_bfd_error_handler) ("Unexpected size of imported ex9 table.");
-         break;
-       }
+      /* Ignore the final byte 0x0a.  */
+      if (nread < 1)
+       break;
       insn = bfd_getb32 (contents);
       code = bfd_malloc (sizeof (char) * 9);
       snprintf (code, 9, "%08lx", insn);
@@ -13553,7 +15014,6 @@ nds32_elf_ex9_import_table (struct bfd_link_info *info)
       ptr->irel = NULL;
       ptr->next = NULL;
       nds32_elf_ex9_insert_entry (ptr);
-      count--;
       num++;
     }
 
@@ -13585,14 +15045,14 @@ nds32_elf_ex9_export (struct bfd_link_info *info,
 /* Adjust relocations of J and JAL in ex9.itable.
    Export ex9 table.  */
 
-void
+static void
 nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
 {
   asection *table_sec = NULL;
   struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head;
   struct elf_nds32_insn_times_entry *temp_ptr, *temp_ptr2;
   bfd *it_abfd;
-  unsigned long insn, insn_with_reg, source_insn;
+  uint32_t insn, insn_with_reg, source_insn;
   bfd_byte *contents = NULL, *source_contents = NULL;
   int size = 0;
   bfd_vma gp;
@@ -13601,7 +15061,13 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
   Elf_Internal_Rela rel_backup;
   unsigned short insn_ex9;
   struct elf_nds32_link_hash_table *table;
-  FILE *ex9_export_file, *ex9_import_file;
+  FILE *ex9_export_file;
+  static bfd_boolean done = FALSE;
+
+  if (done)
+    return;
+
+  done = TRUE;
 
   table = nds32_elf_hash_table (link_info);
   if (table)
@@ -13623,7 +15089,6 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
       if (table_sec != NULL)
        {
          bfd *output_bfd;
-         struct bfd_link_hash_entry *bh = NULL;
 
          output_bfd = table_sec->output_section->owner;
          nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
@@ -13632,10 +15097,6 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
 
          if (!nds32_get_section_contents (it_abfd, table_sec, &contents))
            return;
-         /* Get the offset between _ITB_BASE_ and .ex9.itable.  */
-         bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_",
-                                    FALSE, FALSE, FALSE);
-         offset = bh->u.def.value;
        }
     }
   else
@@ -13677,7 +15138,7 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
              insn =
                insn_with_reg | ((relocation >> shift) &
                                 nds32_elf_irel_mask (&rel_backup));
-             bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+             bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
            }
          else if ((ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3
                    && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0)
@@ -13692,27 +15153,27 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
              insn =
                insn_with_reg | (((relocation - gp) >> shift) &
                                 nds32_elf_irel_mask (&rel_backup));
-             bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+             bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
            }
          else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA)
            {
              /* Sethi may be multiple entry for one insn.  */
-             if (ex9_insn->next && ((ex9_insn->m_list && ex9_insn->m_list == ex9_insn->next->m_list)
-                               || (ex9_insn->m_list && ex9_insn->next->order == 234
-                                   && ex9_insn->next->next
-                                   && ex9_insn->m_list == ex9_insn->next->next->m_list)))
+             if (ex9_insn->next && ex9_insn->m_list
+                 && ex9_insn->m_list == ex9_insn->next->m_list)
                {
                  struct elf_link_hash_entry_mul_list *m_list;
                  struct elf_nds32_ex9_refix *fix_ptr;
+                 struct elf_link_hash_entry *h;
 
                  temp_ptr = ex9_insn;
                  temp_ptr2 = ex9_insn;
                  m_list = ex9_insn->m_list;
                  while (m_list)
                    {
-                     relocation = (m_list->h_list->h->root.u.def.value +
-                                   m_list->h_list->h->root.u.def.section->output_section->vma +
-                                   m_list->h_list->h->root.u.def.section->output_offset);
+                     h = m_list->h_list->h;
+                     relocation = h->root.u.def.value +
+                       h->root.u.def.section->output_section->vma +
+                       h->root.u.def.section->output_offset;
                      relocation += m_list->irel->r_addend;
 
                      if (relocation < min_relocation)
@@ -13724,26 +15185,19 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
                  /* Put insntruction into ex9 table.  */
                  insn = insn_with_reg
                    | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup));
-                 bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+                 bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
                  relocation = relocation + 0x1000;     /* hi20 */
 
-                 while (ex9_insn->next && ((ex9_insn->m_list && ex9_insn->m_list == ex9_insn->next->m_list)
-                                      || (ex9_insn->m_list && ex9_insn->next->order == 234
-                                          && ex9_insn->next->next
-                                          && ex9_insn->m_list == ex9_insn->next->next->m_list)))
+                 while (ex9_insn->next && ex9_insn->m_list
+                        && ex9_insn->m_list == ex9_insn->next->m_list)
                    {
                      /* Multiple sethi.  */
                      ex9_insn = ex9_insn->next;
                      size += 4;
-                     if (ex9_insn->order == 234)
-                       {
-                         ex9_insn = ex9_insn->next;
-                         size += 4;
-                       }
                      insn =
                        insn_with_reg | ((relocation >> shift) &
                                         nds32_elf_irel_mask (&rel_backup));
-                     bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+                     bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
                      relocation = relocation + 0x1000; /* hi20 */
                    }
 
@@ -13761,21 +15215,16 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
                        break;
 
                      /* Set source insn.  */
-                     relocation = (fix_ptr->h->root.u.def.value +
-                                   fix_ptr->h->root.u.def.section->output_section->vma +
-                                   fix_ptr->h->root.u.def.section->output_offset);
+                     relocation =
+                       fix_ptr->h->root.u.def.value +
+                       fix_ptr->h->root.u.def.section->output_section->vma +
+                       fix_ptr->h->root.u.def.section->output_offset;
                      relocation += fix_ptr->irel->r_addend;
                      /* sethi imm is imm20s.  */
                      source_insn = insn_with_reg | ((relocation >> shift) & 0xfffff);
 
                      while (temp_ptr)
                        {
-                         if (temp_ptr->order == 234)
-                           {
-                             temp_ptr = temp_ptr->next;
-                             continue;
-                           }
-
                          /* Match entry and source code.  */
                          insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset);
                          if (insn == source_insn)
@@ -13814,7 +15263,7 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
                  relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info);
                  insn = insn_with_reg
                         | ((relocation >> shift) & nds32_elf_irel_mask (&rel_backup));
-                 bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+                 bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
                }
            }
        }
@@ -13831,13 +15280,12 @@ nds32_elf_ex9_reloc_jmp (struct bfd_link_info *link_info)
 
   ex9_export_file = table->ex9_export_file;
   if (ex9_export_file != NULL)
-    nds32_elf_ex9_export (link_info, contents + 4, table_sec->size - 4);
+    nds32_elf_ex9_export (link_info, contents, table_sec->size);
   else if (update_ex9_table == 1)
     {
-      ex9_import_file = table->ex9_import_file;
-      ex9_export_file = ex9_import_file;
-      rewind (ex9_export_file);
-      nds32_elf_ex9_export (link_info, contents + 4, size);
+      table->ex9_export_file = table->ex9_import_file;
+      rewind (table->ex9_export_file);
+      nds32_elf_ex9_export (link_info, contents, size);
     }
 }
 
@@ -13859,8 +15307,7 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
   bfd_byte *contents = NULL;
   long unsigned int off = 0;
   unsigned long r_symndx;
-  unsigned long insn;
-  unsigned long insn_with_reg;
+  uint32_t insn, insn_with_reg;
   struct elf_link_hash_entry *h;
   int data_flag, shift, align;
   bfd_vma relocation;
@@ -13902,8 +15349,8 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
       while (irel != NULL && irel < irelend && irel->r_offset < off)
        irel++;
 
-      data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend, NULL,
-                                                 sec, &off, contents);
+      data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend,
+                                                 NULL, sec, &off, contents);
       if (data_flag & DATA_EXIST)
        {
          /* We save the move offset in the highest byte.  */
@@ -13974,8 +15421,9 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
                                               h, sym_sec, relocation,
                                               unresolved_reloc, warned, ignored);
                      relocation += irel->r_addend;
-                     if (h->type != bfd_link_hash_defined
-                         && h->type != bfd_link_hash_defweak)
+                     if ((h->root.type != bfd_link_hash_defined
+                          && h->root.type != bfd_link_hash_defweak)
+                         || strcmp (h->root.root.string, "_FP_BASE_") == 0)
                        {
                          off += 4;
                          continue;
@@ -14025,7 +15473,8 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
                    | ((relocation >> shift) & nds32_elf_irel_mask (irel));
                }
              else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
-                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END)
+                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END
+                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE)
                {
                  /* These relocations do not have to relocate contens, so it can
                     be regard as instruction without relocation.  */
@@ -14037,7 +15486,7 @@ nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
                }
            }
 
-         snprintf (code, sizeof (code), "%08lx", insn);
+         snprintf (code, sizeof (code), "%08x", insn);
          /* Copy "code".  */
          entry = (struct elf_nds32_code_hash_entry*)
            bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE);
@@ -14162,16 +15611,17 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
   asection *sec;
   bfd *output_bfd = NULL;
   struct bfd_link_hash_entry *bh = NULL;
-  int target_optimize;
-  struct elf_nds32_link_hash_table *table;
 
   if (is_ITB_BASE_set == 1)
     return TRUE;
 
   is_ITB_BASE_set = 1;
 
-  table = nds32_elf_hash_table (link_info);
-  target_optimize  = table->target_optimize;
+  bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_", FALSE, FALSE, TRUE);
+
+  if (bh && (bh->type == bfd_link_hash_defined
+            || bh->type == bfd_link_hash_defweak))
+    return TRUE;
 
   for (abfd = link_info->input_bfds; abfd != NULL;
        abfd = abfd->link.next)
@@ -14195,9 +15645,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
                             FALSE, FALSE, TRUE);
   return (_bfd_generic_link_add_one_symbol
          (link_info, output_bfd, "_ITB_BASE_",
-          BSF_GLOBAL | BSF_WEAK, sec,
-          /* We don't know its value yet, set it to 0.  */
-          (target_optimize & NDS32_RELAX_EX9_ON) ? 0 : (-234 * 4),
+          BSF_GLOBAL | BSF_WEAK, sec, 0,
           (const char *) NULL, FALSE, get_elf_backend_data
           (output_bfd)->collect, &bh));
 } /* End EX9.IT  */
@@ -14206,6 +15654,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define ELF_ARCH                               bfd_arch_nds32
 #define ELF_MACHINE_CODE                       EM_NDS32
 #define ELF_MAXPAGESIZE                                0x1000
+#define ELF_TARGET_ID                           NDS32_ELF_DATA
 
 #define TARGET_BIG_SYM                         nds32_elf32_be_vec
 #define TARGET_BIG_NAME                                "elf32-nds32be"
@@ -14221,6 +15670,7 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define bfd_elf32_bfd_relax_section            nds32_elf_relax_section
 #define bfd_elf32_bfd_set_private_flags                nds32_elf_set_private_flags
 
+#define bfd_elf32_mkobject                     nds32_elf_mkobject
 #define elf_backend_action_discarded           nds32_elf_action_discarded
 #define elf_backend_add_symbol_hook            nds32_elf_add_symbol_hook
 #define elf_backend_check_relocs               nds32_elf_check_relocs
@@ -14241,6 +15691,8 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define elf_backend_object_p                   nds32_elf_object_p
 #define elf_backend_final_write_processing     nds32_elf_final_write_processing
 #define elf_backend_special_sections           nds32_elf_special_sections
+#define bfd_elf32_bfd_get_relocated_section_contents \
+                                nds32_elf_get_relocated_section_contents
 
 #define elf_backend_can_gc_sections            1
 #define elf_backend_can_refcount               1
index 9aec0fc..d4d4e93 100644 (file)
@@ -46,6 +46,7 @@
 
 /* Relocation flags for R_NDS32_INSN16.  */
 
+/* Tag the nop16 can be removed.  */
 #define R_NDS32_INSN16_CONVERT_FLAG                            (1 << 0)
 /* Convert a gp-relative access (e.g., lwi.gp)
    to fp-as-gp access (lwi37.fp).
    in this region due to performance drop.  */
 #define R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG               (1 << 4)
 
+/* Tag range for LOADSTORE relocation.  */
+enum
+{
+  NDS32_LOADSTORE_NONE = 0x0,
+  NDS32_LOADSTORE_BYTE = 0x1,
+  NDS32_LOADSTORE_HALF = 0x2,
+  NDS32_LOADSTORE_WORD = 0x4,
+  NDS32_LOADSTORE_FLOAT_S = 0x8,
+  NDS32_LOADSTORE_FLOAT_D = 0x10,
+  NDS32_LOADSTORE_IMM = 0x20
+};
+
 /* Relax tag for nds32_elf_relax_section, we have to specify which
    optimization do in this round.  */
 enum
 {
   NDS32_RELAX_NONE_ROUND = 0,
-  NDS32_RELAX_JUMP_IFC_ROUND = 1,
+  NDS32_RELAX_NORMAL_ROUND,
+  NDS32_RELAX_JUMP_IFC_ROUND,
   NDS32_RELAX_EX9_BUILD_ROUND,
-  NDS32_RELAX_EX9_REPLACE_ROUND
-
+  NDS32_RELAX_EX9_REPLACE_ROUND,
+  NDS32_RELAX_EMPTY_ROUND
 };
 
 /* Optimization status mask.  */
@@ -85,29 +99,23 @@ enum
 /* Optimization turn on mask.  */
 #define NDS32_RELAX_JUMP_IFC_ON                (1 << 0)
 #define NDS32_RELAX_EX9_ON             (1 << 1)
-
-/* The break 0xea defined for ex9 table to keep for trace32 to use 0xeaea.  */
-#define INSN_BREAK_EA   0x64001d4a
 \f
 extern void nds32_insertion_sort
   (void *, size_t, size_t, int (*) (const void *, const void *));
 
 extern int         nds32_elf_ex9_init (void);
-extern void        nds32_elf_ex9_reloc_jmp (struct bfd_link_info *);
-extern void        nds32_elf_ex9_finish (struct bfd_link_info *);
-extern bfd_boolean nds32_elf_ex9_itb_base (struct bfd_link_info *);
-extern void        nds32_elf_ex9_import_table (struct bfd_link_info *);
-extern bfd_boolean nds32_elf_ifc_reloc (void);
-extern bfd_boolean nds32_elf_ifc_finish (struct bfd_link_info *);
 extern int         nds32_convert_32_to_16 (bfd *, uint32_t, uint16_t *, int *);
 extern int         nds32_convert_16_to_32 (bfd *, uint16_t, uint32_t *);
-extern void        bfd_elf32_nds32_set_target_option (struct bfd_link_info *, int, int,
-                                                     FILE *, int, int, int, int, FILE *, FILE *,
-                                                     int, int, bfd_boolean, bfd_boolean);
+extern void        bfd_elf32_nds32_set_target_option (struct bfd_link_info *,
+                                                     int, int, FILE *, int,
+                                                     int, int, int, FILE *,
+                                                     FILE *, int, int,
+                                                     bfd_boolean, bfd_boolean);
 
 #define nds32_elf_hash_table(info) \
   (elf_hash_table_id ((struct elf_link_hash_table *) ((info)->hash)) \
-   == NDS32_ELF_DATA ? ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL)
+   == NDS32_ELF_DATA ? \
+   ((struct elf_nds32_link_hash_table *) ((info)->hash)) : NULL)
 
 /* Hash table structure for target nds32.  There are some members to
    save target options passed from nds32elf.em to bfd.  */
index c0f4e96..d43fec4 100644 (file)
@@ -1797,6 +1797,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_NDS32_15_FIXED",
   "BFD_RELOC_NDS32_17_FIXED",
   "BFD_RELOC_NDS32_25_FIXED",
+  "BFD_RELOC_NDS32_LONGCALL4",
+  "BFD_RELOC_NDS32_LONGCALL5",
+  "BFD_RELOC_NDS32_LONGCALL6",
+  "BFD_RELOC_NDS32_LONGJUMP4",
+  "BFD_RELOC_NDS32_LONGJUMP5",
+  "BFD_RELOC_NDS32_LONGJUMP6",
+  "BFD_RELOC_NDS32_LONGJUMP7",
   "BFD_RELOC_NDS32_PLTREL_HI20",
   "BFD_RELOC_NDS32_PLTREL_LO12",
   "BFD_RELOC_NDS32_PLT_GOTREL_HI20",
@@ -1838,11 +1845,25 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_NDS32_DIFF16",
   "BFD_RELOC_NDS32_DIFF32",
   "BFD_RELOC_NDS32_DIFF_ULEB128",
+  "BFD_RELOC_NDS32_EMPTY",
   "BFD_RELOC_NDS32_25_ABS",
   "BFD_RELOC_NDS32_DATA",
   "BFD_RELOC_NDS32_TRAN",
   "BFD_RELOC_NDS32_17IFC_PCREL",
   "BFD_RELOC_NDS32_10IFCU_PCREL",
+  "BFD_RELOC_NDS32_TPOFF",
+  "BFD_RELOC_NDS32_TLS_LE_HI20",
+  "BFD_RELOC_NDS32_TLS_LE_LO12",
+  "BFD_RELOC_NDS32_TLS_LE_ADD",
+  "BFD_RELOC_NDS32_TLS_LE_LS",
+  "BFD_RELOC_NDS32_GOTTPOFF",
+  "BFD_RELOC_NDS32_TLS_IE_HI20",
+  "BFD_RELOC_NDS32_TLS_IE_LO12S2",
+  "BFD_RELOC_NDS32_TLS_TPOFF",
+  "BFD_RELOC_NDS32_TLS_LE_20",
+  "BFD_RELOC_NDS32_TLS_LE_15S0",
+  "BFD_RELOC_NDS32_TLS_LE_15S1",
+  "BFD_RELOC_NDS32_TLS_LE_15S2",
   "BFD_RELOC_V850_9_PCREL",
   "BFD_RELOC_V850_22_PCREL",
   "BFD_RELOC_V850_SDA_16_16_OFFSET",
index 79079cf..dc47173 100644 (file)
@@ -4000,6 +4000,20 @@ ENUMX
   BFD_RELOC_NDS32_17_FIXED
 ENUMX
   BFD_RELOC_NDS32_25_FIXED
+ENUMX
+  BFD_RELOC_NDS32_LONGCALL4
+ENUMX
+  BFD_RELOC_NDS32_LONGCALL5
+ENUMX
+  BFD_RELOC_NDS32_LONGCALL6
+ENUMX
+  BFD_RELOC_NDS32_LONGJUMP4
+ENUMX
+  BFD_RELOC_NDS32_LONGJUMP5
+ENUMX
+  BFD_RELOC_NDS32_LONGJUMP6
+ENUMX
+  BFD_RELOC_NDS32_LONGJUMP7
 ENUMDOC
   for relax
 ENUM
@@ -4102,8 +4116,14 @@ ENUMX
 ENUMX
   BFD_RELOC_NDS32_DIFF_ULEB128
 ENUMX
+  BFD_RELOC_NDS32_EMPTY
+ENUMDOC
+  relaxation relative relocation types
+ENUM
   BFD_RELOC_NDS32_25_ABS
-ENUMX
+ENUMDOC
+  This is a 25 bit absolute address.
+ENUM
   BFD_RELOC_NDS32_DATA
 ENUMX
   BFD_RELOC_NDS32_TRAN
@@ -4112,7 +4132,35 @@ ENUMX
 ENUMX
   BFD_RELOC_NDS32_10IFCU_PCREL
 ENUMDOC
-  relaxation relative relocation types
+  For ex9 and ifc using.
+ENUM
+  BFD_RELOC_NDS32_TPOFF
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_HI20
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_LO12
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_ADD
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_LS
+ENUMX
+  BFD_RELOC_NDS32_GOTTPOFF
+ENUMX
+  BFD_RELOC_NDS32_TLS_IE_HI20
+ENUMX
+  BFD_RELOC_NDS32_TLS_IE_LO12S2
+ENUMX
+  BFD_RELOC_NDS32_TLS_TPOFF
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_20
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_15S0
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_15S1
+ENUMX
+  BFD_RELOC_NDS32_TLS_LE_15S2
+ENUMDOC
+  For TLS.
 
 
 ENUM
index 0cbfb40..14a4e52 100644 (file)
@@ -1,3 +1,20 @@
+2014-09-16  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * config/tc-nds32.c (nds32_fsrs, nds32_fdrs, nds32_gprs): Remove.
+       (relax_table): Add new relaxation pattern.
+       (do_pseudo_la_internal, do_pseudo_ls_bhw): Expand for PIC suffix.
+       (do_pseudo_move, do_pseudo_neg, do_pseudo_pushpopm): Fix.
+       (get_range_type, nds32_elf_record_fixup_exp, nds32_get_align,
+       nds32_elf_build_relax_relation, md_assemble, invalid_prev_frag,
+       nds32_relax_frag, md_estimate_size_before_relax): Adjust relaxation.
+       (relocation_table): Remove.
+       (relax_ls_table): Load-store relaxation pattern.
+       (hint_map): Define-use chain pattern.
+       (nds32_find_reloc_table, nds32_match_hint_insn): Analysis
+       relaxation pattern.
+       (nds32_parse_name): Parse PIC suffix.
+       * config/tc-nds32.h: Declare.
+
 2014-09-15  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/tc-i386.c (OPTION_omit_lock_prefix): Renamed to ...
index 94479ba..353a165 100644 (file)
@@ -55,23 +55,26 @@ 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;
 };
-/*
-static int relax_jal_bound = 3;
-static int multi_call_relax;
-static int pltgot_call_relax;
-*/
+
+/* Suffix name and relocation.  */
+struct suffix_name
+{
+  char *suffix;
+  short unsigned int reloc;
+  int pic;
+};
 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,6 +82,8 @@ 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;
@@ -90,70 +95,13 @@ static int enable_relax_ifc = 0;
 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}
-};
-
-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}
-};
-
+/* 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;
 \f
 static struct hash_control *nds32_relax_info_hash;
 static relax_info_t relax_table[] =
@@ -161,7 +109,7 @@ static relax_info_t relax_table[] =
   {
     "jal",                                     /* opcode */
     BR_RANGE_S16M,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
     {
       {
         INSN_JAL /* jal label */
@@ -180,14 +128,14 @@ static relax_info_t relax_table[] =
         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 */
+    },                                         /* relax_code_seq */
+    {
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */
+      {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 4, 12},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -209,11 +157,13 @@ static relax_info_t relax_table[] =
       }, /* 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}
+       {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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -221,9 +171,9 @@ static relax_info_t relax_table[] =
     "bltzal",                                  /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BLTZAL /* bltzal $rt, label */
@@ -235,38 +185,38 @@ static relax_info_t relax_table[] =
         INSN_BLTZAL /* bltzal $rt, label */
       }, /* BR_RANGE_S64K */
       {
-       INSN_BGEZ,  /* bgez $rt, $1 */
+       INSN_BGEZ, /* bgez $rt, $1 */
         INSN_JAL /* jal label */
       }, /* BR_RANGE_S16M */
       {
-       INSN_BGEZ,  /* bgez $rt, $1 */
+       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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -283,18 +233,21 @@ static relax_info_t relax_table[] =
         {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},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5},
         {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},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6},
         {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},
+       {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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
@@ -303,9 +256,9 @@ static relax_info_t relax_table[] =
     "bgezal",                                  /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BGEZAL /* bgezal $rt, label */
@@ -317,38 +270,38 @@ static relax_info_t relax_table[] =
         INSN_BGEZAL /* bgezal $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BLTZ,  /* bltz $rt, $1 */
+        INSN_BLTZ, /* bltz $rt, $1 */
         INSN_JAL /* jal label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BLTZ,  /* bltz $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -365,26 +318,29 @@ static relax_info_t relax_table[] =
         {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},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5},
         {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},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6},
         {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}
+       {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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
   {
     "j",                                       /* opcode */
     BR_RANGE_S16M,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
     {
       {
         (INSN_J8 << 16) /* j8 label */
@@ -403,14 +359,14 @@ static relax_info_t relax_table[] =
         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 */
+    },                                         /* relax_code_seq */
+    {
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */
+      {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */
+    },                                         /* relax_code_condition */
     {2, 4, 4, 4, 12},                          /* relax_code_size */
     {2, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -432,18 +388,20 @@ static relax_info_t relax_table[] =
       }, /* 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}
+       {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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
   {
     "j8",                                      /* opcode */
     BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                               /* cond_field */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
     {
       {
         (INSN_J8 << 16) /* j8 label */
@@ -462,14 +420,14 @@ static relax_info_t relax_table[] =
         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 */
+    },                                         /* relax_code_seq */
+    {
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */
+      {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */
+    },                                         /* relax_code_condition */
     {2, 4, 4, 4, 12},                          /* relax_code_size */
     {2, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -491,11 +449,13 @@ static relax_info_t relax_table[] =
       }, /* 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}
+       {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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -503,9 +463,9 @@ static relax_info_t relax_table[] =
     "beqz",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                 /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BEQZ /* beqz $rt, label */
@@ -517,44 +477,44 @@ static relax_info_t relax_table[] =
         INSN_BEQZ /* beqz $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BNEZ,  /* bnez $rt, $1 */
+        INSN_BNEZ, /* bnez $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BNEZ,  /* bnez $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* 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, 4, 0, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -566,20 +526,24 @@ static relax_info_t relax_table[] =
         {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}
+       {0, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {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, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
@@ -588,9 +552,9 @@ static relax_info_t relax_table[] =
     "bgez",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BGEZ /* bgez $rt, label */
@@ -602,38 +566,38 @@ static relax_info_t relax_table[] =
         INSN_BGEZ /* bgez $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BLTZ,  /* bltz $rt, $1 */
+        INSN_BLTZ, /* bltz $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BLTZ,  /* bltz $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -650,19 +614,22 @@ static relax_info_t relax_table[] =
         {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},
+       {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -670,9 +637,9 @@ static relax_info_t relax_table[] =
     "bnez",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BNEZ /* bnez $rt, label */
@@ -684,44 +651,44 @@ static relax_info_t relax_table[] =
         INSN_BNEZ /* bnez $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BEQZ,  /* beqz $rt, $1 */
+        INSN_BEQZ, /* beqz $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BEQZ,  /* beqz $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* 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, 4, 0, BFD_RELOC_NDS32_17_PCREL},
+       {0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -733,21 +700,25 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -755,9 +726,9 @@ static relax_info_t relax_table[] =
     "bgtz",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BGTZ /* bgtz $rt, label */
@@ -769,38 +740,38 @@ static relax_info_t relax_table[] =
         INSN_BGTZ /* bgtz $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BLEZ,  /* blez $rt, $1 */
+        INSN_BLEZ, /* blez $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BLEZ,  /* blez $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -817,19 +788,22 @@ static relax_info_t relax_table[] =
         {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},
+       {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -837,9 +811,9 @@ static relax_info_t relax_table[] =
     "blez",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                         /* cond_field */
     {
       {
         INSN_BLEZ /* blez $rt, label */
@@ -851,38 +825,38 @@ static relax_info_t relax_table[] =
         INSN_BLEZ /* blez $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BGTZ,  /* bgtz $rt, $1 */
+        INSN_BGTZ, /* bgtz $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BGTZ,  /* bgtz $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -899,19 +873,22 @@ static relax_info_t relax_table[] =
         {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},
+       {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -919,9 +896,9 @@ static relax_info_t relax_table[] =
     "bltz",                                    /* opcode */
     BR_RANGE_S64K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BLTZ /* bltz $rt, label */
@@ -933,38 +910,38 @@ static relax_info_t relax_table[] =
         INSN_BLTZ /* bltz $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BGEZ,  /* bgez $rt, $1 */
+        INSN_BGEZ, /* bgez $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BGEZ,  /* bgez $rt, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 4, 4, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -981,19 +958,22 @@ static relax_info_t relax_table[] =
         {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},
+       {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1001,10 +981,10 @@ static relax_info_t relax_table[] =
     "beq",                                     /* opcode */
     BR_RANGE_S16K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      {0, 15, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 15, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BEQ /* beq $rt, $ra, label */
@@ -1026,40 +1006,40 @@ static relax_info_t relax_table[] =
         INSN_ORI_TA, /* ori $ta, $ta, label */
         INSN_JR_TA /* jr $ta */
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* 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, 4, 0, BFD_RELOC_NDS32_15_PCREL},
+        {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1067,28 +1047,34 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_ABS, BFD_RELOC_NDS32_EMPTY},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1096,10 +1082,10 @@ static relax_info_t relax_table[] =
     "bne",                                     /* opcode */
     BR_RANGE_S16K,                             /* br_range */
     {
-      {0, 20, 0x1F},
-      {0, 15, 0x1F},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 20, 0x1F, FALSE},
+      {0, 15, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                         /* cond_field */
     {
       {
         INSN_BNE /* bne $rt, $ra, label */
@@ -1121,40 +1107,40 @@ static relax_info_t relax_table[] =
         INSN_ORI_TA, /* ori $ta, $ta, label */
         INSN_JR_TA /* jr $ta */
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 15, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 15, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* 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, 4, 0, BFD_RELOC_NDS32_15_PCREL},
+        {0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1162,28 +1148,33 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1191,12 +1182,12 @@ static relax_info_t relax_table[] =
     "beqz38",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 8, 0x7, FALSE},
+      {0, 0, 0, FALSE}
+    },                                         /* cond_field */
     {
       {
-        INSN_BEQZ /* beqz $rt, label */
+        INSN_BEQZ38 << 16 /* beqz $rt, label */
       }, /* BR_RANGE_S256 */
       {
         INSN_BEQZ /* beqz $rt, label */
@@ -1205,7 +1196,7 @@ static relax_info_t relax_table[] =
         INSN_BEQZ /* beqz $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BNEZ,  /* bnez $rt, $1 */
+        INSN_BNEZ, /* bnez $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
@@ -1214,35 +1205,34 @@ static relax_info_t relax_table[] =
         INSN_ORI_TA, /* ori $ta, $ta, label */
         INSN_JR_TA /* jr $ta */
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
+    },                                         /* relax_code_condition */
+    {2, 4, 4, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1254,21 +1244,25 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1276,12 +1270,12 @@ static relax_info_t relax_table[] =
     "bnez38",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 8, 0x7, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
-        INSN_BNEZ /* bnez $rt, label */
+        INSN_BNEZ38 << 16 /* bnez $rt, label */
       }, /* BR_RANGE_S256 */
       {
         INSN_BNEZ /* bnez $rt, label */
@@ -1290,7 +1284,7 @@ static relax_info_t relax_table[] =
         INSN_BNEZ /* bnez $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BEQZ,  /* beqz $rt, $1 */
+        INSN_BEQZ, /* beqz $rt, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
@@ -1299,35 +1293,34 @@ static relax_info_t relax_table[] =
         INSN_ORI_TA, /* ori $ta, $ta, label */
         INSN_JR_TA /* jr $ta */
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_seq */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 4, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
+    },                                         /* relax_code_condition */
+    {2, 4, 4, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1339,40 +1332,44 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
   {
     "beqzs8",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                                       /* cond_field */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
     {
       {
-        INSN_BEQZ_TA /* beqz $r15, label */
+        INSN_BEQZS8 << 16 /* beqz $r15, label */
       }, /* BR_RANGE_S256 */
       {
-        INSN_BNEZ /* bnez $rt, label */
+        INSN_BEQZ_TA /* bnez $rt, label */
       }, /* BR_RANGE_S16K */
       {
-        INSN_BNEZ /* bnez $rt, label */
+        INSN_BEQZ_TA /* bnez $rt, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BNEZ_TA,  /* bnez $r15, $1 */
+        INSN_BNEZ_TA, /* bnez $r15, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
@@ -1381,20 +1378,19 @@ static relax_info_t relax_table[] =
         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 */
+    },                                         /* relax_code_seq */
+    {
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */
+      {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */
+    },                                         /* relax_code_condition */
+    {2, 4, 4, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1406,20 +1402,24 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
@@ -1427,10 +1427,10 @@ static relax_info_t relax_table[] =
   {
     "bnezs8",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
-    {{0, 0, 0}},                                       /* cond_field */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
     {
       {
-        INSN_BNEZ_TA /* bnez $r15, label */
+        INSN_BNEZS8 << 16 /* bnez $r15, label */
       }, /* BR_RANGE_S256 */
       {
         INSN_BNEZ_TA /* bnez $r15, label */
@@ -1439,29 +1439,28 @@ static relax_info_t relax_table[] =
         INSN_BNEZ_TA /* bnez $r15, label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BEQZ_TA,  /* beqz $r15, $1 */
+        INSN_BEQZ_TA, /* beqz $r15, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BEQZ_TA,  /* beqz $r15, $1 */
+        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 */
+    },                                         /* relax_code_seq */
+    {
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S256 */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S64K */
+      {{0, 0, 0, FALSE}}, /* BR_RANGE_S16M */
+      {{0, 0, 0, FALSE}} /* BR_RANGE_U4G */
+    },                                         /* relax_code_condition */
+    {2, 4, 4, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1473,21 +1472,25 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1495,59 +1498,58 @@ static relax_info_t relax_table[] =
     "bnes38",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 8, 0x7, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
-        INSN_BNE_R5 /* bne $rt, $r5, label */
+        INSN_BNES38 << 16 /* bne $rt, $R5, label */
       }, /* BR_RANGE_S256 */
       {
-        INSN_BNE_R5 /* bne $rt, $r5, label */
+        INSN_BNE_R5 /* bne $rt, $R5, label */
       }, /* BR_RANGE_S16K */
       {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
+        INSN_BEQ_R5, /* beq $rt, $R5, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
+        INSN_BEQ_R5, /* beq $rt, $R5, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BEQ_R5,  /* beq $rt, $r5, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
+    },                                         /* relax_code_condition */
+    {2, 4, 8, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1555,28 +1557,33 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1584,59 +1591,58 @@ static relax_info_t relax_table[] =
     "beqs38",                                  /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7},
-      { 0, 0, 0 }
-    },                                         /* cond_field */
+      {0, 8, 0x7, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
-        INSN_BEQ_R5 /* beq $rt, $r5, label */
+        INSN_BEQS38 << 16 /* beq $rt, $R5, label */
       }, /* BR_RANGE_S256 */
       {
-        INSN_BEQ_R5 /* beq $rt, $r5, label */
+        INSN_BEQ_R5 /* beq $rt, $R5, label */
       }, /* BR_RANGE_S16K */
       {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
+        INSN_BNE_R5, /* bne $rt, $R5, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
+        INSN_BNE_R5, /* bne $rt, $R5, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BNE_R5,  /* bne $rt, $r5, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
-    {4, 4, 8, 8, 16},                          /* relax_code_size */
-    {4, 4, 4, 4, 4},                           /* relax_branch_isize */
+    },                                         /* relax_code_condition */
+    {2, 4, 8, 8, 16},                          /* relax_code_size */
+    {2, 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, 2, 0, BFD_RELOC_NDS32_9_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
@@ -1644,28 +1650,33 @@ static relax_info_t relax_table[] =
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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, 4, NDS32_CREATE_LABEL, 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, 0, BFD_RELOC_NDS32_25_PCREL},
+       {4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
         {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}
+        {0, 4, NDS32_CREATE_LABEL, 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}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
@@ -1673,60 +1684,60 @@ static relax_info_t relax_table[] =
     "beqc",                                    /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7FF},
-      {0, 20, 0x1F},
-      {0, 0, 0}
-    },                                         /* cond_field */
+      {0, 8, 0x7FF, TRUE},
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BEQC /* beqc $rt, imm11s, label */
       }, /* BR_RANGE_S256 */
       {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
+        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 */
+        INSN_BNEC, /* bnec $rt, imm11s, $1 */
+        INSN_J /* j label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BNEC,  /* bnec $rt, imm11s, $1 */
+        INSN_BNEC, /* bnec $rt, imm11s, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BNEC,  /* bnec $rt, imm11s, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, TRUE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
+        {0, 0, 0xFFFFF, FALSE},
+        {4, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 8, 8, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -1735,24 +1746,26 @@ static relax_info_t relax_table[] =
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7},
         {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S16K */
       {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL},
+        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S64K */
       {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
+        {0, 4, NDS32_CREATE_LABEL, 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},
+        {0, 4, NDS32_CREATE_LABEL, 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},
+       {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI},
+       {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
@@ -1761,60 +1774,60 @@ static relax_info_t relax_table[] =
     "bnec",                                    /* opcode */
     BR_RANGE_S256,                             /* br_range */
     {
-      {0, 8, 0x7FF},
-      {0, 20, 0x1F},
-      {0, 0, 0}
-    },                                         /* cond_field */
+      {0, 8, 0x7FF, TRUE},
+      {0, 20, 0x1F, FALSE},
+      {0, 0, 0, FALSE}
+    },                                                 /* cond_field */
     {
       {
         INSN_BNEC /* bnec $rt, imm11s, label */
       }, /* BR_RANGE_S256 */
       {
-        INSN_MOVI_TA,  /* movi $ta, imm11s */
+        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 */
+        INSN_BEQC, /* beqc $rt, imm11s, $1 */
+        INSN_J /* j label */
       }, /* BR_RANGE_S64K */
       {
-        INSN_BEQC,  /* beqc $rt, imm11s, $1 */
+        INSN_BEQC, /* beqc $rt, imm11s, $1 */
         INSN_J /* j label */
       }, /* BR_RANGE_S16M */
       {
-        INSN_BEQC,  /* beqc $rt, imm11s, $1 */
+        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 */
+    },                                         /* relax_code_seq */
     {
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, TRUE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S256 */
       {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
+        {0, 0, 0xFFFFF, FALSE},
+        {4, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16K */
       {
-        {0, 0, 0xFFFFF},
-        {4, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S64K */
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       }, /* BR_RANGE_S16M */
       {
-        {0, 8, 0x7FF},
-        {0, 20, 0x1F},
-        {0, 0, 0}
+        {0, 8, 0x7FF, FALSE},
+        {0, 20, 0x1F, FALSE},
+        {0, 0, 0, FALSE}
       } /* BR_RANGE_U4G */
-    },                                 /* relax_code_condition */
+    },                                         /* relax_code_condition */
     {4, 8, 8, 8, 16},                          /* relax_code_size */
     {4, 4, 4, 4, 4},                           /* relax_branch_isize */
     {
@@ -1823,40 +1836,41 @@ static relax_info_t relax_table[] =
         {0, 0, 0, 0}
       }, /* BR_RANGE_S256 */
       {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
+       {0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16},
+       {0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7},
+       {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S16K */
       {
-        {4, 4, 0, BFD_RELOC_NDS32_15_PCREL},
+        {0, 4, NDS32_CREATE_LABEL, BFD_RELOC_NDS32_WORD_9_PCREL},
+        {4, 4, 0, BFD_RELOC_NDS32_25_PCREL},
         {0, 0, 0, 0}
       }, /* BR_RANGE_S64K */
       {
-        {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL},
+        {0, 4, NDS32_CREATE_LABEL, 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},
+        {0, 4, NDS32_CREATE_LABEL, 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},
+       {12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16},
         {0, 0, 0, 0}
       } /* BR_RANGE_U4G */
     }                                          /* relax_fixup */
   },
   {
-    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 */
+    NULL,                                      /* opcode */
+    0,                                         /* br_range */
+    {{0, 0, 0, FALSE}},                        /* cond_field */
+    {{0}},                                     /* relax_code_seq */
+    {{{0, 0, 0, FALSE}}},                      /* relax_code_condition */
+    {0},                                       /* relax_code_size */
+    {0},                                       /* relax_branch_isize */
+    {{{0, 0, 0, 0}}},                          /* relax_fixup */
   },
 };
-
 \f
 /* GAS definitions for command-line options.  */
 enum options
@@ -1872,7 +1886,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 +1898,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},
@@ -2131,7 +2146,9 @@ 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)
@@ -2177,9 +2194,9 @@ static void
 do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], 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 && strstr (arg_label, "@PLT"))
     {
       md_assemblef ("sethi $ta,hi20(%s)", arg_label);
       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label);
@@ -2190,12 +2207,14 @@ do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
     {
       md_assemblef ("j %s", arg_label);
     }
+  relaxing = FALSE;
 }
 
 static void
 do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], 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")))
@@ -2209,6 +2228,7 @@ do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
     {
       md_assemblef ("jal %s", arg_label);
     }
+  relaxing = FALSE;
 }
 
 static void
@@ -2291,21 +2311,38 @@ 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, const char *arg_label,
+                      const char *line)
 {
+  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,6 +2364,7 @@ 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
@@ -2390,16 +2428,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"))
        {
@@ -2430,6 +2488,7 @@ do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv)
        {
          as_bad (_("needs @GOT or @GOTOFF. %s"), argv[argc]);
        }
+      relaxing = FALSE;
     }
 }
 
@@ -2464,7 +2523,7 @@ static void
 do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], 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 = "";
@@ -2521,18 +2580,25 @@ do_pseudo_move_reg_internal (char *dst, char *src)
 static void
 do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED)
 {
+  expressionS exp;
+
+  parse_expression (argv[1], &exp);
+
   if (builtin_isreg (argv[1], NULL))
     do_pseudo_move_reg_internal (argv[0], argv[1]);
+  else if (exp.X_op == O_constant)
+    /* move $rt, imm  -> li $rt, imm  */
+    do_pseudo_li_internal (argv[0], exp.X_add_number);
   else
-    /* move $rt, imm  -> li $rt, imm */
-    do_pseudo_li (argc, argv, PV_DONT_CARE);
+    /* 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)
 {
-  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
@@ -2586,10 +2652,21 @@ 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
@@ -2842,7 +2919,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},
@@ -3138,7 +3215,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 +3236,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)
@@ -3409,12 +3490,8 @@ nds32_aligned_cons (int idx)
 
       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);
     }
 }
 
@@ -3528,12 +3605,14 @@ 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);
@@ -3649,6 +3728,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.  */
@@ -3795,12 +3875,23 @@ 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);
+           {
+             fragP = frag_now;
+             frag_align_code (n, max);
+
+             /* Tag this alignment when there is a lable before it.  */
+             if (label_exist)
+               {
+                 fragP->tc_frag_data.flag = NDS32_FRAG_LABEL;
+                 label_exist = 0;
+               }
+           }
          else
            frag_align (n, 0, max);
        }
@@ -3888,7 +3979,7 @@ md_begin (void)
 
   /* Initial general pupose 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 +3989,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 +4057,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,19 +4103,19 @@ 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_opcode *opcode,
                               char *out, symbolS *sym,
-                              struct nds32_relocs_pattern *reloc_ptr)
+                              struct nds32_relocs_pattern *reloc_ptr,
+                              fragS *fragP)
 {
   if (!reloc_ptr)
     reloc_ptr = malloc (sizeof (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->next = NULL;
   return reloc_ptr;
@@ -4029,88 +4123,103 @@ nds32_elf_save_pseudo_pattern (int reloc, struct nds32_asm_insn *insn,
 
 /* 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, 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.  */
+       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 = BFD_RELOC_NDS32_TLS_IE_HI20;
+         break;
+       default:        /* No suffix.  */
          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;
+           default:    /* No suffix.  */
+             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 = 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 = R_NDS32_LO12S2_SP_RELA;         /* 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 +4236,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))
@@ -4144,9 +4252,16 @@ 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, 0 /* pcrel */,
-                  reloc);
+      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))
@@ -4157,20 +4272,50 @@ 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)
-    {
-      as_bad (_("Don't know how to handle this field. %s"),
-             str);
+  else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_IFC_EXT))
+    {
+      /* Relocation for ifcall instruction.  */
+      if (insn->opcode->isize == 2 && fld->bitsize == 9 && fld->shift == 1)
+       reloc = BFD_RELOC_NDS32_10IFCU_PCREL;
+      else if (insn->opcode->isize == 4 && fld->bitsize == 16
+              && fld->shift == 1)
+       reloc = BFD_RELOC_NDS32_17IFC_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_opcode *opcode, fragS *fragP,
+                               const struct nds32_field *fld)
+{
+  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_opcode)
     {
       /* Save instruction relation for pseudo instruction expanding pattern.  */
-      reloc_ptr = nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, NULL);
+      reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, opcode, out, sym,
+                                                NULL, fragP);
       if (!relocs_list)
        relocs_list = reloc_ptr;
       else
@@ -4187,267 +4332,120 @@ nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld,
       group = nds32_relax_hint_current;
       while (group)
        {
-         nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, group->pattern);
+         nds32_elf_save_pseudo_pattern (fixP, opcode, 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)
+#define N32_MEM_EXT(insn) ((N32_OP6_MEM << 25) | insn)
 
 /* Relax pattern for link time relaxation.  */
 
-static struct nds32_relocation_map relocation_table[] =
+static struct nds32_relax_hint_table relax_ls_table[] =
 {
+  {
+    /* Set address: la -> sethi ori.  */
+    NDS32_RELAX_HINT_LA,       /* main_type */
+    8,                         /* relax_code_size */
     {
-      /* 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}
-       }
-      },
-    },
+      OP6 (SETHI),
+      OP6 (ORI),
+    },                         /* relax_code_seq */
     {
-      /* 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},
-       },
-      },
-    },
+      {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+      {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16}
+    }                          /* relax_fixup */
+  },
+  {
+    /* Set address: l.w -> sethi ori.  */
+    NDS32_RELAX_HINT_LS,       /* main_type */
+    8,                         /* relax_code_size */
     {
-      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},
-       },
-      },
-    },
+      OP6 (SETHI),
+      OP6 (LBI),
+    },                         /* relax_code_seq */
     {
-      0,
-      {
-        {
-          {0, 0},
-       },
-      },
-    }
+      {0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE},
+      {4, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_INSN16}
+    }                          /* relax_fixup */
+  },
+  {
+    0,
+    0,
+    {0},
+    {{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 *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;
-      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;
-      break;
-    case INSN_LWI:
-    case INSN_SWI:
-    case N32_MEM_EXT (N32_MEM_LW):
-    case N32_MEM_EXT (N32_MEM_SW):
-      range = 0x04;
-      break;
-    case INSN_FLSI:
-    case INSN_FSSI:
-      range = 0x08;
-      break;
-    case INSN_FLDI:
-    case INSN_FSDI:
-      range = 0x10;
-      break;
-    case INSN_ORI:
-      range = 0x20;
-      break;
-    default:
-      range = 0x0;
-      break;
-    }
-  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))
-
-/* Insert new fix.  */
-
-static void
-nds32_elf_insert_relocation (struct nds32_relocs_pattern *pattern, unsigned int reloc,
-                            unsigned int insn_mask, symbolS *sym)
+nds32_elf_sethi_range (struct nds32_relocs_pattern *pattern)
 {
-  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)
+  int range = 0;
+  while (pattern)
     {
-    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;
-
-    case BFD_RELOC_NDS32_PTR:
-      pattern_t = pattern->next;
-      while (pattern_t)
+      switch (pattern->opcode->value)
        {
-         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;
-
-    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;
-
-    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)
-       {
-         exp.X_add_symbol = sym;
-         fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc);
-       }
-      break;
-
-    case BFD_RELOC_NDS32_PTR_RESOLVED:
-    default:
-      if (insn_mask == 0 || pattern->insn == insn_mask)
-       {
-         fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc);
+       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))
+
 static void
 nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn)
 {
@@ -4562,58 +4560,525 @@ nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn)
   /* TODO: E_NDS32_HAS_SATURATION_INST */
 }
 
+/* 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),
+};
+
+struct nds32_hint_map
+{
+  bfd_reloc_code_real_type hi_type;
+  char *opc;
+  enum nds32_relax_hint_type hint_type;
+  enum nds32_br_range range;
+  enum nds32_insn_type insn_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
+    },
+    {
+      /* LONGCALL5.  */
+      _dummy_first_bfd_reloc_code_real,
+      "bgezal",
+      NDS32_RELAX_HINT_NONE,
+      BR_RANGE_S16M,
+      N32_RELAX_BR | N32_RELAX_CALL
+    },
+    {
+      /* 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
+    },
+    {
+      /* LONGJUMP4.  */
+      BFD_RELOC_NDS32_HI20,
+      "j",
+      NDS32_RELAX_HINT_NONE,
+      BR_RANGE_U4G,
+      N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_JUMP
+    },
+    {
+      /* LONGJUMP5.  */
+      /* There is two kinds of veriation 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
+    },
+    {
+      /* 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
+    },
+    {
+      /* LONGJUMP7.  */
+      _dummy_first_bfd_reloc_code_real,
+      "beqc",
+      NDS32_RELAX_HINT_NONE,
+      BR_RANGE_S16K,
+      N32_RELAX_MOVI | N32_RELAX_BR
+    },
+    {
+      /* LOADSTORE ADDRESS.  */
+      BFD_RELOC_NDS32_HI20,
+      NULL,
+      NDS32_RELAX_HINT_LA,
+      BR_RANGE_U4G,
+      N32_RELAX_SETHI | N32_RELAX_ORI
+    },
+    {
+      /* LOADSTORE ADDRESS.  */
+      BFD_RELOC_NDS32_HI20,
+      NULL,
+      NDS32_RELAX_HINT_LS,
+      BR_RANGE_U4G,
+      N32_RELAX_SETHI | N32_RELAX_LSI
+    },
+    {0, NULL, 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;
+  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;
+  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_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:
+             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.  */
+         for (i = 0; i < sizeof (check_insn) / sizeof (check_insn[0]); i++)
+           {
+             if (strcmp (pattern->opcode->opcode, check_insn[i]) == 0)
+               {
+                 relax_type |= N32_RELAX_BR;
+                 break;
+               }
+           }
+         if (strcmp (pattern->opcode->opcode, "movi55") == 0)
+           relax_type |= N32_RELAX_MOVI;
+       }
+      pattern = pattern->next;
+    }
+
+  /* Analysis instruction flag to choose relaxation table.  */
+  while (map_ptr->insn_list != 0)
+    {
+      if (map_ptr->insn_list == relax_type
+         && (!hi_pattern
+             || (hi_pattern->fixP
+                 && hi_pattern->fixP->fx_r_type == map_ptr->hi_type)))
+       {
+         opc = map_ptr->opc;
+         hint_type = map_ptr->hint_type;
+         range = map_ptr->range;
+         break;
+       }
+      map_ptr++;
+    }
+
+  if (map_ptr->insn_list == 0)
+    {
+      as_warn (_("Can not find match relax hint. line : %d"),
+              relocs_pattern->frag->fr_line);
+      return FALSE;
+    }
+
+  /* Get the match table.  */
+  if (opc)
+    {
+      /* 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)
+       {
+         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
+    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)
+    {
+      if (fixup_info->ramp & NDS32_HINT)
+       {
+         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 sequance.  */
+  memcpy (hint_code, code_seq, seq_size);
+  return TRUE;
+}
+
+/* Because there are a lot of variant of load-store, check
+   all these type here.  */
+
+#define CLEAN_REG(insn) ((insn) & 0xff0003ff)
+static bfd_boolean
+nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq)
+{
+  char *check_insn[] =
+    { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" };
+  uint32_t insn = opcode->value;
+  unsigned int i;
+
+  insn = CLEAN_REG (opcode->value);
+  if (insn == seq)
+    return TRUE;
+
+  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))
+        return TRUE;
+      break;
+    case OP6 (BR2):
+      /* This is for LONGCALL5 and LONGCALL6.  */
+      if (insn == OP6 (BR2))
+        return TRUE;
+      break;
+    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 < sizeof (check_insn) / sizeof (check_insn[0]); i++)
+           if (strcmp (opcode->opcode, check_insn[i]) == 0)
+             return TRUE;
+       }
+      break;
+    case OP6 (MOVI):
+      /* This is for LONGJUMP7.  */
+      if (opcode->isize == 2 && strcmp (opcode->opcode, "movi55") == 0)
+        return TRUE;
+      break;
+    }
+  return FALSE;
+}
+
 /* Append relax relocation for link time relaxing.  */
 
 static void
 nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value)
 {
-  struct nds32_relocs_pattern *relocs_temp =
+  struct nds32_relocs_pattern *relocs_pattern =
     (struct nds32_relocs_pattern *) value;
-  unsigned int reloc, group_type, insn;
-  symbolS *sym;
-  unsigned int i = 0, x = 0, y;
+  struct nds32_relocs_pattern *pattern_temp, *pattern_now;
+  symbolS *sym, *hi_sym = NULL;
+  expressionS exp;
+  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;
+  fixS *fixP;
+  int range, offset;
+  unsigned int ptr_offset, hint_count, relax_code_size, count = 0;
+  uint32_t *code_seq, code_insn;
+  char *where;
+
+  if (!relocs_pattern)
+    return;
 
-  if (!relocs_temp)
+  if (!nds32_find_reloc_table (relocs_pattern, &hint_info))
     return;
 
-  group_type = relocs_temp->reloc;
-  sym = relocs_temp->sym;
+  /* Save symbol for some EMPTY relocation using.  */
+  pattern_now = relocs_pattern;
+  while (pattern_now)
+    {
+      if (pattern_now->opcode->value == OP6 (SETHI))
+       {
+         hi_sym = pattern_now->sym;
+         break;
+       }
+      pattern_now = pattern_now->next;
+    }
+
   /* Inserting fix up must specify now_seg or frchain_now.  */
-  now_seg = relocs_temp->seg;
-  frchain_now = relocs_temp->frchain;
+  now_seg = relocs_pattern->seg;
+  frchain_now = relocs_pattern->frchain;
+  fragP = relocs_pattern->frag;
+  branch_offset = fragP->fr_offset;
 
-  /* Find pattern in relocation table.  */
-  while (i < (sizeof (relocation_table)/sizeof (relocation_table[0]))
-        &&relocation_table[i].main_type != group_type)
-    i++;
+  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;
 
-  /* Can not find relocation pattern.  */
-  if (relocation_table[i].main_type == 0)
-    return;
+  /* Insert relaxation.  */
+  exp.X_op = O_symbol;
 
-  while (relocs_temp)
+  while (pattern_now)
     {
-      y = 0;
+      /* Choose the match fixup by instruction.  */
+      code_insn = CLEAN_REG (*(code_seq + count));
+      if (!nds32_match_hint_insn (pattern_now->opcode, code_insn))
+       {
+         count = 0;
+         code_insn = CLEAN_REG (*(code_seq + count));
 
-      while (relocation_table[i].reloc_insn[x][y][0] != 0)
+         while (!nds32_match_hint_insn (pattern_now->opcode, code_insn))
+           {
+             count++;
+             if (count >= relax_code_size / 4)
+               {
+                 as_bad (_("Internal error: Relax hint error. %s: %x"),
+                         now_seg->name, pattern_now->opcode->value);
+                 goto restore;
+               }
+             code_insn = CLEAN_REG (*(code_seq + count));
+           }
+       }
+      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)
+       {
+         fixup_now++;
+         if (fixup_now->size == 0)
+           break;
+       }
+      /* This element is without relaxation relocation.  */
+      if (fixup_now->size == 0)
        {
-         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++;
+         pattern_now = pattern_now->next;
+         continue;
        }
+      fixup_size = fixup_now->size;
 
-      /* Next instruction.  */
-      relocs_temp = relocs_temp->next;
+      /* Insert all fixup.  */
+      while (fixup_size != 0 && fixup_now->offset == offset)
+       {
+         /* Set the real instruction size in element.  */
+         fixup_size = pattern_now->opcode->isize;
+         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 = branch_offset;
+           }
+         else
+           {
+             exp.X_add_symbol = sym;
+             exp.X_add_number = branch_offset;
+           }
 
-      /* 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++;
+         if (fixup_size != 0)
+           {
+             fixP = fix_new_exp (fragP, where - fragP->fr_literal,
+                                 fixup_size, &exp, 0, fixup_now->r_type);
+             fixP->fx_addnumber = fixP->fx_offset;
+           }
+         fixup_now++;
+         fixup_size = fixup_now->size;
+       }
+      if (count < relax_code_size / 4)
+       count++;
+      pattern_now = pattern_now->next;
     }
 
+restore:
   now_seg = seg_bak;
   frchain_now = frchain_bak;
 }
@@ -4663,12 +5128,12 @@ 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;
+  fragS *fragP;
+  int label = label_exist;
 
   popcode = nds32_lookup_pseudo_opcode (str);
   /* Note that we need to check 'verbatim' and
@@ -4694,6 +5159,7 @@ md_assemble (char *str)
       return;
     }
 
+  label_exist = 0;
   insn.info = (expressionS *) alloca (sizeof (expressionS));
   nds32_assemble (&asm_desc, &insn, str);
 
@@ -4728,76 +5194,115 @@ md_assemble (char *str)
   if (!nds32_check_insn_available (insn, str))
     return;
 
-  /* Create new frag if the instruction can be relaxed.  */
+  /* Make sure the begining of text being 2-byte align.  */
+  nds32_adjust_label (1);
   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 msut 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);
 
       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;
       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 (!fld && !relaxing && enable_16bit && (optimize || optimize_for_space)
+          && ((!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.  */
+      dwarf2_emit_insn (0);
+      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 instrucion 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);
+      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 insturction 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, 0, 0, &exp, 0, BFD_RELOC_NDS32_LABEL);
        }
     }
-
-  out = frag_more (insn.opcode->isize);
+  else
+    out = frag_more (insn.opcode->isize);
 
   if (insn.opcode->isize == 4)
     bfd_putb32 (insn.insn, out);
-  else if (insn.opcode->isize == 2)
+  if (insn.opcode->isize == 2)
     bfd_putb16 (insn.insn, out);
 
   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.  */
+  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.opcode, fragP, fld);
 }
 
 /* md_macro_start  */
@@ -4933,10 +5438,17 @@ 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++;
     }
 }
@@ -4959,8 +5471,6 @@ 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); */
@@ -5023,18 +5533,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;
@@ -5050,6 +5548,89 @@ 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 = ~((~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)
+{
+  addressT address;
+  fragS *frag_start = *prev_frag;
+
+  if (!frag_start)
+    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 lable.  */
+         if (frag_t->tc_frag_data.flag & NDS32_FRAG_LABEL)
+           {
+             prev_frag = NULL;
+             return;
+           }
+         /* Relax previos 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;
+    }
+}
+
 /* md_relax_frag  */
 
 int
@@ -5059,9 +5640,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);
 
-  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
+       unendless loop when relaxing.  Once the instruction is relaxed,
+       it can not be undo.  */
+    prev_frag = fragP;
 
   return adjust;
 }
@@ -5083,9 +5676,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 previos relaxable frag.  */
+  static fragS *prev_frag = NULL;
+  int adjust = 0;
+
+  invalid_prev_frag (fragP, &prev_frag);
 
-  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;
 }
@@ -5115,26 +5719,21 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP)
   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;
-  uint16_t insn_16;
-  int insn_type;
+  int code_size, insn_size, offset, fixup_size;
   int buf_offset;
-  nds32_relax_fixup_info_t fixup_info[MAX_RELAX_NUM];
+  int i, k;
+  uint16_t insn_16;
+  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;
 
   /* 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
@@ -5142,142 +5741,150 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP)
   if (opcode == NULL)
     return;
 
-  relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
-
-  if (relax_info == NULL)
-    return;
-
-  backup_endian = target_big_endian;
-  target_big_endian = 1;
-
-  fr_where = fragP->fr_fix - opcode->isize;
-  fr_buffer = fragP->fr_literal + fr_where;
-
-  if ((S_GET_SEGMENT (branch_symbol) != sec)
-      || S_IS_WEAK (branch_symbol))
+  /* Relax the insntruction.  */
+  if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)
     {
-      if (fragP->fr_offset & 3)
-       as_warn (_("Addend to unresolved symbol is not on word boundary."));
-      addend = 0;
+      expressionS exp_t;
+      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_t.X_op = O_symbol;
+      exp_t.X_add_symbol = abs_section_sym;
+      exp_t.X_add_number = 0;
+      fix_new_exp (fragP, fr_where, 4, &exp_t, 0,
+                  BFD_RELOC_NDS32_INSN16);
+      number_to_chars_bigendian (fr_buffer, insn, 4);
     }
   else
     {
-      /* 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;
-    }
+      /* Branch instruction adjust and append relocations.  */
+      relax_info = hash_find (nds32_relax_info_hash, opcode->opcode);
+
+      if (relax_info == NULL)
+       return;
 
-  code_size = relax_info->relax_code_size[branch_range_type];
-  code_seq = relax_info->relax_code_seq[branch_range_type];
+      backup_endian = target_big_endian;
+      target_big_endian = 1;
 
-  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;
-       }
+         nds32_elf_get_set_cond (relax_info, offset, &insn,
+                                 origin_insn, branch_range_type);
 
-      offset += insn_size;
-      i++;
-    }
-
-  /* Set up fixup.  */
-  exp.X_op = O_symbol;
+         /* 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.  */
 
-  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;
+         md_number_to_chars (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;
+
+         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;
+           }
+
+         if (fixup_info[i].r_type != 0)
+           {
+             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;
+           }
        }
-    }
 
-  fragP->fr_fix = fr_where + buf_offset;
+      fragP->fr_fix = fr_where + buf_offset;
 
-  target_big_endian = backup_endian;
+      target_big_endian = backup_endian;
+    }
 }
 
 /* tc_frob_file_before_fix  */
@@ -5287,15 +5894,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  */
 
@@ -5446,7 +6100,7 @@ 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.  */
@@ -5547,8 +6201,8 @@ nds32_set_section_relocs (asection *sec, arelent ** relocs ATTRIBUTE_UNUSED,
 {
   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);
+    nds32_insertion_sort (sec->orelocation, sec->reloc_count,
+                         sizeof (arelent**), compar_relent);
 }
 
 long
@@ -5573,8 +6227,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 +6248,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 +6266,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;
@@ -5658,21 +6318,37 @@ 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;
+
+      /* Tranform specific relocations here for later relocation generation.
+        Tag data here for ex9 relaxtion and tag tls data for linker.  */
+      switch (fixP->fx_r_type)
+       {
+       case BFD_RELOC_NDS32_DATA:
+         if (!enable_relax_ex9)
+           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:
+         S_SET_THREAD_LOCAL (fixP->fx_addsy);
+         break;
+       default:
+         break;
+       }
       return;
     }
 
@@ -5772,7 +6448,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;
        }
     }
@@ -5796,7 +6473,8 @@ nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
        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;
        }
     }
@@ -5847,6 +6525,15 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
   return reloc;
 }
 
+struct suffix_name suffix_table[] =
+{
+  {"GOTOFF",   BFD_RELOC_NDS32_GOTOFF, 1},
+  {"GOT",      BFD_RELOC_NDS32_GOT20,  1},
+  {"TPOFF",    BFD_RELOC_NDS32_TPOFF,  0},
+  {"PLT",      BFD_RELOC_NDS32_25_PLTREL,      1},
+  {"GOTTPOFF", BFD_RELOC_NDS32_GOTTPOFF,       0}
+};
+
 /* Implement md_parse_name.  */
 
 int
@@ -5854,35 +6541,32 @@ 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;
 
-  segment = S_GET_SEGMENT (exprP->X_add_symbol);
-  if (segment != undefined_section)
-    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];
+             if (!nds32_pic && suffix_table[i].pic)
+               as_bad (_("need PIC qualifier with symbol."));
+             exprP->X_md = suffix_table[i].reloc;
              *input_line_pointer = *nextcharP;
              input_line_pointer = next;
              *nextcharP = *input_line_pointer;
@@ -5891,10 +6575,6 @@ nds32_parse_name (char const *name, expressionS *exprP,
            }
        }
     }
-
-  exprP->X_op = O_symbol;
-  exprP->X_add_number = 0;
-
   return 1;
 }
 
@@ -5903,18 +6583,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);
 }
index 731bb87..1483d51 100644 (file)
 #define TARGET_BYTES_BIG_ENDIAN        1
 #endif
 
-/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT
-   symbols.  The relocation type is stored in X_md.  */
-#define O_PIC_reloc O_md1
-
 /* as.c.  */
 /* Extend GAS command line option handling capability.  */
 extern int nds32_parse_option (int, char *);
@@ -154,6 +150,12 @@ extern void nds32_do_align (int);
 #define LOCAL_LABELS_FB                                1 /* Permit temporary numeric labels.  */
 
 /* frags.c.  */
+
+#define NDS32_FRAG_RELAXABLE 0x1
+#define NDS32_FRAG_RELAXED 0x2
+#define NDS32_FRAG_BRANCH 0x4
+#define NDS32_FRAG_LABEL 0x8
+
 struct nds32_frag_type
 {
   relax_substateT flag;
@@ -211,10 +213,16 @@ enum nds32_br_range
 
 enum nds32_ramp
 {
-  NDS32_CREATE_LABLE = 1,
-  NDS32_RELAX = 2,
-  NDS32_ORIGIN = 4,
-  NDS32_CONVERT = 8
+  NDS32_CREATE_LABEL = 1,
+  NDS32_RELAX = (1 << 1), /* Obsolete in the future.  */
+  NDS32_ORIGIN = (1 << 2),
+  NDS32_INSN16 = (1 << 3),
+  NDS32_PTR = (1 << 4),
+  NDS32_ABS = (1 << 5),
+  NDS32_HINT = (1 << 6),
+  NDS32_FIX = (1 << 7),
+  NDS32_ADDEND = (1 << 8),
+  NDS32_SYM = (1 << 9)
 };
 
 typedef struct nds32_relax_fixup_info
@@ -231,13 +239,15 @@ typedef struct nds32_cond_field
   int offset;
   int bitpos; /* Register position.  */
   int bitmask; /* Number of register bits.  */
+  bfd_boolean signed_extend;
 } nds32_cond_field_t;
 
 /* The max relaxation pattern is 20-bytes including the nop.  */
 #define NDS32_MAXCHAR 20
 /* In current, the max entend number of instruction for one pseudo instruction
-   is 4, but its number of relocation may be 5.  */
-#define MAX_RELAX_NUM 8
+   is 4, but its number of relocation may be 12.  */
+#define MAX_RELAX_NUM 4
+#define MAX_RELAX_FIX 12
 
 typedef struct nds32_relax_info
 {
@@ -248,17 +258,24 @@ typedef struct nds32_relax_info
   /* Code sequences for different branch range.  */
   uint32_t relax_code_seq[BR_RANGE_NUM][MAX_RELAX_NUM];
   nds32_cond_field_t relax_code_condition[BR_RANGE_NUM][MAX_RELAX_NUM];
-  int relax_code_size[BR_RANGE_NUM];
+  unsigned int relax_code_size[BR_RANGE_NUM];
   int relax_branch_isize[BR_RANGE_NUM];
-  nds32_relax_fixup_info_t relax_fixup[BR_RANGE_NUM][MAX_RELAX_NUM];
+  nds32_relax_fixup_info_t relax_fixup[BR_RANGE_NUM][MAX_RELAX_FIX];
 } relax_info_t;
 
-/* Relocation table.  */
-struct nds32_relocation_map
+enum nds32_relax_hint_type
+{
+  NDS32_RELAX_HINT_NONE = 0,
+  NDS32_RELAX_HINT_LA,
+  NDS32_RELAX_HINT_LS
+};
+
+struct nds32_relax_hint_table
 {
-  unsigned int main_type;
-  /* Number of instructions, {relocations type, instruction type}.  */
-  unsigned int reloc_insn[6][6][3];
+  enum nds32_relax_hint_type main_type;
+  unsigned int relax_code_size;
+  uint32_t relax_code_seq[MAX_RELAX_NUM];
+  nds32_relax_fixup_info_t relax_fixup[MAX_RELAX_FIX];
 };
 
 #endif /* TC_NDS32 */
index ab0a542..dd9bd9b 100644 (file)
@@ -1,3 +1,7 @@
+2014-09-16  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * nds32.h: Declare new relocations.
+
 2014-09-15  Andrew Bennett  <andrew.bennett@imgtec.com>
            Matthew Fortune  <matthew.fortune@imgtec.com>
 
index 216bbc1..71aa4aa 100644 (file)
@@ -76,7 +76,6 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type)
   RELOC_NUMBER (R_NDS32_GOTOFF, 43)
   RELOC_NUMBER (R_NDS32_GOTPC20, 44)
   RELOC_NUMBER (R_NDS32_GOT_HI20, 45)
-
   RELOC_NUMBER (R_NDS32_GOT_LO12, 46)
   RELOC_NUMBER (R_NDS32_GOTPC_HI20, 47)
   RELOC_NUMBER (R_NDS32_GOTPC_LO12, 48)
@@ -95,8 +94,8 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type)
   RELOC_NUMBER (R_NDS32_15_FIXED_RELA, 61)
   RELOC_NUMBER (R_NDS32_17_FIXED_RELA, 62)
   RELOC_NUMBER (R_NDS32_25_FIXED_RELA, 63)
-  RELOC_NUMBER (R_NDS32_PLTREL_HI20, 64)
-  RELOC_NUMBER (R_NDS32_PLTREL_LO12, 65)
+  RELOC_NUMBER (R_NDS32_PLTREL_HI20, 64)       /* This is obsoleted.  */
+  RELOC_NUMBER (R_NDS32_PLTREL_LO12, 65)       /* This is obsoleted.  */
   RELOC_NUMBER (R_NDS32_PLT_GOTREL_HI20, 66)
   RELOC_NUMBER (R_NDS32_PLT_GOTREL_LO12, 67)
   RELOC_NUMBER (R_NDS32_SDA12S2_DP_RELA, 68)
@@ -123,22 +122,38 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type)
   RELOC_NUMBER (R_NDS32_GOT15S2_RELA, 89)
   RELOC_NUMBER (R_NDS32_GOT17S2_RELA, 90)
   RELOC_NUMBER (R_NDS32_5_RELA, 91)
-  RELOC_NUMBER (R_NDS32_10_UPCREL_RELA, 92)
+  RELOC_NUMBER (R_NDS32_10_UPCREL_RELA, 92)    /* This is obsoleted.  */
   RELOC_NUMBER (R_NDS32_SDA_FP7U2_RELA, 93)
   RELOC_NUMBER (R_NDS32_WORD_9_PCREL_RELA, 94)
   RELOC_NUMBER (R_NDS32_25_ABS_RELA, 95)
   RELOC_NUMBER (R_NDS32_17IFC_PCREL_RELA, 96)
   RELOC_NUMBER (R_NDS32_10IFCU_PCREL_RELA, 97)
+  RELOC_NUMBER (R_NDS32_TLS_LE_HI20, 98)
+  RELOC_NUMBER (R_NDS32_TLS_LE_LO12, 99)
+  RELOC_NUMBER (R_NDS32_TLS_IE_HI20, 100)
+  RELOC_NUMBER (R_NDS32_TLS_IE_LO12S2, 101)
+  RELOC_NUMBER (R_NDS32_TLS_TPOFF, 102)
+  RELOC_NUMBER (R_NDS32_TLS_LE_20, 103)
+  RELOC_NUMBER (R_NDS32_TLS_LE_15S0, 104)
+  RELOC_NUMBER (R_NDS32_TLS_LE_15S1, 105)
+  RELOC_NUMBER (R_NDS32_TLS_LE_15S2, 106)
+  RELOC_NUMBER (R_NDS32_LONGCALL4, 107)
+  RELOC_NUMBER (R_NDS32_LONGCALL5, 108)
+  RELOC_NUMBER (R_NDS32_LONGCALL6, 109)
+  RELOC_NUMBER (R_NDS32_LONGJUMP4, 110)
+  RELOC_NUMBER (R_NDS32_LONGJUMP5, 111)
+  RELOC_NUMBER (R_NDS32_LONGJUMP6, 112)
+  RELOC_NUMBER (R_NDS32_LONGJUMP7, 113)
 
   RELOC_NUMBER (R_NDS32_RELAX_ENTRY, 192)
   RELOC_NUMBER (R_NDS32_GOT_SUFF, 193)
   RELOC_NUMBER (R_NDS32_GOTOFF_SUFF, 194)
   RELOC_NUMBER (R_NDS32_PLT_GOT_SUFF, 195)
-  RELOC_NUMBER (R_NDS32_MULCALL_SUFF, 196)
+  RELOC_NUMBER (R_NDS32_MULCALL_SUFF, 196)     /* This is obsoleted.  */
   RELOC_NUMBER (R_NDS32_PTR, 197)
   RELOC_NUMBER (R_NDS32_PTR_COUNT, 198)
   RELOC_NUMBER (R_NDS32_PTR_RESOLVED, 199)
-  RELOC_NUMBER (R_NDS32_PLTBLOCK, 200)
+  RELOC_NUMBER (R_NDS32_PLTBLOCK, 200)         /* This is obsoleted.  */
   RELOC_NUMBER (R_NDS32_RELAX_REGION_BEGIN, 201)
   RELOC_NUMBER (R_NDS32_RELAX_REGION_END, 202)
   RELOC_NUMBER (R_NDS32_MINUEND, 203)
@@ -149,7 +164,9 @@ START_RELOC_NUMBERS (elf_nds32_reloc_type)
   RELOC_NUMBER (R_NDS32_DIFF_ULEB128, 208)
   RELOC_NUMBER (R_NDS32_DATA, 209)
   RELOC_NUMBER (R_NDS32_TRAN, 210)
-  RELOC_NUMBER (R_NDS32_FPBASE, 211)
+  RELOC_NUMBER (R_NDS32_TLS_LE_ADD, 211)
+  RELOC_NUMBER (R_NDS32_TLS_LE_LS, 212)
+  RELOC_NUMBER (R_NDS32_EMPTY, 213)
 
 END_RELOC_NUMBERS (R_NDS32_max)
 
index d50a456..ca27cc2 100644 (file)
@@ -1,3 +1,10 @@
+2014-09-16  Kuan-Lin Chen  <kuanlinchentw@gmail.com>
+
+       * emultempl/nds32elf.em (nds32_elf_after_open): Do not keep
+       ex9 234th entry.
+       (nds32_elf_after_allocation): Move all optimizations into
+       nds32_elf_relax_section.
+
 2014-09-15  Andrew Bennett  <andrew.bennett@imgtec.com>
            Matthew Fortune  <matthew.fortune@imgtec.com>
 
index cad6715..592471e 100644 (file)
@@ -52,7 +52,8 @@ nds32_elf_create_output_section_statements (void)
   if (strstr (bfd_get_target (link_info.output_bfd), "nds32") == NULL)
     {
       /* Check the output target is nds32.  */
-      einfo ("%F%X%P: error: Cannot change output format whilst linking NDS32 binaries.\n");
+      einfo ("%F%X%P: error: Cannot change output format whilst "
+            "linking NDS32 binaries.\n");
       return;
     }
 
@@ -124,8 +125,9 @@ nds32_elf_after_open (void)
          einfo (_("%F%B: ABI version of object files mismatched\n"), abfd);
        }
 
+#if defined NDS32_EX9_EXT
       /* Append .ex9.itable section in the last input object file.  */
-      if (!link_info.relocatable && abfd->link.next == NULL)
+      if (abfd->link_next == NULL && (target_optimize & NDS32_RELAX_EX9_ON))
        {
          asection *itable;
          struct bfd_link_hash_entry *h;
@@ -137,17 +139,8 @@ nds32_elf_after_open (void)
            {
              itable->gc_mark = 1;
              itable->alignment_power = 2;
-             if ((target_optimize & NDS32_RELAX_EX9_ON))
-               {
-                 itable->size = 0x1000;
-                 itable->contents = bfd_zalloc (abfd, itable->size);
-               }
-             else
-               {
-                 itable->size = 0x4;
-                 itable->contents = bfd_zalloc (abfd, itable->size);
-                 bfd_putb32 (INSN_BREAK_EA,itable->contents);
-               }
+             itable->size = 0x1000;
+             itable->contents = bfd_zalloc (abfd, itable->size);
 
              /* Add a symbol in the head of ex9.itable to objdump clearly.  */
              h = bfd_link_hash_lookup (link_info.hash, "_EX9_BASE_",
@@ -158,6 +151,7 @@ nds32_elf_after_open (void)
                 get_elf_backend_data (link_info.output_bfd)->collect, &h);
            }
        }
+#endif
     }
 
   /* Check object files if the target is dynamic linked executable
@@ -173,12 +167,14 @@ nds32_elf_after_open (void)
              if (link_info.shared || link_info.pie)
                {
                  /* For PIE or shared object, all input must be PIC.  */
-                 einfo (_("%B: must use -fpic to compile this file for shared object or PIE\n"), abfd);
+                 einfo (_("%B: must use -fpic to compile this file "
+                          "for shared object or PIE\n"), abfd);
                }
              else
                {
                  /* Dynamic linked executable with SDA and non-PIC.
                     Turn off load/store relaxtion.  */
+                 /* TODO: This may support in the future.  */
                  load_store_relax = 0 ;
                  relax_fp_as_gp = 0;
                }
@@ -192,108 +188,22 @@ nds32_elf_after_open (void)
   gld${EMULATION_NAME}_after_open ();
 }
 
-static void nds32_elf_relax_stub (bfd_boolean relax)
-{
-  /* Re-caculate memory map address.  */
-  lang_do_assignments (lang_assigning_phase_enum);
-  lang_reset_memory_regions ();
-  one_lang_size_sections_pass (&relax, FALSE);
-}
-
 static void
 nds32_elf_after_allocation (void)
 {
-  struct elf_nds32_link_hash_table *table;
-  table = nds32_elf_hash_table (&link_info);
+  if (target_optimize & NDS32_RELAX_EX9_ON
+      || (ex9_import_file != NULL && update_ex9_table == 1))
+    {
+      /* Initialize ex9 hash table.  */
+      if (!nds32_elf_ex9_init ())
+        return;
+    }
 
   /* Call default after allocation callback.
      1. This is where relaxation is done.
      2. It calls gld${EMULATION_NAME}_map_segments to build ELF segment table.
      3. Any relaxation requires relax being done must be called after it.  */
   gld${EMULATION_NAME}_after_allocation ();
-
-  if (!table)
-    return;
-
-  /* Use IFC */
-  if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON)
-      && !(table->relax_status & NDS32_RELAX_JUMP_IFC_DONE))
-    {
-      table->relax_round = NDS32_RELAX_JUMP_IFC_ROUND;
-      /* Traverse all sections to build j and jal list.  */
-      nds32_elf_relax_stub (TRUE);
-
-      /* Replace with ifc.  */
-      if (!nds32_elf_ifc_finish (&link_info))
-       einfo (_("%F: Please report this bug. IFC error.\n"));
-      table->relax_round = NDS32_RELAX_NONE_ROUND;
-
-      /* Adjust address after ifcall.  */
-      nds32_elf_relax_stub (FALSE);
-
-      if (!nds32_elf_ifc_reloc ())
-       einfo (_("%F: Please report this bug. IFC error.\n"));
-    }
-
-  /* EX9 Instruction Table Relaxation.  */
-  if (!link_info.relocatable && !nds32_elf_ex9_itb_base (&link_info))
-    einfo (_("%F: Please report this bug. Ex9 relocation error.\n"));
-
-
-  /* Generate ex9 table.  */
-  if ((target_optimize & NDS32_RELAX_EX9_ON)
-      && !(table->relax_status & NDS32_RELAX_EX9_DONE))
-    {
-      /* Ex9 entry point.  */
-      table->relax_round = NDS32_RELAX_EX9_BUILD_ROUND;
-
-      /* Initialize ex9 hash table.  */
-      if (!nds32_elf_ex9_init ())
-       return;
-
-      /* Build ex9 instruction table.  */
-      nds32_elf_relax_stub (TRUE);
-      nds32_elf_ex9_finish (&link_info);
-      /* Replace with ex9.it.  */
-      nds32_elf_relax_stub (TRUE);
-      table->relax_round = NDS32_RELAX_NONE_ROUND;
-
-      /* Do ifc again.  */
-      if (target_optimize & NDS32_RELAX_JUMP_IFC_ON)
-       if (!nds32_elf_ifc_finish (&link_info))
-         einfo (_("%F: Please report this bug. IFC error.\n"));
-
-      /* Re-caculate memory map address.  */
-      lang_do_assignments (lang_assigning_phase_enum);
-      /* Relocation for .ex9.itable.  */
-      nds32_elf_ex9_reloc_jmp (&link_info);
-    }
-  else if (ex9_import_file != NULL
-      && !(table->relax_status = NDS32_RELAX_EX9_DONE))
-    {
-      /* Import ex9 table.  */
-
-      if (update_ex9_table == 1)
-       {
-         /* Build ex9 table.  */
-         table->relax_round = NDS32_RELAX_EX9_BUILD_ROUND;
-         /* Initialize ex9 hash table.  */
-         if (!nds32_elf_ex9_init ())
-           return;
-         /* Build ex9 table.  */
-         nds32_elf_relax_stub (TRUE);
-
-         /* Relocation for .ex9.itable.  */
-         lang_do_assignments (lang_assigning_phase_enum);
-         nds32_elf_ex9_reloc_jmp (&link_info);
-       }
-      nds32_elf_ex9_import_table (&link_info);
-
-      /* Replace with ex9.it.  */
-      table->relax_round = NDS32_RELAX_EX9_REPLACE_ROUND;
-      table->relax_status |= NDS32_RELAX_EX9_DONE;
-      nds32_elf_relax_stub (TRUE);
-    }
 }
 
 EOF
@@ -332,7 +242,7 @@ PARSE_AND_LIST_PROLOGUE='
 PARSE_AND_LIST_LONGOPTS='
   { "mfp-as-gp", no_argument, NULL, OPTION_FP_AS_GP},
   { "mno-fp-as-gp", no_argument, NULL, OPTION_NO_FP_AS_GP},
-  { "mgen-symbol-ld-script", required_argument, NULL, OPTION_EXPORT_SYMBOLS},
+  { "mexport-symbols", required_argument, NULL, OPTION_EXPORT_SYMBOLS},
   /* These are deprecated options.  Remove them in the future.  */
   { "mrelax-reduce-fp-update", no_argument, NULL, OPTION_REDUCE_FP_UPDATE},
   { "mrelax-no-reduce-fp-update", no_argument, NULL, OPTION_NO_REDUCE_FP_UPDATE},
@@ -399,7 +309,7 @@ PARSE_AND_LIST_ARGS_CASES='
     break;
   case OPTION_EXPORT_SYMBOLS:
     if (!optarg)
-      einfo (_("Missing file for --mgen-symbol-ld-script.\n"), optarg);
+      einfo (_("Missing file for --mexport-symbols.\n"), optarg);
 
     if(strcmp (optarg, "-") == 0)
       sym_ld_script = stdout;
@@ -425,7 +335,7 @@ PARSE_AND_LIST_ARGS_CASES='
       ex9_export_file = stdout;
     else
       {
-       ex9_export_file = fopen (optarg, FOPEN_WT);
+       ex9_export_file = fopen (optarg, "wb");
        if(ex9_export_file == NULL)
          einfo (_("ERROR %P%F: cannot open ex9 export file %s.\n"), optarg);
       }
@@ -434,7 +344,7 @@ PARSE_AND_LIST_ARGS_CASES='
     if (!optarg)
       einfo (_("Missing file for --mimport-ex9=<file>.\n"));
 
-    ex9_import_file = fopen (optarg, "r+");
+    ex9_import_file = fopen (optarg, "rb+");
     if(ex9_import_file == NULL)
       einfo (_("ERROR %P%F: cannot open ex9 import file %s.\n"), optarg);
     break;