gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / bfd / elf32-nds32.c
index a2e78ed047958196c683e07528bcc533534e67f3..01ea277426fb345bb5aad237edc899ab86369bfd 100644 (file)
@@ -1,5 +1,5 @@
 /* NDS32-specific support for 32-bit ELF.
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2020 Free Software Foundation, Inc.
    Contributed by Andes Technology Corporation.
 
    This file is part of BFD, the Binary File Descriptor library.
    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"
 #include "bfd.h"
-#include "bfd_stdint.h"
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "libiberty.h"
-#include "bfd_stdint.h"
 #include "elf/nds32.h"
 #include "opcode/nds32.h"
 #include "elf32-nds32.h"
 #include "opcode/cgen.h"
 #include "../opcodes/nds32-opc.h"
 
+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
 /* Relocation HOWTO functions.  */
 static bfd_reloc_status_type nds32_elf_ignore_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
@@ -56,70 +57,14 @@ static bfd_reloc_status_type nds32_elf_sda15_reloc
 static bfd_reloc_status_type nds32_elf_do_9_pcrel_reloc
   (bfd *, reloc_howto_type *, asection *, bfd_byte *, bfd_vma,
    asection *, bfd_vma, bfd_vma);
-static void nds32_elf_relocate_hi20
-  (bfd *, int, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *, bfd_vma);
-static reloc_howto_type *bfd_elf32_bfd_reloc_type_table_lookup
-  (enum elf_nds32_reloc_type);
-static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
-  (bfd *, bfd_reloc_code_real_type);
-
-/* Target hooks.  */
-static void nds32_info_to_howto_rel
-  (bfd *, arelent *, Elf_Internal_Rela *dst);
-static void nds32_info_to_howto
-  (bfd *, arelent *, Elf_Internal_Rela *dst);
-static bfd_boolean nds32_elf_add_symbol_hook
-  (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **,
-   flagword *, asection **, bfd_vma *);
-static bfd_boolean nds32_elf_relocate_section
-  (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
-   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **);
-static bfd_boolean nds32_elf_object_p (bfd *);
-static void nds32_elf_final_write_processing (bfd *, bfd_boolean);
-static bfd_boolean nds32_elf_set_private_flags (bfd *, flagword);
-static bfd_boolean nds32_elf_merge_private_bfd_data (bfd *, bfd *);
-static bfd_boolean nds32_elf_print_private_bfd_data (bfd *, void *);
-static bfd_boolean nds32_elf_gc_sweep_hook
-  (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
-static bfd_boolean nds32_elf_check_relocs
-  (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *);
-static asection *nds32_elf_gc_mark_hook
-  (asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-   struct elf_link_hash_entry *, Elf_Internal_Sym *);
-static bfd_boolean nds32_elf_adjust_dynamic_symbol
-  (struct bfd_link_info *, struct elf_link_hash_entry *);
-static bfd_boolean nds32_elf_size_dynamic_sections
-  (bfd *, struct bfd_link_info *);
-static bfd_boolean nds32_elf_create_dynamic_sections
-  (bfd *, struct bfd_link_info *);
-static bfd_boolean nds32_elf_finish_dynamic_sections
-  (bfd *, struct bfd_link_info *info);
-static bfd_boolean nds32_elf_finish_dynamic_symbol
-  (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
-   Elf_Internal_Sym *);
 
 /* Nds32 helper functions.  */
-static bfd_reloc_status_type nds32_elf_final_sda_base
-  (bfd *, struct bfd_link_info *, bfd_vma *, bfd_boolean);
-static bfd_boolean allocate_dynrelocs (struct elf_link_hash_entry *, void *);
-static bfd_boolean readonly_dynrelocs (struct elf_link_hash_entry *, void *);
-static Elf_Internal_Rela *find_relocs_at_address
-  (Elf_Internal_Rela *, Elf_Internal_Rela *,
-   Elf_Internal_Rela *, enum elf_nds32_reloc_type);
 static bfd_vma calculate_memory_address
   (bfd *, Elf_Internal_Rela *, Elf_Internal_Sym *, Elf_Internal_Shdr *);
-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 void nds32_elf_get_insn_with_reg
-  (Elf_Internal_Rela *, unsigned long, unsigned long *);
+static int nds32_get_section_contents (bfd *, asection *,
+                                      bfd_byte **, bfd_boolean);
 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_replace (struct bfd_link_info *);
 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,
@@ -143,6 +88,10 @@ enum
    section.  */
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
+#define NDS32_GUARD_SEC_P(flags) ((flags) & SEC_ALLOC \
+                                 && (flags) & SEC_LOAD \
+                                 && (flags) & SEC_READONLY)
+
 /* The nop opcode we use.  */
 #define NDS32_NOP32 0x40000009
 #define NDS32_NOP16 0x9200
@@ -154,39 +103,56 @@ enum
 /* The first entry in a procedure linkage table are reserved,
    and the initial contents are unimportant (we zero them out).
    Subsequent entries look like this.  */
-#define PLT0_ENTRY_WORD0  0x46f00000           /* sethi   r15, HI20(.got+4)      */
-#define PLT0_ENTRY_WORD1  0x58f78000           /* ori     r15, r25, LO12(.got+4) */
-#define PLT0_ENTRY_WORD2  0x05178000           /* lwi     r17, [r15+0]           */
-#define PLT0_ENTRY_WORD3  0x04f78001           /* lwi     r15, [r15+4]           */
-#define PLT0_ENTRY_WORD4  0x4a003c00           /* jr      r15                    */
+#define PLT0_ENTRY_WORD0  0x46f00000           /* sethi   r15, HI20(.got+4)      */
+#define PLT0_ENTRY_WORD1  0x58f78000           /* ori     r15, r25, LO12(.got+4) */
+#define PLT0_ENTRY_WORD2  0x05178000           /* lwi     r17, [r15+0]           */
+#define PLT0_ENTRY_WORD3  0x04f78001           /* lwi     r15, [r15+4]           */
+#define PLT0_ENTRY_WORD4  0x4a003c00           /* jr      r15                    */
 
 /* $ta is change to $r15 (from $r25).  */
 #define PLT0_PIC_ENTRY_WORD0  0x46f00000       /* sethi   r15, HI20(got[1]@GOT)  */
-#define PLT0_PIC_ENTRY_WORD1  0x58f78000       /* ori     r15, r15, LO12(got[1]@GOT) */
-#define PLT0_PIC_ENTRY_WORD2  0x40f7f400       /* add     r15, gp, r15           */
-#define PLT0_PIC_ENTRY_WORD3  0x05178000       /* lwi     r17, [r15+0]           */
-#define PLT0_PIC_ENTRY_WORD4  0x04f78001       /* lwi     r15, [r15+4]           */
-#define PLT0_PIC_ENTRY_WORD5  0x4a003c00       /* jr      r15                    */
-
-#define PLT_ENTRY_WORD0  0x46f00000            /* sethi   r15, HI20(&got[n+3])      */
-#define PLT_ENTRY_WORD1  0x04f78000            /* lwi     r15, r15, LO12(&got[n+3]) */
-#define PLT_ENTRY_WORD2  0x4a003c00            /* jr      r15                       */
-#define PLT_ENTRY_WORD3  0x45000000            /* movi    r16, sizeof(RELA) * n     */
-#define PLT_ENTRY_WORD4  0x48000000            /* j      .plt0.                     */
+#define PLT0_PIC_ENTRY_WORD1  0x58f78000       /* ori     r15, r15, LO12(got[1]@GOT) */
+#define PLT0_PIC_ENTRY_WORD2  0x40f7f400       /* add     r15, gp, r15           */
+#define PLT0_PIC_ENTRY_WORD3  0x05178000       /* lwi     r17, [r15+0]           */
+#define PLT0_PIC_ENTRY_WORD4  0x04f78001       /* lwi     r15, [r15+4]           */
+#define PLT0_PIC_ENTRY_WORD5  0x4a003c00       /* jr      r15                    */
+
+#define PLT_ENTRY_WORD0         0x46f00000             /* sethi   r15, HI20(&got[n+3])      */
+#define PLT_ENTRY_WORD1         0x04f78000             /* lwi     r15, r15, LO12(&got[n+3]) */
+#define PLT_ENTRY_WORD2         0x4a003c00             /* jr      r15                       */
+#define PLT_ENTRY_WORD3         0x45000000             /* movi    r16, sizeof(RELA) * n     */
+#define PLT_ENTRY_WORD4         0x48000000             /* j      .plt0.                     */
 
 #define PLT_PIC_ENTRY_WORD0  0x46f00000                /* sethi  r15, HI20(got[n+3]@GOT)    */
-#define PLT_PIC_ENTRY_WORD1  0x58f78000                /* ori    r15, r15,    LO12(got[n+3]@GOT) */
-#define PLT_PIC_ENTRY_WORD2  0x38febc02                /* lw     r15, [gp+r15]              */
-#define PLT_PIC_ENTRY_WORD3  0x4a003c00                /* jr     r15                        */
-#define PLT_PIC_ENTRY_WORD4  0x45000000                /* movi   r16, sizeof(RELA) * n      */
-#define PLT_PIC_ENTRY_WORD5  0x48000000                /* j      .plt0                      */
+#define PLT_PIC_ENTRY_WORD1  0x58f78000                /* ori    r15, r15,    LO12(got[n+3]@GOT) */
+#define PLT_PIC_ENTRY_WORD2  0x38febc02                /* lw     r15, [gp+r15]              */
+#define PLT_PIC_ENTRY_WORD3  0x4a003c00                /* jr     r15                        */
+#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[] =
@@ -215,24 +181,16 @@ struct elf_nds32_pcrel_relocs_copied
   bfd_size_type count;
 };
 
-/* The sh linker needs to keep track of the number of relocs that it
-   decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct elf_nds32_dyn_relocs
+enum elf_nds32_tls_type
 {
-  struct elf_nds32_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
+  GOT_UNKNOWN = (0),
+  GOT_NORMAL = (1 << 0),
+  GOT_TLS_LE = (1 << 1),
+  GOT_TLS_IE = (1 << 2),
+  GOT_TLS_IEGP = (1 << 3),
+  GOT_TLS_LD = (1 << 4),
+  GOT_TLS_GD = (1 << 5),
+  GOT_TLS_DESC = (1 << 6),
 };
 
 /* Nds32 ELF linker hash entry.  */
@@ -241,1724 +199,2324 @@ struct elf_nds32_link_hash_entry
 {
   struct elf_link_hash_entry root;
 
-  /* Track dynamic relocs copied for this symbol.  */
-  struct elf_nds32_dyn_relocs *dyn_relocs;
+  /* For checking relocation type.  */
+  enum elf_nds32_tls_type tls_type;
+
+  int offset_to_gp;
 };
 
 /* Get the nds32 ELF linker hash table from a link_info structure.  */
 
 #define FP_BASE_NAME "_FP_BASE_"
 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
+
+typedef struct
+{
+  int min_id;
+  int max_id;
+  int count;
+  int bias;
+  int init;
+} elf32_nds32_relax_group_t;
+
+struct elf_nds32_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+
+  /* GOTPLT entries for TLS descriptors.  */
+  bfd_vma *local_tlsdesc_gotent;
+
+  /* for R_NDS32_RELAX_GROUP handling.  */
+  elf32_nds32_relax_group_t relax_group;
+
+  unsigned int hdr_size;
+  int* offset_to_gp;
+};
+
+#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_local_gp_offset(bfd) \
+  (elf_nds32_tdata (bfd)->offset_to_gp)
+
+#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent))
+
+#define elf32_nds32_relax_group_ptr(bfd) \
+  &(elf_nds32_tdata (bfd)->relax_group)
+
+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.  */
+/* Define HOWTO2 (for relocation) and HOWTO3 (for relaxation) to
+   initialize array nds32_elf_howto_table in any order. The benefit
+   is that we can add any new relocations with any numbers and don't
+   need to fill the gap by lots of EMPTY_HOWTO. */
+#define HOWTO2(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+  [C] = HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC)
+
 static reloc_howto_type nds32_elf_howto_table[] =
 {
   /* This reloc does nothing.  */
-  HOWTO (R_NDS32_NONE,         /* 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_NONE",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_NONE,                /* 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_NONE",        /* name  */
+        FALSE,                 /* partial_inplace  */
+        0,                     /* src_mask  */
+        0,                     /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 16 bit absolute relocation.  */
-  HOWTO (R_NDS32_16,           /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
-        nds32_elf_generic_reloc,       /* special_function */
-        "R_NDS32_16",          /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_16,          /* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_bitfield,/* complain_on_overflow  */
+        nds32_elf_generic_reloc,/* special_function  */
+        "R_NDS32_16",          /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 32 bit absolute relocation.  */
-  HOWTO (R_NDS32_32,           /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
-        nds32_elf_generic_reloc,       /* special_function */
-        "R_NDS32_32",          /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_32,          /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        32,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_bitfield,/* complain_on_overflow  */
+        nds32_elf_generic_reloc,/* special_function  */
+        "R_NDS32_32",          /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 20 bit address.  */
-  HOWTO (R_NDS32_20,           /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        20,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned,    /* complain_on_overflow */
-        nds32_elf_generic_reloc,       /* special_function */
-        "R_NDS32_20",          /* name */
-        FALSE,                 /* partial_inplace */
-        0xfffff,               /* src_mask */
-        0xfffff,               /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_20,          /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        20,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_unsigned,/* complain_on_overflow  */
+        nds32_elf_generic_reloc,/* special_function  */
+        "R_NDS32_20",          /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xfffff,               /* src_mask  */
+        0xfffff,               /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* An PC Relative 9-bit relocation, shifted by 2.
      This reloc is complicated because relocations are relative to pc & -4.
      i.e. branches in the right insn slot use the address of the left insn
      slot for pc.  */
-  /* ??? It's not clear whether this should have partial_inplace set or not.
+  /* It's not clear whether this should have partial_inplace set or not.
      Branch relaxing in the assembler can store the addend in the insn,
      and if bfd_install_relocation gets called the addend may get added
      again.  */
-  HOWTO (R_NDS32_9_PCREL,      /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        nds32_elf_9_pcrel_reloc,       /* special_function */
-        "R_NDS32_9_PCREL",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_9_PCREL,     /* type  */
+        1,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        nds32_elf_9_pcrel_reloc,/* special_function  */
+        "R_NDS32_9_PCREL",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xff,                  /* src_mask  */
+        0xff,                  /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 15 bit relocation, right shifted by 1.  */
-  HOWTO (R_NDS32_15_PCREL,     /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        14,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_15_PCREL",    /* name */
-        FALSE,                 /* partial_inplace */
-        0x3fff,                /* src_mask */
-        0x3fff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_15_PCREL,    /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        14,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_15_PCREL",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x3fff,                /* src_mask  */
+        0x3fff,                /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 17 bit relocation, right shifted by 1.  */
-  HOWTO (R_NDS32_17_PCREL,     /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_17_PCREL",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_17_PCREL,    /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_17_PCREL",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 25 bit relocation, right shifted by 1.  */
-  /* ??? It's not clear whether this should have partial_inplace set or not.
+  /* It's not clear whether this should have partial_inplace set or not.
      Branch relaxing in the assembler can store the addend in the insn,
      and if bfd_install_relocation gets called the addend may get added
      again.  */
-  HOWTO (R_NDS32_25_PCREL,     /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        24,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_25_PCREL",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffff,              /* src_mask */
-        0xffffff,              /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_25_PCREL,    /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        24,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_25_PCREL",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffff,              /* src_mask  */
+        0xffffff,              /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* High 20 bits of address when lower 12 is or'd in.  */
-  HOWTO (R_NDS32_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 */
-        nds32_elf_hi20_reloc,  /* special_function */
-        "R_NDS32_HI20",        /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_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  */
+        nds32_elf_hi20_reloc,  /* special_function  */
+        "R_NDS32_HI20",        /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S3,       /* type */
-        3,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        9,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_lo12_reloc,  /* special_function */
-        "R_NDS32_LO12S3",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x000001ff,            /* src_mask */
-        0x000001ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S3,      /* type  */
+        3,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        9,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_lo12_reloc,  /* special_function  */
+        "R_NDS32_LO12S3",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000001ff,            /* src_mask  */
+        0x000001ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_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 */
-        nds32_elf_lo12_reloc,  /* special_function */
-        "R_NDS32_LO12S2",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x000003ff,            /* src_mask */
-        0x000003ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_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  */
+        nds32_elf_lo12_reloc,  /* special_function  */
+        "R_NDS32_LO12S2",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000003ff,            /* src_mask  */
+        0x000003ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S1,       /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        11,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_lo12_reloc,  /* special_function */
-        "R_NDS32_LO12S1",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x000007ff,            /* src_mask */
-        0x000007ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S1,      /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        11,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_lo12_reloc,  /* special_function  */
+        "R_NDS32_LO12S1",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000007ff,            /* src_mask  */
+        0x000007ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S0,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        12,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_lo12_reloc,  /* special_function */
-        "R_NDS32_LO12S0",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S0,      /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        12,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_lo12_reloc,  /* special_function  */
+        "R_NDS32_LO12S0",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S3,      /* type */
-        3,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        nds32_elf_sda15_reloc, /* special_function */
-        "R_NDS32_SDA15S3",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S3,     /* type  */
+        3,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        nds32_elf_sda15_reloc, /* special_function  */
+        "R_NDS32_SDA15S3",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S2,      /* type */
-        2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        nds32_elf_sda15_reloc, /* special_function */
-        "R_NDS32_SDA15S2",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S2,     /* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        nds32_elf_sda15_reloc, /* special_function  */
+        "R_NDS32_SDA15S2",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S1,      /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        nds32_elf_sda15_reloc, /* special_function */
-        "R_NDS32_SDA15S1",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S1,     /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        nds32_elf_sda15_reloc, /* special_function  */
+        "R_NDS32_SDA15S1",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S0,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        nds32_elf_sda15_reloc, /* special_function */
-        "R_NDS32_SDA15S0",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* GNU extension to record C++ vtable hierarchy */
-  HOWTO (R_NDS32_GNU_VTINHERIT,        /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_NDS32_GNU_VTINHERIT",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* GNU extension to record C++ vtable member usage */
-  HOWTO (R_NDS32_GNU_VTENTRY,  /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
-        "R_NDS32_GNU_VTENTRY", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S0,     /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        nds32_elf_sda15_reloc, /* special_function  */
+        "R_NDS32_SDA15S0",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* GNU extension to record C++ vtable hierarchy  */
+  HOWTO2 (R_NDS32_GNU_VTINHERIT,/* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        0,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        NULL,                  /* special_function  */
+        "R_NDS32_GNU_VTINHERIT",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0,                     /* src_mask  */
+        0,                     /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* GNU extension to record C++ vtable member usage  */
+  HOWTO2 (R_NDS32_GNU_VTENTRY, /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        0,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        _bfd_elf_rel_vtable_reloc_fn,/* special_function  */
+        "R_NDS32_GNU_VTENTRY", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0,                     /* src_mask  */
+        0,                     /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 16 bit absolute relocation.  */
-  HOWTO (R_NDS32_16_RELA,      /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_16_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_16_RELA,     /* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_bitfield,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_16_RELA",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 32 bit absolute relocation.  */
-  HOWTO (R_NDS32_32_RELA,      /* 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_32_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_32_RELA,     /* 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_32_RELA",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A 20 bit address.  */
-  HOWTO (R_NDS32_20_RELA,      /* 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_20_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xfffff,               /* src_mask */
-        0xfffff,               /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_9_PCREL_RELA, /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_9_PCREL_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_20_RELA,     /* 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_20_RELA",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xfffff,               /* src_mask  */
+        0xfffff,               /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_9_PCREL_RELA,        /* type  */
+        1,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_9_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xff,                  /* src_mask  */
+        0xff,                  /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 15 bit relocation, right shifted by 1.  */
-  HOWTO (R_NDS32_15_PCREL_RELA,        /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        14,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_15_PCREL_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0x3fff,                /* src_mask */
-        0x3fff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_15_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        14,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_15_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x3fff,                /* src_mask  */
+        0x3fff,                /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 17 bit relocation, right shifted by 1.  */
-  HOWTO (R_NDS32_17_PCREL_RELA,        /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_17_PCREL_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_17_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_17_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative 25 bit relocation, right shifted by 2.  */
-  HOWTO (R_NDS32_25_PCREL_RELA,        /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        24,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_25_PCREL_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffff,              /* src_mask */
-        0xffffff,              /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_25_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        24,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_25_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffff,              /* src_mask  */
+        0xffffff,              /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* High 20 bits of address when lower 16 is or'd in.  */
-  HOWTO (R_NDS32_HI20_RELA,    /* 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_HI20_RELA",   /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_HI20_RELA,   /* 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_HI20_RELA",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S3_RELA,  /* type */
-        3,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        9,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_LO12S3_RELA", /* name */
-        FALSE,                 /* partial_inplace */
-        0x000001ff,            /* src_mask */
-        0x000001ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S3_RELA, /* type  */
+        3,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        9,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_LO12S3_RELA", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000001ff,            /* src_mask  */
+        0x000001ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S2_RELA,  /* 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_LO12S2_RELA", /* name */
-        FALSE,                 /* partial_inplace */
-        0x000003ff,            /* src_mask */
-        0x000003ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S2_RELA, /* 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_LO12S2_RELA", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000003ff,            /* src_mask  */
+        0x000003ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S1_RELA,  /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        11,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_LO12S1_RELA", /* name */
-        FALSE,                 /* partial_inplace */
-        0x000007ff,            /* src_mask */
-        0x000007ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S1_RELA, /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        11,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_LO12S1_RELA", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000007ff,            /* src_mask  */
+        0x000007ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S0_RELA,  /* 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_LO12S0_RELA", /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S0_RELA, /* 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_LO12S0_RELA", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S3_RELA, /* type */
-        3,                     /* 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_SDA15S3_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S3_RELA,        /* type  */
+        3,                     /* 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_SDA15S3_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA15S2_RELA, /* 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_SDA15S2_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_SDA15S1_RELA, /* 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_SDA15S1_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_SDA15S0_RELA, /* 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_SDA15S0_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* GNU extension to record C++ vtable hierarchy */
-  HOWTO (R_NDS32_RELA_GNU_VTINHERIT,   /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_NDS32_RELA_GNU_VTINHERIT",  /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  /* GNU extension to record C++ vtable member usage */
-  HOWTO (R_NDS32_RELA_GNU_VTENTRY,     /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
-        "R_NDS32_RELA_GNU_VTENTRY",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA15S2_RELA,        /* 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_SDA15S2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_SDA15S1_RELA,        /* 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_SDA15S1_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_SDA15S0_RELA,        /* 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_SDA15S0_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* GNU extension to record C++ vtable hierarchy  */
+  HOWTO2 (R_NDS32_RELA_GNU_VTINHERIT,/* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        0,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        NULL,                  /* special_function  */
+        "R_NDS32_RELA_GNU_VTINHERIT",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0,                     /* src_mask  */
+        0,                     /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* GNU extension to record C++ vtable member usage  */
+  HOWTO2 (R_NDS32_RELA_GNU_VTENTRY,/* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        0,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        _bfd_elf_rel_vtable_reloc_fn,/* special_function  */
+        "R_NDS32_RELA_GNU_VTENTRY",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0,                     /* src_mask  */
+        0,                     /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Like R_NDS32_20, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_NDS32_GOT20,                /* 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_GOT20",       /* name */
-        FALSE,                 /* partial_inplace */
-        0xfffff,               /* src_mask */
-        0xfffff,               /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOT20,       /* 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_GOT20",       /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xfffff,               /* src_mask  */
+        0xfffff,               /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Like R_NDS32_PCREL, but referring to the procedure linkage table
      entry for the symbol.  */
-  HOWTO (R_NDS32_25_PLTREL,    /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        24,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_25_PLTREL",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffff,              /* src_mask */
-        0xffffff,              /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_25_PLTREL,   /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        24,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_25_PLTREL",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffff,              /* src_mask  */
+        0xffffff,              /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* This is used only by the dynamic linker.  The symbol should exist
      both in the object being run and in some shared library.  The
      dynamic linker copies the data addressed by the symbol from the
      shared library into the object, because the object being
      run has to have the data at some particular address.  */
-  HOWTO (R_NDS32_COPY,         /* 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_COPY",        /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_COPY,                /* 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_COPY",        /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Like R_NDS32_20, but used when setting global offset table
      entries.  */
-  HOWTO (R_NDS32_GLOB_DAT,     /* 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_GLOB_DAT",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GLOB_DAT,    /* 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_GLOB_DAT",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Marks a procedure linkage table entry for a symbol.  */
-  HOWTO (R_NDS32_JMP_SLOT,     /* 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_JMP_SLOT",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_JMP_SLOT,    /* 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_JMP_SLOT",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Used only by the dynamic linker.  When the object is run, this
      longword is set to the load address of the object, plus the
      addend.  */
-  HOWTO (R_NDS32_RELATIVE,     /* 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_RELATIVE",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_GOTOFF,       /* 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_GOTOFF",      /* name */
-        FALSE,                 /* partial_inplace */
-        0xfffff,               /* src_mask */
-        0xfffff,               /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_RELATIVE,    /* 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_RELATIVE",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_GOTOFF,      /* 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_GOTOFF",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xfffff,               /* src_mask  */
+        0xfffff,               /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* An PC Relative 20-bit relocation used when setting PIC offset
      table register.  */
-  HOWTO (R_NDS32_GOTPC20,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        20,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOTPC20",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xfffff,               /* src_mask */
-        0xfffff,               /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOTPC20,     /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        20,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOTPC20",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xfffff,               /* src_mask  */
+        0xfffff,               /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* Like R_NDS32_HI20, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_NDS32_GOT_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_GOT_HI20",    /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOT_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_GOT_LO12",    /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOT_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_GOT_HI20",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOT_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_GOT_LO12",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* An PC Relative relocation used when setting PIC offset table register.
      Like R_NDS32_HI20, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_NDS32_GOTPC_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_GOTPC_HI20",  /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-  HOWTO (R_NDS32_GOTPC_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_GOTPC_LO12",  /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-
-  HOWTO (R_NDS32_GOTOFF_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_GOTOFF_HI20", /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOTOFF_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_GOTOFF_LO12", /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOTPC_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_GOTPC_HI20",  /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOTPC_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_GOTPC_LO12",  /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_GOTOFF_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_GOTOFF_HI20", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOTOFF_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_GOTOFF_LO12", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Alignment hint for relaxable instruction.  This is used with
      R_NDS32_LABEL as a pair.  Relax this instruction from 4 bytes to 2
      in order to make next label aligned on word boundary.  */
-  HOWTO (R_NDS32_INSN16,       /* 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_INSN16",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_INSN16,      /* 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_INSN16",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Alignment hint for label.  */
-  HOWTO (R_NDS32_LABEL,                /* 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_LABEL",       /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LABEL,       /* 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_LABEL",       /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for unconditional call sequence  */
-  HOWTO (R_NDS32_LONGCALL1,    /* 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_LONGCALL1",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGCALL1,   /* 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_LONGCALL1",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for conditional call sequence.  */
-  HOWTO (R_NDS32_LONGCALL2,    /* 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_LONGCALL2",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGCALL2,   /* 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_LONGCALL2",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for conditional call sequence.  */
-  HOWTO (R_NDS32_LONGCALL3,    /* 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_LONGCALL3",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGCALL3,   /* 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_LONGCALL3",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for unconditional branch sequence.  */
-  HOWTO (R_NDS32_LONGJUMP1,    /* 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_LONGJUMP1",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGJUMP1,   /* 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_LONGJUMP1",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for conditional branch sequence.  */
-  HOWTO (R_NDS32_LONGJUMP2,    /* 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_LONGJUMP2",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGJUMP2,   /* 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_LONGJUMP2",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for conditional branch sequence.  */
-  HOWTO (R_NDS32_LONGJUMP3,    /* 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_LONGJUMP3",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LONGJUMP3,   /* 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_LONGJUMP3",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for load/store sequence.   */
-  HOWTO (R_NDS32_LOADSTORE,    /* 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_LOADSTORE",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LOADSTORE,   /* 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_LOADSTORE",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for load/store sequence.  */
-  HOWTO (R_NDS32_9_FIXED_RELA, /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_9_FIXED_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x000000ff,            /* src_mask */
-        0x000000ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_9_FIXED_RELA,        /* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_9_FIXED_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000000ff,            /* src_mask  */
+        0x000000ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for load/store sequence.  */
-  HOWTO (R_NDS32_15_FIXED_RELA,        /* 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_15_FIXED_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0x00003fff,            /* src_mask */
-        0x00003fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_15_FIXED_RELA,/* 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_15_FIXED_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00003fff,            /* src_mask  */
+        0x00003fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for load/store sequence.  */
-  HOWTO (R_NDS32_17_FIXED_RELA,        /* 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_17_FIXED_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_17_FIXED_RELA,/* 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_17_FIXED_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0000ffff,            /* src_mask  */
+        0x0000ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Relax hint for load/store sequence.  */
-  HOWTO (R_NDS32_25_FIXED_RELA,        /* 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_25_FIXED_RELA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0x00ffffff,            /* src_mask */
-        0x00ffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_25_FIXED_RELA,/* 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_25_FIXED_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00ffffff,            /* src_mask  */
+        0x00ffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* High 20 bits of PLT symbol offset relative to PC.  */
-  HOWTO (R_NDS32_PLTREL_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_PLTREL_HI20", /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLTREL_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_PLTREL_HI20", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Low 12 bits of PLT symbol offset relative to PC.  */
-  HOWTO (R_NDS32_PLTREL_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_PLTREL_LO12", /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLTREL_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_PLTREL_LO12", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* High 20 bits of PLT symbol offset relative to GOT (GP).  */
-  HOWTO (R_NDS32_PLT_GOTREL_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_PLT_GOTREL_HI20",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLT_GOTREL_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_PLT_GOTREL_HI20",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Low 12 bits of PLT symbol offset relative to GOT (GP).  */
-  HOWTO (R_NDS32_PLT_GOTREL_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_PLT_GOTREL_LO12",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLT_GOTREL_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_PLT_GOTREL_LO12",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 12 bits offset.  */
-  HOWTO (R_NDS32_SDA12S2_DP_RELA,      /* type */
-        2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        12,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA12S2_DP_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA12S2_DP_RELA,/* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        12,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA12S2_DP_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 12 bits offset.  */
-  HOWTO (R_NDS32_SDA12S2_SP_RELA,      /* type */
-        2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        12,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA12S2_SP_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA12S2_SP_RELA,/* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        12,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA12S2_SP_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* Lower 12 bits of address.  */
 
-  HOWTO (R_NDS32_LO12S2_DP_RELA,       /* 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_LO12S2_DP_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x000003ff,            /* src_mask */
-        0x000003ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S2_DP_RELA,      /* 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_LO12S2_DP_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000003ff,            /* src_mask  */
+        0x000003ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Lower 12 bits of address.  */
-  HOWTO (R_NDS32_LO12S2_SP_RELA,/* 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_LO12S2_SP_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x000003ff,            /* src_mask */
-        0x000003ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S2_SP_RELA,/* 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_LO12S2_SP_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000003ff,            /* src_mask  */
+        0x000003ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* Lower 12 bits of address.  Special identity for or case.  */
-  HOWTO (R_NDS32_LO12S0_ORI_RELA,      /* 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_LO12S0_ORI_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00000fff,            /* src_mask */
-        0x00000fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_LO12S0_ORI_RELA,/* 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_LO12S0_ORI_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* Small data area 19 bits offset.  */
-  HOWTO (R_NDS32_SDA16S3_RELA, /* type */
-        3,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA16S3_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA16S3_RELA,        /* type  */
+        3,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA16S3_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0000ffff,            /* src_mask  */
+        0x0000ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* Small data area 15 bits offset.  */
-  HOWTO (R_NDS32_SDA17S2_RELA, /* type */
-        2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        17,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA17S2_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x0001ffff,            /* src_mask */
-        0x0001ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_SDA18S1_RELA, /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        18,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA18S1_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x0003ffff,            /* src_mask */
-        0x0003ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_NDS32_SDA19S0_RELA, /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        19,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA19S0_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x0007ffff,            /* src_mask */
-        0x0007ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DWARF2_OP1_RELA,      /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_DWARF2_OP1_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DWARF2_OP2_RELA,      /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_DWARF2_OP2_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DWARF2_LEB_RELA,      /* 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_DWARF2_LEB_RELA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_UPDATE_TA_RELA,/* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_UPDATE_TA_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_SDA17S2_RELA,        /* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        17,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA17S2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0001ffff,            /* src_mask  */
+        0x0001ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_SDA18S1_RELA,        /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        18,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA18S1_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0003ffff,            /* src_mask  */
+        0x0003ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_SDA19S0_RELA,        /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        19,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA19S0_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0007ffff,            /* src_mask  */
+        0x0007ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_DWARF2_OP1_RELA,/* type  */
+        0,                     /* rightshift  */
+        0,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_DWARF2_OP1_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xff,                  /* src_mask  */
+        0xff,                  /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_DWARF2_OP2_RELA,/* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_DWARF2_OP2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_DWARF2_LEB_RELA,/* 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_DWARF2_LEB_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_UPDATE_TA_RELA,/* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_UPDATE_TA_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* Like R_NDS32_PCREL, but referring to the procedure linkage table
      entry for the symbol.  */
-  HOWTO (R_NDS32_9_PLTREL,     /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_9_PLTREL",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_9_PLTREL,    /* type  */
+        1,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_9_PLTREL",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xff,                  /* src_mask  */
+        0xff,                  /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
   /* Low 20 bits of PLT symbol offset relative to GOT (GP).  */
-  HOWTO (R_NDS32_PLT_GOTREL_LO20,      /* type */
-        0,                     /* 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_PLT_GOTREL_LO20",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x000fffff,            /* src_mask */
-        0x000fffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  /* low 15 bits of PLT symbol offset relative to GOT (GP) */
-  HOWTO (R_NDS32_PLT_GOTREL_LO15,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_PLT_GOTREL_LO15",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLT_GOTREL_LO20,/* type  */
+        0,                     /* 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_PLT_GOTREL_LO20",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* low 15 bits of PLT symbol offset relative to GOT (GP)  */
+  HOWTO2 (R_NDS32_PLT_GOTREL_LO15,/* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_PLT_GOTREL_LO15",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* Low 19 bits of PLT symbol offset relative to GOT (GP).  */
-  HOWTO (R_NDS32_PLT_GOTREL_LO19,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        19,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_PLT_GOTREL_LO19",     /* name */
-        FALSE,                 /* partial_inplace */
-        0x0007ffff,            /* src_mask */
-        0x0007ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOT_LO15,     /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOT_LO15",    /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOT_LO19,     /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        19,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOT_LO19",    /* name */
-        FALSE,                 /* partial_inplace */
-        0x0007ffff,            /* src_mask */
-        0x0007ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOTOFF_LO15,  /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOTOFF_LO15", /* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOTOFF_LO19,  /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        19,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOTOFF_LO19", /* name */
-        FALSE,                 /* partial_inplace */
-        0x0007ffff,            /* src_mask */
-        0x0007ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_PLT_GOTREL_LO19,/* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        19,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_PLT_GOTREL_LO19",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0007ffff,            /* src_mask  */
+        0x0007ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOT_LO15,    /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOT_LO15",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOT_LO19,    /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        19,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOT_LO19",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0007ffff,            /* src_mask  */
+        0x0007ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOTOFF_LO15, /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        15,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOTOFF_LO15", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_GOTOFF_LO19, /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        19,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOTOFF_LO19", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0007ffff,            /* src_mask  */
+        0x0007ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* GOT 15 bits offset.  */
-  HOWTO (R_NDS32_GOT15S2_RELA, /* 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_GOT15S2_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x00007fff,            /* src_mask */
-        0x00007fff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOT15S2_RELA,        /* 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_GOT15S2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00007fff,            /* src_mask  */
+        0x00007fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* GOT 17 bits offset.  */
-  HOWTO (R_NDS32_GOT17S2_RELA, /* type */
-        2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        17,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_GOT17S2_RELA",/* name */
-        FALSE,                 /* partial_inplace */
-        0x0001ffff,            /* src_mask */
-        0x0001ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_GOT17S2_RELA,        /* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        17,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_GOT17S2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0001ffff,            /* src_mask  */
+        0x0001ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
   /* A 5 bit address.  */
-  HOWTO (R_NDS32_5_RELA,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        5,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_5_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x1f,                  /* src_mask */
-        0x1f,                  /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_10_UPCREL_RELA,/* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        9,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned,    /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_10_UPCREL_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x1ff,                 /* src_mask */
-        0x1ff,                 /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-  HOWTO (R_NDS32_SDA_FP7U2_RELA,/* type */
-        2,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        7,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned,    /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_SDA_FP7U2_RELA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x0000007f,            /* src_mask */
-        0x0000007f,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_WORD_9_PCREL_RELA,    /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_WORD_9_PCREL_RELA",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xff,                  /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
-  HOWTO (R_NDS32_25_ABS_RELA,  /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        24,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_25_ABS_RELA", /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffff,              /* src_mask */
-        0xffffff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOWTO2 (R_NDS32_5_RELA,      /* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        5,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_5_RELA",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x1f,                  /* src_mask  */
+        0x1f,                  /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_10_UPCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        9,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_unsigned,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_10_UPCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x1ff,                 /* src_mask  */
+        0x1ff,                 /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
+  HOWTO2 (R_NDS32_SDA_FP7U2_RELA,/* type  */
+        2,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        7,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_unsigned,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_SDA_FP7U2_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0000007f,            /* src_mask  */
+        0x0000007f,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO2 (R_NDS32_WORD_9_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_WORD_9_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xff,                  /* src_mask  */
+        0xff,                  /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
+  HOWTO2 (R_NDS32_25_ABS_RELA, /* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        24,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_25_ABS_RELA", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffff,              /* src_mask  */
+        0xffffff,              /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 
   /* A relative 17 bit relocation for ifc, right shifted by 1.  */
-  HOWTO (R_NDS32_17IFC_PCREL_RELA,     /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed,      /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_17IFC_PCREL_RELA",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffff,                /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_17IFC_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_17IFC_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffff,                /* src_mask  */
+        0xffff,                /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
 
   /* A relative unsigned 10 bit relocation for ifc, right shifted by 1.  */
-  HOWTO (R_NDS32_10IFCU_PCREL_RELA,    /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        9,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_unsigned,    /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_NDS32_10IFCU_PCREL_RELA",   /* name */
-        FALSE,                 /* partial_inplace */
-        0x1ff,                 /* src_mask */
-        0x1ff,                 /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOWTO2 (R_NDS32_10IFCU_PCREL_RELA,/* type  */
+        1,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        9,                     /* bitsize  */
+        TRUE,                  /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_unsigned,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_10IFCU_PCREL_RELA",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x1ff,                 /* src_mask  */
+        0x1ff,                 /* dst_mask  */
+        TRUE),                 /* pcrel_offset  */
+
+  /* Like R_NDS32_HI20, but referring to the TLS LE entry for the symbol.  */
+  HOWTO2 (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  */
+
+  HOWTO2 (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 IE entry for the symbol.  */
+  HOWTO2 (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  */
+
+  HOWTO2 (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  */
+
+  /* TLS LE TP offset relocation  */
+  HOWTO2 (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.  */
+  HOWTO2 (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  */
+
+  HOWTO2 (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  */
+  HOWTO2 (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  */
+  HOWTO2 (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  */
+  HOWTO2 (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.  */
+  HOWTO2 (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.  */
+  HOWTO2 (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.  */
+  HOWTO2 (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.  */
+  HOWTO2 (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.  */
+  HOWTO2 (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.  */
+  HOWTO2 (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  */
+
+  HOWTO2 (R_NDS32_TLS_IE_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_IE_LO12", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* Like R_NDS32_HI20, but referring to the TLS IE (PIE)
+     entry for the symbol.  */
+  HOWTO2 (R_NDS32_TLS_IEGP_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_IEGP_HI20",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_TLS_IEGP_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_IEGP_LO12",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  HOWTO2 (R_NDS32_TLS_IEGP_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_IEGP_LO12S2",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000003ff,            /* src_mask  */
+        0x000003ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* TLS description relocation  */
+  HOWTO2 (R_NDS32_TLS_DESC,    /* type  */
+        12,                    /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        20,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_hi20_reloc,  /* special_function  */
+        "R_NDS32_TLS_DESC_HI20",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* TLS GD/LD description offset high part.  */
+  HOWTO2 (R_NDS32_TLS_DESC_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  */
+        nds32_elf_hi20_reloc,  /* special_function  */
+        "R_NDS32_TLS_DESC_HI20",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* TLS GD/LD description offset low part.  */
+  HOWTO2 (R_NDS32_TLS_DESC_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  */
+        nds32_elf_lo12_reloc,  /* special_function  */
+        "R_NDS32_TLS_DESC_LO12",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x00000fff,            /* src_mask  */
+        0x00000fff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* TLS GD/LD description offset set (movi).  */
+  HOWTO2 (R_NDS32_TLS_DESC_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_DESC_20", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000fffff,            /* src_mask  */
+        0x000fffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+
+  /* TLS GD/LD description offset set (lwi.gp).  */
+  HOWTO2 (R_NDS32_TLS_DESC_SDA17S2,/* type  */
+        2,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        17,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_signed,/* complain_on_overflow  */
+        bfd_elf_generic_reloc, /* special_function  */
+        "R_NDS32_TLS_DESC_SDA17S2",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0001ffff,            /* src_mask  */
+        0x0001ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
 };
 
 /* Relocations used for relaxation.  */
-static reloc_howto_type nds32_elf_relax_howto_table[] =
-{
-  HOWTO (R_NDS32_RELAX_ENTRY,  /* 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_RELAX_ENTRY", /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOT_SUFF,     /* 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_GOT_SUFF",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_GOTOFF_SUFF,  /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_GOTOFF_SUFF", /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_PLT_GOT_SUFF, /* 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_PLT_GOT_SUFF",/* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_MULCALL_SUFF, /* 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_MULCALL_SUFF",/* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_PTR,          /* 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_PTR",         /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_PTR_COUNT,    /* 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_PTR_COUNT",   /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_PTR_RESOLVED, /* 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_PTR_RESOLVED",/* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_PLTBLOCK,     /* 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_PLTBLOCK",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_RELAX_REGION_BEGIN,   /* 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_RELAX_REGION_BEGIN",  /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_RELAX_REGION_END,     /* 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_RELAX_REGION_END",    /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_MINUEND,      /* 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_MINUEND",     /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_SUBTRAHEND,   /* 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_SUBTRAHEND",  /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DIFF8,                /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_DIFF8",       /* name */
-        FALSE,                 /* partial_inplace */
-        0x000000ff,            /* src_mask */
-        0x000000ff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DIFF16,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_DIFF16",      /* name */
-        FALSE,                 /* partial_inplace */
-        0x0000ffff,            /* src_mask */
-        0x0000ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DIFF32,       /* 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_DIFF32",      /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DIFF_ULEB128, /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        nds32_elf_ignore_reloc,/* special_function */
-        "R_NDS32_DIFF_ULEB128",/* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_DATA,         /* 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_DATA",        /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
-  HOWTO (R_NDS32_TRAN,         /* 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_TRAN",        /* name */
-        FALSE,                 /* partial_inplace */
-        0xffffffff,            /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+#define HOWTO3(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \
+  [C-R_NDS32_RELAX_ENTRY] = HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC)
+
+static reloc_howto_type nds32_elf_relax_howto_table[] = {
+  HOWTO3 (R_NDS32_RELAX_ENTRY, /* 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_RELAX_ENTRY", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_GOT_SUFF,    /* 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_GOT_SUFF",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_GOTOFF_SUFF, /* type  */
+        0,                     /* rightshift  */
+        2,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        32,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_bitfield,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_GOTOFF_SUFF", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_PLT_GOT_SUFF,        /* 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_PLT_GOT_SUFF",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_MULCALL_SUFF,        /* 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_MULCALL_SUFF",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_PTR,         /* 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_PTR",         /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_PTR_COUNT,   /* 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_PTR_COUNT",   /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_PTR_RESOLVED,        /* 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_PTR_RESOLVED",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_PLTBLOCK,    /* 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_PLTBLOCK",    /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_RELAX_REGION_BEGIN,/* 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_RELAX_REGION_BEGIN",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_RELAX_REGION_END,/* 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_RELAX_REGION_END",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_MINUEND,     /* 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_MINUEND",     /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_SUBTRAHEND,  /* 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_SUBTRAHEND",  /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_DIFF8,       /* type  */
+        0,                     /* rightshift  */
+        0,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        8,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_DIFF8",       /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x000000ff,            /* src_mask  */
+        0x000000ff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_DIFF16,      /* type  */
+        0,                     /* rightshift  */
+        1,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        16,                    /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_DIFF16",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0x0000ffff,            /* src_mask  */
+        0x0000ffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_DIFF32,      /* 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_DIFF32",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_DIFF_ULEB128,        /* type  */
+        0,                     /* rightshift  */
+        0,                     /* size (0 = byte, 1 = short, 2 = long)  */
+        0,                     /* bitsize  */
+        FALSE,                 /* pc_relative  */
+        0,                     /* bitpos  */
+        complain_overflow_dont,/* complain_on_overflow  */
+        nds32_elf_ignore_reloc,/* special_function  */
+        "R_NDS32_DIFF_ULEB128",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_DATA,                /* 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_DATA",        /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_TRAN,                /* 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_TRAN",        /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (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  */
+  HOWTO3 (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  */
+  HOWTO3 (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  */
+  /* TLS GD/LD description address base addition.  */
+  HOWTO3 (R_NDS32_TLS_DESC_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_DESC_ADD",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* TLS GD/LD description function load.  */
+  HOWTO3 (R_NDS32_TLS_DESC_FUNC,/* 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_DESC_FUNC",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* TLS DESC resolve function call.  */
+  HOWTO3 (R_NDS32_TLS_DESC_CALL,/* 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_DESC_CALL",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* TLS DESC variable access.  */
+  HOWTO3 (R_NDS32_TLS_DESC_MEM,        /* 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_DESC_MEM",/* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* TLS GD/LD description mark (@tlsdec).  */
+  HOWTO3 (R_NDS32_RELAX_REMOVE,        /* 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_REMOVE",      /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* TLS GD/LD description mark (@tlsdec).  */
+  HOWTO3 (R_NDS32_RELAX_GROUP, /* 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_GROUP",       /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  HOWTO3 (R_NDS32_TLS_IEGP_LW, /* 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_IEGP_LW", /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),                /* pcrel_offset  */
+  /* LA and FLSI relaxation.  */
+  HOWTO3 (R_NDS32_LSI,         /* 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_LSI",         /* name  */
+        FALSE,                 /* partial_inplace  */
+        0xffffffff,            /* src_mask  */
+        0xffffffff,            /* dst_mask  */
+        FALSE),
 };
 
-\f
+static unsigned long dl_tlsdesc_lazy_trampoline[] =
+{
+  0x46200000,                  /* sethi $r2,#0x0      */
+  0x58210000,                  /* ori $r2,$r2,#0x0    */
+  0x40217400,                  /* add $r2,$r2,$gp     */
+  0x04210000,                  /* lwi $r2,[$r2+#0x0]  */
+  0x46300000,                  /* sethi $r3,#0x0      */
+  0x58318000,                  /* ori $r3,$r3,#0x0    */
+  0x4031f400,                  /* add $r3,$r3,$gp     */
+  0x4a000800,                  /* jr $r2              */
+};
+
+static void
+nds32_put_trampoline (void *contents, const unsigned long *template,
+                     unsigned count)
+{
+  unsigned ix;
+
+  for (ix = 0; ix != count; ix++)
+    {
+      unsigned long insn = template[ix];
+      bfd_putb32 (insn, (char *) contents + ix * 4);
+    }
+}
+
 /* nds32_insertion_sort sorts an array with nmemb elements of size size.
    This prototype is the same as qsort ().  */
 
@@ -1967,8 +2525,10 @@ 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;
-  char *tmp = alloca (size);
+  int i, j;
+  char tmp[sizeof (Elf_Internal_Rela)];
+
+  BFD_ASSERT (size <= sizeof (tmp));
 
   /* If i is less than j, i is inserted before j.
 
@@ -1977,14 +2537,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);
@@ -2018,21 +2580,24 @@ compar_reloc (const void *lhs, const void *rhs)
 }
 
 /* Functions listed below are only used for old relocs.
-   * nds32_elf_9_pcrel_reloc
-   * nds32_elf_do_9_pcrel_reloc
-   * nds32_elf_hi20_reloc
-   * nds32_elf_relocate_hi20
-   * nds32_elf_lo12_reloc
-   * nds32_elf_sda15_reloc
-   * nds32_elf_generic_reloc
-   */
+     nds32_elf_9_pcrel_reloc
+     nds32_elf_do_9_pcrel_reloc
+     nds32_elf_hi20_reloc
+     nds32_elf_relocate_hi20
+     nds32_elf_lo12_reloc
+     nds32_elf_sda15_reloc
+     nds32_elf_generic_reloc.  */
 
 /* Handle the R_NDS32_9_PCREL & R_NDS32_9_PCREL_RELA reloc.  */
 
 static bfd_reloc_status_type
-nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
-                        void *data, asection *input_section, bfd *output_bfd,
-                        char **error_message ATTRIBUTE_UNUSED)
+nds32_elf_9_pcrel_reloc (bfd *       abfd,
+                        arelent *   reloc_entry,
+                        asymbol *   symbol,
+                        void *      data,
+                        asection *  input_section,
+                        bfd *       output_bfd,
+                        char **     error_message ATTRIBUTE_UNUSED)
 {
   /* This part is from bfd_elf_generic_reloc.  */
   if (output_bfd != (bfd *) NULL
@@ -2063,10 +2628,14 @@ nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 #define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
 
 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 symbol_value, bfd_vma addend)
+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             symbol_value,
+                           bfd_vma             addend)
 {
   bfd_signed_vma relocation;
   unsigned short x;
@@ -2084,7 +2653,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;
@@ -2127,9 +2696,13 @@ struct nds32_hi20
 static struct nds32_hi20 *nds32_hi20_list;
 
 static bfd_reloc_status_type
-nds32_elf_hi20_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
-                     asymbol *symbol, void *data, asection *input_section,
-                     bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
+nds32_elf_hi20_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+                     arelent *reloc_entry,
+                     asymbol *symbol,
+                     void *data,
+                     asection *input_section,
+                     bfd *output_bfd,
+                     char **error_message ATTRIBUTE_UNUSED)
 {
   bfd_reloc_status_type ret;
   bfd_vma relocation;
@@ -2182,8 +2755,10 @@ nds32_elf_hi20_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
 
 static void
 nds32_elf_relocate_hi20 (bfd *input_bfd ATTRIBUTE_UNUSED,
-                        int type ATTRIBUTE_UNUSED, Elf_Internal_Rela *relhi,
-                        Elf_Internal_Rela *rello, bfd_byte *contents,
+                        int type ATTRIBUTE_UNUSED,
+                        Elf_Internal_Rela *relhi,
+                        Elf_Internal_Rela *rello,
+                        bfd_byte *contents,
                         bfd_vma addend)
 {
   unsigned long insn;
@@ -2450,14 +3025,15 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NONE, R_NDS32_NONE},
   {BFD_RELOC_16, R_NDS32_16_RELA},
   {BFD_RELOC_32, R_NDS32_32_RELA},
+  {BFD_RELOC_VTABLE_INHERIT, R_NDS32_RELA_GNU_VTINHERIT},
+  {BFD_RELOC_VTABLE_ENTRY, R_NDS32_RELA_GNU_VTENTRY},
+
   {BFD_RELOC_NDS32_20, R_NDS32_20_RELA},
-  {BFD_RELOC_NDS32_5, R_NDS32_5_RELA},
   {BFD_RELOC_NDS32_9_PCREL, R_NDS32_9_PCREL_RELA},
   {BFD_RELOC_NDS32_WORD_9_PCREL, R_NDS32_WORD_9_PCREL_RELA},
   {BFD_RELOC_NDS32_15_PCREL, R_NDS32_15_PCREL_RELA},
   {BFD_RELOC_NDS32_17_PCREL, R_NDS32_17_PCREL_RELA},
   {BFD_RELOC_NDS32_25_PCREL, R_NDS32_25_PCREL_RELA},
-  {BFD_RELOC_NDS32_10_UPCREL, R_NDS32_10_UPCREL_RELA},
   {BFD_RELOC_NDS32_HI20, R_NDS32_HI20_RELA},
   {BFD_RELOC_NDS32_LO12S3, R_NDS32_LO12S3_RELA},
   {BFD_RELOC_NDS32_LO12S2, R_NDS32_LO12S2_RELA},
@@ -2468,9 +3044,10 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_SDA15S2, R_NDS32_SDA15S2_RELA},
   {BFD_RELOC_NDS32_SDA15S1, R_NDS32_SDA15S1_RELA},
   {BFD_RELOC_NDS32_SDA15S0, R_NDS32_SDA15S0_RELA},
-  {BFD_RELOC_VTABLE_INHERIT, R_NDS32_RELA_GNU_VTINHERIT},
-  {BFD_RELOC_VTABLE_ENTRY, R_NDS32_RELA_GNU_VTENTRY},
-
+  {BFD_RELOC_NDS32_SDA16S3, R_NDS32_SDA16S3_RELA},
+  {BFD_RELOC_NDS32_SDA17S2, R_NDS32_SDA17S2_RELA},
+  {BFD_RELOC_NDS32_SDA18S1, R_NDS32_SDA18S1_RELA},
+  {BFD_RELOC_NDS32_SDA19S0, R_NDS32_SDA19S0_RELA},
   {BFD_RELOC_NDS32_GOT20, R_NDS32_GOT20},
   {BFD_RELOC_NDS32_9_PLTREL, R_NDS32_9_PLTREL},
   {BFD_RELOC_NDS32_25_PLTREL, R_NDS32_25_PLTREL},
@@ -2479,17 +3056,13 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_JMP_SLOT, R_NDS32_JMP_SLOT},
   {BFD_RELOC_NDS32_RELATIVE, R_NDS32_RELATIVE},
   {BFD_RELOC_NDS32_GOTOFF, R_NDS32_GOTOFF},
+  {BFD_RELOC_NDS32_GOTOFF_HI20, R_NDS32_GOTOFF_HI20},
+  {BFD_RELOC_NDS32_GOTOFF_LO12, R_NDS32_GOTOFF_LO12},
   {BFD_RELOC_NDS32_GOTPC20, R_NDS32_GOTPC20},
   {BFD_RELOC_NDS32_GOT_HI20, R_NDS32_GOT_HI20},
   {BFD_RELOC_NDS32_GOT_LO12, R_NDS32_GOT_LO12},
-  {BFD_RELOC_NDS32_GOT_LO15, R_NDS32_GOT_LO15},
-  {BFD_RELOC_NDS32_GOT_LO19, R_NDS32_GOT_LO19},
   {BFD_RELOC_NDS32_GOTPC_HI20, R_NDS32_GOTPC_HI20},
   {BFD_RELOC_NDS32_GOTPC_LO12, R_NDS32_GOTPC_LO12},
-  {BFD_RELOC_NDS32_GOTOFF_HI20, R_NDS32_GOTOFF_HI20},
-  {BFD_RELOC_NDS32_GOTOFF_LO12, R_NDS32_GOTOFF_LO12},
-  {BFD_RELOC_NDS32_GOTOFF_LO15, R_NDS32_GOTOFF_LO15},
-  {BFD_RELOC_NDS32_GOTOFF_LO19, R_NDS32_GOTOFF_LO19},
   {BFD_RELOC_NDS32_INSN16, R_NDS32_INSN16},
   {BFD_RELOC_NDS32_LABEL, R_NDS32_LABEL},
   {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1},
@@ -2503,51 +3076,90 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA},
   {BFD_RELOC_NDS32_17_FIXED, R_NDS32_17_FIXED_RELA},
   {BFD_RELOC_NDS32_25_FIXED, R_NDS32_25_FIXED_RELA},
+  {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4},
+  {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5},
+  {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6},
+  {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_PLTREL_HI20, R_NDS32_PLTREL_HI20},
   {BFD_RELOC_NDS32_PLTREL_LO12, R_NDS32_PLTREL_LO12},
   {BFD_RELOC_NDS32_PLT_GOTREL_HI20, R_NDS32_PLT_GOTREL_HI20},
   {BFD_RELOC_NDS32_PLT_GOTREL_LO12, R_NDS32_PLT_GOTREL_LO12},
-  {BFD_RELOC_NDS32_PLT_GOTREL_LO15, R_NDS32_PLT_GOTREL_LO15},
-  {BFD_RELOC_NDS32_PLT_GOTREL_LO19, R_NDS32_PLT_GOTREL_LO19},
-  {BFD_RELOC_NDS32_PLT_GOTREL_LO20, R_NDS32_PLT_GOTREL_LO20},
   {BFD_RELOC_NDS32_SDA12S2_DP, R_NDS32_SDA12S2_DP_RELA},
   {BFD_RELOC_NDS32_SDA12S2_SP, R_NDS32_SDA12S2_SP_RELA},
   {BFD_RELOC_NDS32_LO12S2_DP, R_NDS32_LO12S2_DP_RELA},
   {BFD_RELOC_NDS32_LO12S2_SP, R_NDS32_LO12S2_SP_RELA},
-  {BFD_RELOC_NDS32_SDA16S3, R_NDS32_SDA16S3_RELA},
-  {BFD_RELOC_NDS32_SDA17S2, R_NDS32_SDA17S2_RELA},
-  {BFD_RELOC_NDS32_SDA18S1, R_NDS32_SDA18S1_RELA},
-  {BFD_RELOC_NDS32_SDA19S0, R_NDS32_SDA19S0_RELA},
-  {BFD_RELOC_NDS32_SDA_FP7U2_RELA, R_NDS32_SDA_FP7U2_RELA},
   {BFD_RELOC_NDS32_DWARF2_OP1, R_NDS32_DWARF2_OP1_RELA},
   {BFD_RELOC_NDS32_DWARF2_OP2, R_NDS32_DWARF2_OP2_RELA},
   {BFD_RELOC_NDS32_DWARF2_LEB, R_NDS32_DWARF2_LEB_RELA},
   {BFD_RELOC_NDS32_UPDATE_TA, R_NDS32_UPDATE_TA_RELA},
-  {BFD_RELOC_NDS32_GOT_SUFF, R_NDS32_GOT_SUFF},
-  {BFD_RELOC_NDS32_GOTOFF_SUFF, R_NDS32_GOTOFF_SUFF},
+  {BFD_RELOC_NDS32_PLT_GOTREL_LO20, R_NDS32_PLT_GOTREL_LO20},
+  {BFD_RELOC_NDS32_PLT_GOTREL_LO15, R_NDS32_PLT_GOTREL_LO15},
+  {BFD_RELOC_NDS32_PLT_GOTREL_LO19, R_NDS32_PLT_GOTREL_LO19},
+  {BFD_RELOC_NDS32_GOT_LO15, R_NDS32_GOT_LO15},
+  {BFD_RELOC_NDS32_GOT_LO19, R_NDS32_GOT_LO19},
+  {BFD_RELOC_NDS32_GOTOFF_LO15, R_NDS32_GOTOFF_LO15},
+  {BFD_RELOC_NDS32_GOTOFF_LO19, R_NDS32_GOTOFF_LO19},
   {BFD_RELOC_NDS32_GOT15S2, R_NDS32_GOT15S2_RELA},
   {BFD_RELOC_NDS32_GOT17S2, R_NDS32_GOT17S2_RELA},
+  {BFD_RELOC_NDS32_5, R_NDS32_5_RELA},
+  {BFD_RELOC_NDS32_10_UPCREL, R_NDS32_10_UPCREL_RELA},
+  {BFD_RELOC_NDS32_SDA_FP7U2_RELA, R_NDS32_SDA_FP7U2_RELA},
+  {BFD_RELOC_NDS32_RELAX_ENTRY, R_NDS32_RELAX_ENTRY},
+  {BFD_RELOC_NDS32_GOT_SUFF, R_NDS32_GOT_SUFF},
+  {BFD_RELOC_NDS32_GOTOFF_SUFF, R_NDS32_GOTOFF_SUFF},
+  {BFD_RELOC_NDS32_PLT_GOT_SUFF, R_NDS32_PLT_GOT_SUFF},
+  {BFD_RELOC_NDS32_MULCALL_SUFF, R_NDS32_MULCALL_SUFF},
   {BFD_RELOC_NDS32_PTR, R_NDS32_PTR},
   {BFD_RELOC_NDS32_PTR_COUNT, R_NDS32_PTR_COUNT},
-  {BFD_RELOC_NDS32_PLT_GOT_SUFF, R_NDS32_PLT_GOT_SUFF},
   {BFD_RELOC_NDS32_PTR_RESOLVED, R_NDS32_PTR_RESOLVED},
-  {BFD_RELOC_NDS32_RELAX_ENTRY, R_NDS32_RELAX_ENTRY},
-  {BFD_RELOC_NDS32_MULCALL_SUFF, R_NDS32_MULCALL_SUFF},
   {BFD_RELOC_NDS32_PLTBLOCK, R_NDS32_PLTBLOCK},
   {BFD_RELOC_NDS32_RELAX_REGION_BEGIN, R_NDS32_RELAX_REGION_BEGIN},
   {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_DIFF8, R_NDS32_DIFF8},
   {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16},
   {BFD_RELOC_NDS32_DIFF32, R_NDS32_DIFF32},
   {BFD_RELOC_NDS32_DIFF_ULEB128, R_NDS32_DIFF_ULEB128},
+  {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY},
   {BFD_RELOC_NDS32_25_ABS, R_NDS32_25_ABS_RELA},
   {BFD_RELOC_NDS32_DATA, R_NDS32_DATA},
   {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},
+  /* Not sure.  */
+  {BFD_RELOC_NDS32_TPOFF, R_NDS32_TLS_TPOFF},
+  /* Missing: BFD_RELOC_NDS32_GOTTPOFF.  */
+  {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_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},
+  {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_LO12, R_NDS32_TLS_IE_LO12},
+  {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2},
+  {BFD_RELOC_NDS32_TLS_IEGP_HI20, R_NDS32_TLS_IEGP_HI20},
+  {BFD_RELOC_NDS32_TLS_IEGP_LO12, R_NDS32_TLS_IEGP_LO12},
+  {BFD_RELOC_NDS32_TLS_IEGP_LO12S2, R_NDS32_TLS_IEGP_LO12S2},
+  {BFD_RELOC_NDS32_TLS_IEGP_LW, R_NDS32_TLS_IEGP_LW},
+  {BFD_RELOC_NDS32_TLS_DESC, R_NDS32_TLS_DESC},
+  {BFD_RELOC_NDS32_TLS_DESC_HI20, R_NDS32_TLS_DESC_HI20},
+  {BFD_RELOC_NDS32_TLS_DESC_LO12, R_NDS32_TLS_DESC_LO12},
+  {BFD_RELOC_NDS32_TLS_DESC_20, R_NDS32_TLS_DESC_20},
+  {BFD_RELOC_NDS32_TLS_DESC_SDA17S2, R_NDS32_TLS_DESC_SDA17S2},
+  {BFD_RELOC_NDS32_TLS_DESC_ADD, R_NDS32_TLS_DESC_ADD},
+  {BFD_RELOC_NDS32_TLS_DESC_FUNC, R_NDS32_TLS_DESC_FUNC},
+  {BFD_RELOC_NDS32_TLS_DESC_CALL, R_NDS32_TLS_DESC_CALL},
+  {BFD_RELOC_NDS32_TLS_DESC_MEM, R_NDS32_TLS_DESC_MEM},
+  {BFD_RELOC_NDS32_REMOVE, R_NDS32_RELAX_REMOVE},
+  {BFD_RELOC_NDS32_GROUP, R_NDS32_RELAX_GROUP},
+  {BFD_RELOC_NDS32_LSI, R_NDS32_LSI},
 };
 
 /* Patch tag.  */
@@ -2581,6 +3193,13 @@ bfd_elf32_bfd_reloc_type_table_lookup (enum elf_nds32_reloc_type code)
     }
   else
     {
+      if ((size_t) (code - R_NDS32_RELAX_ENTRY)
+         >= ARRAY_SIZE (nds32_elf_relax_howto_table))
+       {
+         int i = code;
+         i += 1;
+       }
+
       BFD_ASSERT ((size_t) (code - R_NDS32_RELAX_ENTRY)
                  < ARRAY_SIZE (nds32_elf_relax_howto_table));
       return &nds32_elf_relax_howto_table[code - R_NDS32_RELAX_ENTRY];
@@ -2597,7 +3216,7 @@ bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     {
       if (nds32_reloc_map[i].bfd_reloc_val == code)
        return bfd_elf32_bfd_reloc_type_table_lookup
-                (nds32_reloc_map[i].elf_reloc_val);
+         (nds32_reloc_map[i].elf_reloc_val);
     }
 
   return NULL;
@@ -2605,25 +3224,45 @@ bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 
 /* Set the howto pointer for an NDS32 ELF reloc.  */
 
-static void
-nds32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+static bfd_boolean
+nds32_info_to_howto_rel (bfd *abfd, arelent *cache_ptr,
                         Elf_Internal_Rela *dst)
 {
   enum elf_nds32_reloc_type r_type;
 
   r_type = ELF32_R_TYPE (dst->r_info);
+  if (r_type > R_NDS32_GNU_VTENTRY)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                         abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
   BFD_ASSERT (ELF32_R_TYPE (dst->r_info) <= R_NDS32_GNU_VTENTRY);
   cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type);
+  return TRUE;
 }
 
-static void
+static bfd_boolean
 nds32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
                     Elf_Internal_Rela *dst)
 {
-  BFD_ASSERT ((ELF32_R_TYPE (dst->r_info) == R_NDS32_NONE)
-             || ((ELF32_R_TYPE (dst->r_info) > R_NDS32_GNU_VTENTRY)
-                 && (ELF32_R_TYPE (dst->r_info) < R_NDS32_max)));
-  cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (dst->r_info));
+  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+
+  if ((r_type == R_NDS32_NONE)
+      || ((r_type > R_NDS32_GNU_VTENTRY)
+         && (r_type < R_NDS32_max)))
+    {
+      cache_ptr->howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type);
+      return TRUE;
+    }
+
+  /* xgettext:c-format */
+  _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type);
+  bfd_set_error (bfd_error_bad_value);
+  return FALSE;
 }
 
 /* Support for core dump NOTE sections.
@@ -2638,7 +3277,7 @@ nds32_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   switch (note->descsz)
     {
     case 0x114:
-      /* Linux/NDS32 32-bit, ABI1 */
+      /* Linux/NDS32 32-bit, ABI1 */
 
       /* pr_cursig */
       elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
@@ -2652,7 +3291,7 @@ nds32_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
       break;
 
     case 0xfc:
-      /* Linux/NDS32 32-bit */
+      /* Linux/NDS32 32-bit */
 
       /* pr_cursig */
       elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
@@ -2680,13 +3319,14 @@ nds32_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   switch (note->descsz)
     {
     case 124:
-      /* Linux/NDS32 */
+      /* Linux/NDS32 */
 
       /* __kernel_uid_t, __kernel_gid_t are short on NDS32 platform.  */
       elf_tdata (abfd)->core->program =
        _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
       elf_tdata (abfd)->core->command =
        _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+      break;
 
     default:
       return FALSE;
@@ -2756,7 +3396,6 @@ nds32_elf_add_symbol_hook (bfd *abfd,
   return TRUE;
 }
 
-
 /* This function can figure out the best location for a base register to access
    data relative to this base register
    INPUT:
@@ -2802,28 +3441,32 @@ 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,
-                         bfd_vma *psb, bfd_boolean add_symbol)
+nds32_elf_final_sda_base (bfd *                   output_bfd,
+                         struct bfd_link_info *  info,
+                         bfd_vma *               psb,
+                         bfd_boolean             add_symbol)
 {
   int relax_fp_as_gp;
   struct elf_nds32_link_hash_table *table;
   struct bfd_link_hash_entry *h, *h2;
+  long unsigned int total = 0;
+  asection *first = NULL, *final = NULL, *temp;
+  bfd_vma sda_base = 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))
+  if (!h || (h->type != bfd_link_hash_defined
+            && h->type != bfd_link_hash_defweak))
     {
-      asection *first = NULL, *final = NULL, *temp;
-      bfd_vma sda_base;
       /* The first section must be 4-byte aligned to promise _SDA_BASE_ being
         4 byte-aligned.  Therefore, it has to set the first section ".data"
         4 byte-aligned.  */
       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 +3477,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 < ARRAY_SIZE (sec_name))
        {
          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 < ARRAY_SIZE (sec_name))
            {
              final = bfd_get_section_by_name (output_bfd, sec_name[i]);
              if (final && (final->size != 0 || final->rawsize != 0)
@@ -2866,48 +3534,84 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
        }
       else
        {
-         /* There is not any data section in output bfd, and set _SDA_BASE_ in
-            first output section.  */
-         first = output_bfd->sections;
-         while (first && first->size == 0 && first->rawsize == 0)
-           first = first->next;
+         /* If there is not any default data section in output bfd, try to find
+            the first data section.  If no data section be found, just simplily
+            choose the first output section.  */
+         temp = output_bfd->sections;
+         while (temp)
+           {
+             if (temp->flags & SEC_ALLOC
+                 && (((temp->flags & SEC_DATA)
+                      && ((temp->flags & SEC_READONLY) == 0))
+                     || (temp->flags & SEC_LOAD) == 0)
+                 && (temp->size != 0 || temp->rawsize != 0))
+               {
+                 if (!first)
+                   first = temp;
+                 final = temp;
+               }
+             temp = temp->next;
+           }
+
+         /* There is no data or bss section.  */
+         if (!first || (first->size == 0 && first->rawsize == 0))
+           {
+             first = output_bfd->sections;
+             while (first && first->size == 0 && first->rawsize == 0)
+               first = first->next;
+           }
+
+         /* There is no concrete section.  */
          if (!first)
            {
              *psb = elf_gp (output_bfd);
              return bfd_reloc_ok;
            }
-         sda_base = first->vma;
+
+         if (final && (final->vma + final->rawsize - first->vma) <= 0x4000)
+           sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2;
+         else
+           sda_base = first->vma + 0x2000;
        }
 
       sda_base -= first->vma;
       sda_base = sda_base & (~7);
 
       if (!_bfd_generic_link_add_one_symbol
-            (info, output_bfd, "_SDA_BASE_", BSF_GLOBAL | BSF_WEAK, first,
-             (bfd_vma) sda_base, (const char *) NULL, FALSE,
-             get_elf_backend_data (output_bfd)->collect, &h))
+         (info, output_bfd, "_SDA_BASE_", BSF_GLOBAL | BSF_WEAK, first,
+          (bfd_vma) sda_base, (const char *) NULL, FALSE,
+          get_elf_backend_data (output_bfd)->collect, &h))
        return FALSE;
 
       sda_rela_sec = first;
+    }
 
-      table = nds32_elf_hash_table (info);
-      relax_fp_as_gp = table->relax_fp_as_gp;
-      if (relax_fp_as_gp)
-       {
-         h2 = bfd_link_hash_lookup (info->hash, FP_BASE_NAME,
-                                    FALSE, FALSE, FALSE);
-         /* Define a weak FP_BASE_NAME here to prevent the undefined symbol.
-            And set FP equal to SDA_BASE to do relaxation for
-            la $fp, _FP_BASE_.  */
-         if (!_bfd_generic_link_add_one_symbol
-                (info, output_bfd, FP_BASE_NAME, BSF_GLOBAL | BSF_WEAK,
-                 first, (bfd_vma) sda_base, (const char *) NULL,
-                 FALSE, get_elf_backend_data (output_bfd)->collect, &h2))
-           return FALSE;
-       }
+  /* Set _FP_BASE_ to _SDA_BASE_.  */
+  table = nds32_elf_hash_table (info);
+  relax_fp_as_gp = table->relax_fp_as_gp;
+  h2 = bfd_link_hash_lookup (info->hash, FP_BASE_NAME, FALSE, FALSE, FALSE);
+  /* _SDA_BASE_ is difined in linker script.  */
+  if (!first)
+    {
+      first = h->u.def.section;
+      sda_base = h->u.def.value;
+    }
+
+  if (relax_fp_as_gp && h2
+      && (h2->type == bfd_link_hash_undefweak
+         || h2->type == bfd_link_hash_undefined))
+    {
+      /* Define a weak FP_BASE_NAME here to prevent the undefined symbol.
+        And set FP equal to SDA_BASE to do relaxation for
+        la $fp, _FP_BASE_.  */
+      if (!_bfd_generic_link_add_one_symbol
+         (info, output_bfd, FP_BASE_NAME, BSF_GLOBAL | BSF_WEAK,
+          first, sda_base, (const char *) NULL,
+          FALSE, get_elf_backend_data (output_bfd)->collect, &h2))
+       return FALSE;
     }
 
-  if (add_symbol == TRUE)
+  if (add_symbol)
     {
       if (h)
        {
@@ -2918,13 +3622,14 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
        }
       else
        {
-         (*_bfd_error_handler) (_("error: Can't find symbol: _SDA_BASE_."));
+         _bfd_error_handler (_("error: can't find symbol: %s"), "_SDA_BASE_");
          return bfd_reloc_dangerous;
        }
     }
 
-  *psb = h->u.def.value + h->u.def.section->output_section->vma
-        + h->u.def.section->output_offset;
+  *psb = h->u.def.value
+    + h->u.def.section->output_section->vma
+    + h->u.def.section->output_offset;
   return bfd_reloc_ok;
 }
 \f
@@ -2932,7 +3637,6 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
 /* Return size of a PLT entry.  */
 #define elf_nds32_sizeof_plt(info) PLT_ENTRY_SIZE
 
-
 /* Create an entry in an nds32 ELF linker hash table.  */
 
 static struct bfd_hash_entry *
@@ -2962,7 +3666,8 @@ nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       struct elf_nds32_link_hash_entry *eh;
 
       eh = (struct elf_nds32_link_hash_entry *) ret;
-      eh->dyn_relocs = NULL;
+      eh->tls_type = GOT_UNKNOWN;
+      eh->offset_to_gp = 0;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -2975,13 +3680,13 @@ nds32_elf_link_hash_table_create (bfd *abfd)
 {
   struct elf_nds32_link_hash_table *ret;
 
-  bfd_size_type amt = sizeof (struct elf_nds32_link_hash_table);
+  size_t amt = sizeof (struct elf_nds32_link_hash_table);
 
   ret = (struct elf_nds32_link_hash_table *) bfd_zmalloc (amt);
   if (ret == NULL)
     return NULL;
 
-  /* patch tag.  */
+  /* Patch tag.  */
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
                                      nds32_elf_link_hash_newfunc,
                                      sizeof (struct elf_nds32_link_hash_entry),
@@ -2991,16 +3696,9 @@ nds32_elf_link_hash_table_create (bfd *abfd)
       return NULL;
     }
 
-  ret->sgot = NULL;
-  ret->sgotplt = NULL;
-  ret->srelgot = NULL;
-  ret->splt = NULL;
-  ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
   ret->sym_ld_script = NULL;
-  ret->ex9_export_file = NULL;
-  ret->ex9_import_file = NULL;
 
   return &ret->root.root;
 }
@@ -3011,25 +3709,25 @@ nds32_elf_link_hash_table_create (bfd *abfd)
 static bfd_boolean
 create_got_section (bfd *dynobj, struct bfd_link_info *info)
 {
-  struct elf_nds32_link_hash_table *htab;
+  struct elf_link_hash_table *ehtab;
 
   if (!_bfd_elf_create_got_section (dynobj, info))
     return FALSE;
 
-  htab = nds32_elf_hash_table (info);
-  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
-  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
-  if (!htab->sgot || !htab->sgotplt)
+  ehtab = elf_hash_table (info);
+  ehtab->sgot = bfd_get_section_by_name (dynobj, ".got");
+  ehtab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+  if (!ehtab->sgot || !ehtab->sgotplt)
     abort ();
 
   /* _bfd_elf_create_got_section will create it for us.  */
-  htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-  if (htab->srelgot == NULL
-      || !bfd_set_section_flags (dynobj, htab->srelgot,
+  ehtab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  if (ehtab->srelgot == NULL
+      || !bfd_set_section_flags (ehtab->srelgot,
                                 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
                                  | SEC_IN_MEMORY | SEC_LINKER_CREATED
                                  | SEC_READONLY))
-      || !bfd_set_section_alignment (dynobj, htab->srelgot, 2))
+      || !bfd_set_section_alignment (ehtab->srelgot, 2))
     return FALSE;
 
   return TRUE;
@@ -3040,14 +3738,19 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
 static bfd_boolean
 nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
+  struct elf_link_hash_table *ehtab;
   struct elf_nds32_link_hash_table *htab;
   flagword flags, pltflags;
   register asection *s;
   const struct elf_backend_data *bed;
   int ptralign = 2;            /* 32-bit  */
+  const char *secname;
+  char *relname;
+  flagword secflags;
+  asection *sec;
 
   bed = get_elf_backend_data (abfd);
-
+  ehtab = elf_hash_table (info);
   htab = nds32_elf_hash_table (info);
 
   /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
@@ -3064,10 +3767,10 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
     pltflags |= SEC_READONLY;
 
   s = bfd_make_section (abfd, ".plt");
-  htab->splt = s;
+  ehtab->splt = s;
   if (s == NULL
-      || !bfd_set_section_flags (abfd, s, pltflags)
-      || !bfd_set_section_alignment (abfd, s, bed->plt_alignment))
+      || !bfd_set_section_flags (s, pltflags)
+      || !bfd_set_section_alignment (s, bed->plt_alignment))
     return FALSE;
 
   if (bed->want_plt_sym)
@@ -3087,46 +3790,39 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       h->def_regular = 1;
       h->type = STT_OBJECT;
 
-      if (info->shared && !bfd_elf_link_record_dynamic_symbol (info, h))
+      if (bfd_link_pic (info) && !bfd_elf_link_record_dynamic_symbol (info, h))
        return FALSE;
     }
 
   s = bfd_make_section (abfd,
                        bed->default_use_rela_p ? ".rela.plt" : ".rel.plt");
-  htab->srelplt = s;
+  ehtab->srelplt = s;
   if (s == NULL
-      || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
-      || !bfd_set_section_alignment (abfd, s, ptralign))
+      || !bfd_set_section_flags (s, flags | SEC_READONLY)
+      || !bfd_set_section_alignment (s, ptralign))
     return FALSE;
 
-  if (htab->sgot == NULL && !create_got_section (abfd, info))
+  if (ehtab->sgot == NULL && !create_got_section (abfd, info))
     return FALSE;
 
-  {
-    const char *secname;
-    char *relname;
-    flagword secflags;
-    asection *sec;
-
-    for (sec = abfd->sections; sec; sec = sec->next)
-      {
-       secflags = bfd_get_section_flags (abfd, sec);
-       if ((secflags & (SEC_DATA | SEC_LINKER_CREATED))
-           || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS))
-         continue;
-       secname = bfd_get_section_name (abfd, sec);
-       relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6);
-       strcpy (relname, ".rela");
-       strcat (relname, secname);
-       if (bfd_get_section_by_name (abfd, secname))
-         continue;
-       s = bfd_make_section (abfd, relname);
-       if (s == NULL
-           || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
-           || !bfd_set_section_alignment (abfd, s, ptralign))
-         return FALSE;
-      }
-  }
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      secflags = bfd_section_flags (sec);
+      if ((secflags & (SEC_DATA | SEC_LINKER_CREATED))
+         || ((secflags & SEC_HAS_CONTENTS) != SEC_HAS_CONTENTS))
+       continue;
+      secname = bfd_section_name (sec);
+      relname = (char *) bfd_malloc ((bfd_size_type) strlen (secname) + 6);
+      strcpy (relname, ".rela");
+      strcat (relname, secname);
+      if (bfd_get_section_by_name (abfd, secname))
+       continue;
+      s = bfd_make_section (abfd, relname);
+      if (s == NULL
+         || !bfd_set_section_flags (s, flags | SEC_READONLY)
+         || !bfd_set_section_alignment (s, ptralign))
+       return FALSE;
+    }
 
   if (bed->want_dynbss)
     {
@@ -3139,7 +3835,7 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       s = bfd_make_section (abfd, ".dynbss");
       htab->sdynbss = s;
       if (s == NULL
-         || !bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED))
+         || !bfd_set_section_flags (s, SEC_ALLOC | SEC_LINKER_CREATED))
        return FALSE;
       /* The .rel[a].bss section holds copy relocs.  This section is not
         normally needed.  We need to create it here, though, so that the
@@ -3152,14 +3848,14 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
         be needed, we can discard it later.  We will never need this
         section when generating a shared object, since they do not use
         copy relocs.  */
-      if (!info->shared)
+      if (!bfd_link_pic (info))
        {
          s = bfd_make_section (abfd, (bed->default_use_rela_p
                                       ? ".rela.bss" : ".rel.bss"));
          htab->srelbss = s;
          if (s == NULL
-             || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
-             || !bfd_set_section_alignment (abfd, s, ptralign))
+             || !bfd_set_section_flags (s, flags | SEC_READONLY)
+             || !bfd_set_section_alignment (s, ptralign))
            return FALSE;
        }
     }
@@ -3178,44 +3874,18 @@ nds32_elf_copy_indirect_symbol (struct bfd_link_info *info,
   edir = (struct elf_nds32_link_hash_entry *) dir;
   eind = (struct elf_nds32_link_hash_entry *) ind;
 
-  if (eind->dyn_relocs != NULL)
+  if (ind->root.type == bfd_link_hash_indirect)
     {
-      if (edir->dyn_relocs != NULL)
+      if (dir->got.refcount <= 0)
        {
-         struct elf_nds32_dyn_relocs **pp;
-         struct elf_nds32_dyn_relocs *p;
-
-         if (ind->root.type == bfd_link_hash_indirect)
-           abort ();
-
-         /* Add reloc counts against the weak sym to the strong sym
-            list.  Merge any entries against the same section.  */
-         for (pp = &eind->dyn_relocs; (p = *pp) != NULL;)
-           {
-             struct elf_nds32_dyn_relocs *q;
-
-             for (q = edir->dyn_relocs; q != NULL; q = q->next)
-               if (q->sec == p->sec)
-                 {
-                   q->pc_count += p->pc_count;
-                   q->count += p->count;
-                   *pp = p->next;
-                   break;
-                 }
-             if (q == NULL)
-               pp = &p->next;
-           }
-         *pp = edir->dyn_relocs;
+         edir->tls_type = eind->tls_type;
+         eind->tls_type = GOT_UNKNOWN;
        }
-
-      edir->dyn_relocs = eind->dyn_relocs;
-      eind->dyn_relocs = NULL;
     }
 
   _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 \f
-
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -3227,8 +3897,6 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h)
 {
   struct elf_nds32_link_hash_table *htab;
-  struct elf_nds32_link_hash_entry *eh;
-  struct elf_nds32_dyn_relocs *p;
   bfd *dynobj;
   asection *s;
   unsigned int power_of_two;
@@ -3238,7 +3906,7 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* Make sure we know what is going on here.  */
   BFD_ASSERT (dynobj != NULL
              && (h->needs_plt
-                 || h->u.weakdef != NULL
+                 || h->is_weakalias
                  || (h->def_dynamic && h->ref_regular && !h->def_regular)));
 
 
@@ -3247,7 +3915,7 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      when we know the address of the .got section.  */
   if (h->type == STT_FUNC || h->needs_plt)
     {
-      if (!info->shared
+      if (!bfd_link_pic (info)
          && !h->def_dynamic
          && !h->ref_dynamic
          && h->root.type != bfd_link_hash_undefweak
@@ -3270,12 +3938,12 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
+  if (h->is_weakalias)
     {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      struct elf_link_hash_entry *def = weakdef (h);
+      BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+      h->root.u.def.section = def->root.u.def.section;
+      h->root.u.def.value = def->root.u.def.value;
       return TRUE;
     }
 
@@ -3286,7 +3954,7 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (info->shared)
+  if (bfd_link_pic (info))
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -3295,24 +3963,15 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     return TRUE;
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
-  if (info->nocopyreloc)
+  if (0 && info->nocopyreloc)
     {
       h->non_got_ref = 0;
       return TRUE;
     }
 
-  eh = (struct elf_nds32_link_hash_entry *) h;
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      s = p->sec->output_section;
-      if (s != NULL && (s->flags & (SEC_READONLY | SEC_HAS_CONTENTS)) != 0)
-       break;
-    }
-
-  /* If we didn't find any dynamic relocs in sections which needs the
-     copy reloc, then we'll be keeping the dynamic relocs and avoiding
-     the copy reloc.  */
-  if (p == NULL)
+  /* If we don't find any dynamic relocs in read-only sections, then
+     we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
+  if (!_bfd_elf_readonly_dynrelocs (h))
     {
       h->non_got_ref = 0;
       return TRUE;
@@ -3354,9 +4013,9 @@ nds32_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   /* Apply the required alignment.  */
   s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (dynobj, s))
+  if (power_of_two > bfd_section_alignment (s))
     {
-      if (!bfd_set_section_alignment (dynobj, s, power_of_two))
+      if (!bfd_set_section_alignment (s, power_of_two))
        return FALSE;
     }
 
@@ -3377,25 +4036,28 @@ static bfd_boolean
 allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
+  struct elf_link_hash_table *ehtab;
   struct elf_nds32_link_hash_table *htab;
-  struct elf_nds32_link_hash_entry *eh;
-  struct elf_nds32_dyn_relocs *p;
+  struct elf_dyn_relocs *p;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  /* When warning symbols are created, they **replace** the "real"
+     entry in the hash table, thus we never get to see the real
+     symbol in a hash traversal. So look at it now.  */
   if (h->root.type == bfd_link_hash_warning)
-    /* When warning symbols are created, they **replace** the "real"
-       entry in the hash table, thus we never get to see the real
-       symbol in a hash traversal.  So look at it now.  */
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
   info = (struct bfd_link_info *) inf;
+  ehtab = elf_hash_table (info);
   htab = nds32_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
-  eh = (struct elf_nds32_link_hash_entry *) h;
-
-  if (htab->root.dynamic_sections_created && h->plt.refcount > 0)
+  if ((htab->root.dynamic_sections_created || h->type == STT_GNU_IFUNC)
+      && h->plt.refcount > 0
+      && !(bfd_link_pie (info) && h->def_regular))
     {
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -3405,9 +4067,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            return FALSE;
        }
 
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
        {
-         asection *s = htab->splt;
+         asection *s = ehtab->splt;
 
          /* If this is the first .plt entry, make room for the special
             first entry.  */
@@ -3421,7 +4083,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             location in the .plt.  This is required to make function
             pointers compare as equal between the normal executable and
             the shared library.  */
-         if (!info->shared && !h->def_regular)
+         if (!bfd_link_pic (info) && !h->def_regular)
            {
              h->root.u.def.section = s;
              h->root.u.def.value = h->plt.offset;
@@ -3432,10 +4094,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
          /* We also need to make an entry in the .got.plt section, which
             will be placed in the .got section by the linker script.  */
-         htab->sgotplt->size += 4;
+         ehtab->sgotplt->size += 4;
 
          /* We also need to make an entry in the .rel.plt section.  */
-         htab->srelplt->size += sizeof (Elf32_External_Rela);
+         ehtab->srelplt->size += sizeof (Elf32_External_Rela);
+         if (htab->tls_desc_trampoline)
+           htab->next_tls_desc_index++;
        }
       else
        {
@@ -3451,8 +4115,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
   if (h->got.refcount > 0)
     {
-      asection *s;
+      asection *sgot;
       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.  */
@@ -3462,18 +4127,46 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            return FALSE;
        }
 
-      s = htab->sgot;
+      sgot = elf_hash_table (info)->sgot;
+      h->got.offset = sgot->size;
+
+      if (tls_type == GOT_UNKNOWN)
+       abort ();
+
+      /* Non-TLS symbols, and TLS_IE need one GOT slot.  */
+      if (tls_type & (GOT_NORMAL | GOT_TLS_IE | GOT_TLS_IEGP))
+       sgot->size += 4;
+      else
+       {
+         /* TLS_DESC, TLS_GD, and TLS_LD need 2 consecutive GOT slots.  */
+         if (tls_type & GOT_TLS_DESC)
+           sgot->size += 8;
+       }
 
-      h->got.offset = s->size;
-      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);
+
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h))
+       {
+         if (tls_type == GOT_TLS_DESC && htab->tls_desc_trampoline)
+           {
+             /* TLS_DESC with trampoline needs a relocation slot
+                within .rela.plt.  */
+             htab->num_tls_desc++;
+             ehtab->srelplt->size += sizeof (Elf32_External_Rela);
+             htab->tls_trampoline = -1;
+           }
+         else
+           {
+             /* other relocations, including TLS_DESC without trampoline, need
+                a relocation slot within .rela.got.  */
+             ehtab->srelgot->size += sizeof (Elf32_External_Rela);
+           }
+       }
     }
   else
-    h->got.offset = (bfd_vma) - 1;
+    h->got.offset = (bfd_vma)-1;
 
-  if (eh->dyn_relocs == NULL)
+  if (h->dyn_relocs == NULL)
     return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -3482,13 +4175,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      space for pc-relative relocs that have become local due to symbol
      visibility changes.  */
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       if (h->def_regular && (h->forced_local || info->symbolic))
        {
-         struct elf_nds32_dyn_relocs **pp;
+         struct elf_dyn_relocs **pp;
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL;)
+         for (pp = &h->dyn_relocs; (p = *pp) != NULL;)
            {
              p->count -= p->pc_count;
              p->pc_count = 0;
@@ -3525,13 +4218,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            goto keep;
        }
 
-      eh->dyn_relocs = NULL;
+      h->dyn_relocs = NULL;
 
     keep:;
     }
 
   /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  for (p = h->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
       sreloc->size += p->count * sizeof (Elf32_External_Rela);
@@ -3540,33 +4233,23 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
-/* Find any dynamic relocs that apply to read-only sections.  */
+/* Add relocation REL to the end of relocation section SRELOC.  */
 
-static bfd_boolean
-readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+static void
+elf32_nds32_add_dynreloc (bfd *output_bfd,
+                         struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                         asection *sreloc, Elf_Internal_Rela *rel)
 {
-  struct elf_nds32_link_hash_entry *eh;
-  struct elf_nds32_dyn_relocs *p;
-
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  eh = (struct elf_nds32_link_hash_entry *) h;
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection *s = p->sec->output_section;
-
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
-       {
-         struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  bfd_byte *loc;
+  if (sreloc == NULL)
+    abort ();
 
-         info->flags |= DF_TEXTREL;
+  loc = sreloc->contents;
+  loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
+  if (sreloc->reloc_count * sizeof (Elf32_External_Rela) > sreloc->size)
+    abort ();
 
-         /* Not an error, just cut short the traversal.  */
-         return FALSE;
-       }
-    }
-  return TRUE;
+  bfd_elf32_swap_reloca_out (output_bfd, rel, loc);
 }
 
 /* Set the sizes of the dynamic sections.  */
@@ -3579,16 +4262,20 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   bfd *dynobj;
   asection *s;
   bfd_boolean relocs;
+  bfd_boolean plt;
   bfd *ibfd;
 
   htab = nds32_elf_hash_table (info);
-  dynobj = htab->root.dynobj;
+  if (htab == NULL)
+    return FALSE;
+
+  dynobj = elf_hash_table (info)->dynobj;
   BFD_ASSERT (dynobj != NULL);
 
-  if (htab->root.dynamic_sections_created)
+  if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (!info->shared)
+      if (bfd_link_executable (info) && !info->nointerp)
        {
          s = bfd_get_section_by_name (dynobj, ".interp");
          BFD_ASSERT (s != NULL);
@@ -3599,22 +4286,25 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
-      asection *srel;
+      asection *sgot;
+      char *local_tls_type;
+      unsigned long symndx;
+      bfd_vma *local_tlsdesc_gotent;
 
       if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct elf_nds32_dyn_relocs *p;
+         struct elf_dyn_relocs *p;
 
-         for (p = ((struct elf_nds32_dyn_relocs *)
+         for (p = ((struct elf_dyn_relocs *)
                    elf_section_data (s)->local_dynrel);
               p != NULL; p = p->next)
            {
@@ -3628,8 +4318,8 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                }
              else if (p->count != 0)
                {
-                 srel = elf_section_data (p->sec)->sreloc;
-                 srel->size += p->count * sizeof (Elf32_External_Rela);
+                 asection *sreloc = elf_section_data (p->sec)->sreloc;
+                 sreloc->size += p->count * sizeof (Elf32_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                }
@@ -3643,19 +4333,57 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
       end_local_got = local_got + locsymcount;
-      s = htab->sgot;
-      srel = htab->srelgot;
-      for (; local_got < end_local_got; ++local_got)
+      sgot = elf_hash_table (info)->sgot;
+      local_tls_type = elf32_nds32_local_got_tls_type (ibfd);
+      local_tlsdesc_gotent = elf32_nds32_local_tlsdesc_gotent (ibfd);
+      for (symndx = 0; local_got < end_local_got;
+          ++local_got, ++local_tls_type, ++local_tlsdesc_gotent, ++symndx)
        {
          if (*local_got > 0)
            {
-             *local_got = s->size;
-             s->size += 4;
-             if (info->shared)
-               srel->size += sizeof (Elf32_External_Rela);
+             int num_of_got_entry_needed = 0;
+             *local_got = sgot->size;
+             *local_tlsdesc_gotent = sgot->size;
+
+             /* TLS_NORMAL, and TLS_IE need one slot in .got.  */
+             if (*local_tls_type & (GOT_NORMAL | GOT_TLS_IE | GOT_TLS_IEGP))
+               num_of_got_entry_needed = 1;
+             /* TLS_GD, TLS_LD, and TLS_DESC need an 8-byte structure in the GOT.  */
+             else if (*local_tls_type & GOT_TLS_DESC)
+               num_of_got_entry_needed = 2;
+
+             sgot->size += (num_of_got_entry_needed << 2);
+
+             /* non-relax-able TLS_DESCs need a slot in .rela.plt.
+                others need a slot in .rela.got.  */
+             if (*local_tls_type == GOT_TLS_DESC)
+               {
+                 if (bfd_link_pic (info))
+                   {
+                     if (htab->tls_desc_trampoline)
+                       {
+                         htab->num_tls_desc++;
+                         htab->root.srelplt->size += sizeof (Elf32_External_Rela);
+                         htab->tls_trampoline = -1;
+                       }
+                     else
+                       htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+                   }
+                 else
+                   {
+                     /* TLS_DESC -> TLS_LE  */
+                   }
+               }
+             else
+               {
+                 htab->root.srelgot->size += sizeof (Elf32_External_Rela);
+               }
            }
          else
-           *local_got = (bfd_vma) - 1;
+           {
+             *local_got = (bfd_vma) -1;
+             *local_tlsdesc_gotent = (bfd_vma) -1;
+           }
        }
     }
 
@@ -3663,30 +4391,59 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (void *) info);
 
-  /* We now have determined the sizes of the various dynamic sections.
-     Allocate memory for them.  */
-  relocs = FALSE;
-  for (s = dynobj->sections; s != NULL; s = s->next)
+  /* For every jump slot reserved in the sgotplt, reloc_count is
+     incremented.  However, when we reserve space for TLS descriptors,
+     it's not incremented, so in order to compute the space reserved
+     for them, it suffices to multiply the reloc count by the jump
+     slot size.  */
+  if (htab->tls_desc_trampoline && htab->root.srelplt)
+    htab->sgotplt_jump_table_size = elf32_nds32_compute_jump_table_size (htab);
+
+  if (htab->tls_trampoline)
     {
-      if ((s->flags & SEC_LINKER_CREATED) == 0)
+      htab->tls_trampoline = htab->root.splt->size;
+
+      /* If we're not using lazy TLS relocations, don't generate the
+        PLT and GOT entries they require.  */
+      if (!(info->flags & DF_BIND_NOW))
+       {
+         htab->dt_tlsdesc_got = htab->root.sgot->size;
+         htab->root.sgot->size += 4;
+
+         htab->dt_tlsdesc_plt = htab->root.splt->size;
+         htab->root.splt->size += 4 * ARRAY_SIZE (dl_tlsdesc_lazy_trampoline);
+       }
+    }
+
+  /* We now have determined the sizes of the various dynamic sections.
+     Allocate memory for them.  */
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = FALSE;
+  relocs = FALSE;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
-      if (s == htab->splt)
+      if (s == htab->root.splt)
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
+         plt = s->size != 0;
        }
-      else if (s == htab->sgot)
+      else if (s == elf_hash_table (info)->sgot)
        {
          got_size += s->size;
        }
-      else if (s == htab->sgotplt)
+      else if (s == elf_hash_table (info)->sgotplt)
        {
          got_size += s->size;
        }
-      else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
+      else if (strncmp (bfd_section_name (s), ".rela", 5) == 0)
        {
-         if (s->size != 0 && s != htab->srelplt)
+         if (s->size != 0 && s != elf_hash_table (info)->srelplt)
            relocs = TRUE;
 
          /* We use the reloc_count field as a counter if we need
@@ -3735,13 +4492,13 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (!info->shared)
+      if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
        }
 
-      if (htab->splt->size != 0)
+      if (elf_hash_table (info)->splt->size != 0)
        {
          if (!add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
@@ -3750,6 +4507,14 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
            return FALSE;
        }
 
+      if (htab->tls_desc_trampoline && plt)
+       {
+         if (htab->dt_tlsdesc_plt
+             && (!add_dynamic_entry (DT_TLSDESC_PLT, 0)
+                 || !add_dynamic_entry (DT_TLSDESC_GOT, 0)))
+           return FALSE;
+       }
+
       if (relocs)
        {
          if (!add_dynamic_entry (DT_RELA, 0)
@@ -3760,7 +4525,8 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
          if ((info->flags & DF_TEXTREL) == 0)
-           elf_link_hash_traverse (&htab->root, readonly_dynrelocs,
+           elf_link_hash_traverse (&htab->root,
+                                   _bfd_elf_maybe_set_textrel,
                                    (void *) info);
 
          if ((info->flags & DF_TEXTREL) != 0)
@@ -3795,11 +4561,10 @@ nds32_relocate_contents (reloc_howto_type *howto, bfd *input_bfd,
   switch (size)
     {
     default:
-    case 0:
-    case 1:
-    case 8:
       abort ();
       break;
+    case 0:
+      return bfd_reloc_ok;
     case 2:
       x = bfd_getb16 (location);
       break;
@@ -3958,12 +4723,7 @@ nds32_elf_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
 
   /* If the relocation is PC relative, we want to set RELOCATION to
      the distance between the symbol (currently in RELOCATION) and the
-     location we are relocating.  Some targets (e.g., i386-aout)
-     arrange for the contents of the section to be the negative of the
-     offset of the location within the section; for such targets
-     pcrel_offset is FALSE.  Other targets (e.g., m88kbcs or ELF)
-     simply leave the contents of the section as zero; for such
-     targets pcrel_offset is TRUE.  If pcrel_offset is FALSE we do not
+     location we are relocating.  If pcrel_offset is FALSE we do not
      need to subtract out the offset of the location within the
      section (which is just ADDRESS).  */
   if (howto->pc_relative)
@@ -4015,7 +4775,7 @@ nds32_elf_output_symbol_hook (struct bfd_link_info *info,
       if (bfd_is_const_section (input_sec))
        source = input_sec->name;
       else
-       source = input_sec->owner->filename;
+       source = bfd_get_filename (input_sec->owner);
 
       fprintf (sym_ld_script, "\t%s = 0x%08lx;\t /* %s */\n",
               h->root.root.string,
@@ -4060,15 +4820,191 @@ nds32_elf_output_symbol_hook (struct bfd_link_info *info,
    section, which means that the addend must be adjusted
    accordingly.  */
 
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtpoff relocation.
+   This is PT_TLS segment p_vaddr.  */
+
+/* Return the relocation value for @tpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+/* Return the relocation value for @gottpoff relocation
+   if STT_TLS virtual address is ADDRESS.  */
+
+static bfd_vma
+gottpoff (struct bfd_link_info *info, bfd_vma address)
+{
+  bfd_vma tp_base;
+  bfd_vma tp_offset;
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+
+  tp_base = elf_hash_table (info)->tls_sec->vma;
+  tp_offset = address - tp_base;
+
+  return tp_offset;
+}
+
+static bfd_boolean
+patch_tls_desc_to_ie (bfd_byte *contents, Elf_Internal_Rela *rel, bfd *ibfd)
+{
+  /* TLS_GD/TLS_LD model #1
+     46 00 00 00 sethi $r0,#0x0
+     58 00 00 00 ori $r0,$r0,#0x0
+     40 00 74 00 add $r0,$r0,$gp
+     04 10 00 00 lwi $r1,[$r0+#0x0]
+     4b e0 04 01 jral $lp,$r1  */
+
+  /* TLS_GD/TLS_LD model #2
+     46 00 00 00 sethi $r0,#0x0
+     58 00 00 00 ori $r0,$r0,#0x0
+     38 10 74 02 lw $r1,[$r0+($gp<<#0x0)]
+     40 00 74 00 add $r0,$r0,$gp
+     4b e0 04 01 jral $lp,$r1  */
+
+  /* TLS_IE model (non-PIC)
+     46 00 00 00 sethi $r0,#0x0
+     04 00 00 00 lwi $r0,[$r0+#0x0]
+     38 00 64 02 lw $r0,[$r0+($r25<<#0x0)]  */
+
+  /* TLS_IE model (PIC)
+     46 00 00 00 sethi $r0,#0x0
+     58 00 00 00 ori $r0,$r0,#0x0
+     38 00 74 02 lw $r0,[$r0+($gp<<#0x0)]
+     38 00 64 02 lw $r0,[$r0+($r25<<#0x0)]  */
+
+  /* TLS_GD_TO_IE model
+     46 00 00 00 sethi $r0,#0x0
+     58 00 00 00 ori $r0,$r0,#0x0
+     40 00 74 00 add $r0,$rM,$gp
+     04 00 00 01 lwi $r0,[$r0+#0x4]
+     40 00 64 00 add $r0,$r0,$r25  */
+
+  bfd_boolean rz = FALSE;
+
+  typedef struct
+    {
+      uint32_t opcode;
+      uint32_t mask;
+    } pat_t;
+
+  uint32_t patch[3] =
+    {
+      0x40007400, /* add $r0,$rM,$gp     */
+      0x04000001, /* lwi $r0,[$r0+#0x4]  */
+      0x40006400, /* add $r0,$r0,$r25    */
+    };
+
+  pat_t mode0[3] =
+    {
+       { 0x40000000, 0xfe0003ff },
+       { 0x04000000, 0xfe000000 },
+       { 0x4be00001, 0xffff83ff },
+    };
+
+  pat_t mode1[3] =
+    {
+       { 0x38007402, 0xfe007fff },
+       { 0x40007400, 0xfe007fff },
+       { 0x4be00001, 0xffff83ff },
+    };
+
+  unsigned char *p = contents + rel->r_offset;
+
+  uint32_t insn;
+  uint32_t regidx = 0;
+  insn = bfd_getb32 (p);
+  if (INSN_SETHI == (0xfe0fffffu & insn))
+    {
+      regidx = 0x1f & (insn >> 20);
+      p += 4;
+    }
+
+  insn = bfd_getb32 (p);
+  if (INSN_ORI == (0xfe007fffu & insn))
+    {
+      regidx = 0x1f & (insn >> 20);
+      p += 4;
+    }
+
+  if (patch[2] == bfd_getb32 (p + 8)) /* Character instruction.  */
+    {
+      /* already patched?  */
+      if ((patch[0] == (0xfff07fffu & bfd_getb32 (p + 0))) &&
+         (patch[1] == bfd_getb32 (p + 4)))
+       rz = TRUE;
+    }
+  else if (mode0[0].opcode == (mode0[0].mask & bfd_getb32 (p + 0)))
+    {
+      if ((mode0[1].opcode == (mode0[1].mask & bfd_getb32 (p + 4))) &&
+         (mode0[2].opcode == (mode0[2].mask & bfd_getb32 (p + 8))))
+       {
+         bfd_putb32 (patch[0] | (regidx << 15), p + 0);
+         bfd_putb32 (patch[1], p + 4);
+         bfd_putb32 (patch[2], p + 8);
+         rz = TRUE;
+       }
+    }
+  else if (mode1[0].opcode == (mode1[0].mask & bfd_getb32 (p + 0)))
+    {
+      if ((mode1[1].opcode == (mode1[1].mask & bfd_getb32 (p + 4))) &&
+         (mode1[2].opcode == (mode1[2].mask & bfd_getb32 (p + 8))))
+       {
+         bfd_putb32 (patch[0] | (regidx << 15), p + 0);
+         bfd_putb32 (patch[1], p + 4);
+         bfd_putb32 (patch[2], p + 8);
+         rz = TRUE;
+       }
+    }
+
+  if (!rz)
+    {
+      printf ("%s: %s @ 0x%08x\n", __func__, bfd_get_filename (ibfd),
+             (int) rel->r_offset);
+      BFD_ASSERT(0); /* Unsupported pattern.  */
+    }
+
+  return rz;
+}
+
+static enum elf_nds32_tls_type
+get_tls_type (enum elf_nds32_reloc_type r_type, struct elf_link_hash_entry *h);
+
+static unsigned int
+ones32 (register unsigned int x)
+{
+  /* 32-bit recursive reduction using SWAR...
+     but first step is mapping 2-bit values
+     into sum of 2 1-bit values in sneaky way.  */
+  x -= ((x >> 1) & 0x55555555);
+  x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+  x = (((x >> 4) + x) & 0x0f0f0f0f);
+  x += (x >> 8);
+  x += (x >> 16);
+  return (x & 0x0000003f);
+}
+
+#if !HAVE_FLS
+static unsigned int
+fls (register unsigned int x)
+{
+  return ffs (x & (-x));
+}
+#endif /* !HAVE_FLS */
+
+#define nds32_elf_local_tlsdesc_gotent(bfd) \
+  (elf_nds32_tdata (bfd)->local_tlsdesc_gotent)
+
 static bfd_boolean
-nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
+nds32_elf_relocate_section (bfd *                 output_bfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info * info,
-                           bfd *                  input_bfd,
-                           asection *             input_section,
-                           bfd_byte *             contents,
-                           Elf_Internal_Rela *    relocs,
-                           Elf_Internal_Sym *     local_syms,
-                           asection **            local_sections)
+                           bfd *                  input_bfd,
+                           asection *             input_section,
+                           bfd_byte *             contents,
+                           Elf_Internal_Rela *    relocs,
+                           Elf_Internal_Sym *     local_syms,
+                           asection **            local_sections)
 {
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
@@ -4078,6 +5014,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
   bfd_reloc_status_type r;
   const char *errmsg = NULL;
   bfd_vma gp;
+  struct elf_link_hash_table *ehtab;
   struct elf_nds32_link_hash_table *htab;
   bfd *dynobj;
   bfd_vma *local_got_offsets;
@@ -4089,14 +5026,15 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
+  ehtab = elf_hash_table (info);
   htab = nds32_elf_hash_table (info);
   high_address = bfd_get_section_limit (input_bfd, input_section);
 
   dynobj = htab->root.dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
-  sgot = htab->sgot;
-  splt = htab->splt;
+  sgot = ehtab->sgot;
+  splt = ehtab->splt;
   sreloc = NULL;
 
   rel = relocs;
@@ -4104,8 +5042,10 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
   table = nds32_elf_hash_table (info);
   eliminate_gc_relocs = table->eliminate_gc_relocs;
+
   /* By this time, we can adjust the value of _SDA_BASE_.  */
-  if ((!info->relocatable))
+  /* Explain _SDA_BASE_  */
+  if ((!bfd_link_relocatable (info)))
     {
       is_SDA_BASE_set = 1;
       r = nds32_elf_final_sda_base (output_bfd, info, &gp, TRUE);
@@ -4113,11 +5053,15 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
        return FALSE;
     }
 
+  /* Do TLS model conversion once at first.  */
+  nds32_elf_unify_tls_model (input_bfd, input_section, contents, 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.  */
   fpbase_addr = elf_gp (output_bfd);
 
+  /* Deal with (dynamic) relocations.  */
   for (rel = relocs; rel < relend; rel++)
     {
       enum elf_nds32_reloc_type r_type;
@@ -4127,6 +5071,9 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
       Elf_Internal_Sym *sym = NULL;
       asection *sec;
       bfd_vma relocation;
+      bfd_vma relocation_sym = 0xdeadbeef;
+      Elf_Internal_Rela *lorel;
+      bfd_vma off;
 
       /* We can't modify r_addend here as elf_link_input_bfd has an assert to
         ensure it's zero (we use REL relocs, not RELA).  Therefore this
@@ -4139,8 +5086,9 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type >= R_NDS32_max)
        {
-         (*_bfd_error_handler) (_("%B: error: unknown relocation type %d."),
-                                input_bfd, r_type);
+         /* xgettext:c-format */
+         _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                             input_bfd, r_type);
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
          continue;
@@ -4156,7 +5104,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          || r_type == R_NDS32_TRAN)
        continue;
 
-      /* If we enter the fp-as-gp region.  Resolve the address of best fp-base.  */
+      /* If we enter the fp-as-gp region.  Resolve the address
+        of best fp-base.  */
       if (ELF32_R_TYPE (rel->r_info) == R_NDS32_RELAX_REGION_BEGIN
          && (rel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG))
        {
@@ -4173,9 +5122,13 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          fpbase_addr = elf_gp (output_bfd);
        }
 
-      if (((r_type >= R_NDS32_DWARF2_OP1_RELA
-           && r_type <= R_NDS32_DWARF2_LEB_RELA)
-          || r_type >= R_NDS32_RELAX_ENTRY) && !info->relocatable)
+      /* Skip the relocations used for relaxation.  */
+      /* We have to update LONGCALL and LONGJUMP
+        relocations when generating the relocatable files.  */
+      if (!bfd_link_relocatable (info)
+         && (r_type >= R_NDS32_RELAX_ENTRY
+             || (r_type >= R_NDS32_LONGCALL4
+                 && r_type <= R_NDS32_LONGJUMP7)))
        continue;
 
       howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type);
@@ -4194,10 +5147,26 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
          addend = rel->r_addend;
+
+         /* keep symbol location for static TLS_IE GOT entry  */
+         relocation_sym = relocation;
+         if (bfd_link_relocatable (info))
+           {
+             /* This is a relocatable link.  We don't have to change
+                anything, unless the reloc is against a section symbol,
+                in which case we have to adjust according to where the
+                section symbol winds up in the output section.  */
+             if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+               rel->r_addend += sec->output_offset + sym->st_value;
+
+             continue;
+           }
        }
       else
        {
          /* External symbol.  */
+         if (bfd_link_relocatable (info))
+           continue;
          bfd_boolean warned, ignored, unresolved_reloc;
          int symndx = r_symndx - symtab_hdr->sh_info;
 
@@ -4206,10 +5175,27 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                                   relocation, unresolved_reloc, warned,
                                   ignored);
 
+         /* keep symbol location for static TLS_IE GOT entry  */
+         relocation_sym = relocation;
+
          /* la $fp, _FP_BASE_ is per-function (region).
             Handle it specially.  */
          switch ((int) r_type)
            {
+           case R_NDS32_HI20_RELA:
+           case R_NDS32_LO12S0_RELA:
+             if (strcmp (elf_sym_hashes (input_bfd)[symndx]->root.root.string,
+                         FP_BASE_NAME) == 0)
+               {
+                 if (!bfd_link_pie (info))
+                   {
+                     _bfd_error_handler
+                       ("%pB: warning: _FP_BASE_ setting insns relaxation failed.",
+                        input_bfd);
+                   }
+                 relocation = fpbase_addr;
+               }
+             break;
            case R_NDS32_SDA19S0_RELA:
            case R_NDS32_SDA15S0_RELA:
            case R_NDS32_20_RELA:
@@ -4220,19 +5206,6 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                  break;
                }
            }
-
-       }
-
-      if (info->relocatable)
-       {
-         /* This is a relocatable link.  We don't have to change
-            anything, unless the reloc is against a section symbol,
-            in which case we have to adjust according to where the
-            section symbol winds up in the output section.  */
-         if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-           rel->r_addend += sec->output_offset + sym->st_value;
-
-         continue;
        }
 
       /* Sanity check the address.  */
@@ -4242,9 +5215,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          goto check_reloc;
        }
 
-      if ((r_type >= R_NDS32_DWARF2_OP1_RELA
-          && r_type <= R_NDS32_DWARF2_LEB_RELA)
-         || r_type >= R_NDS32_RELAX_ENTRY)
+      if (r_type >= R_NDS32_RELAX_ENTRY)
        continue;
 
       switch ((int) r_type)
@@ -4293,11 +5264,18 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
        case R_NDS32_PLT_GOTREL_LO15:
        case R_NDS32_PLT_GOTREL_LO19:
        case R_NDS32_PLT_GOTREL_LO20:
-         if (h == NULL || h->forced_local || h->plt.offset == (bfd_vma) - 1)
+         if (h == NULL
+             || h->forced_local
+             || h->plt.offset == (bfd_vma) -1
+             || (bfd_link_pie (info) && h->def_regular))
            {
+             /* Maybe we should find better checking to optimize
+                PIE PLT relocations.  */
              /* We didn't make a PLT entry for this symbol.  This
                 happens when statically linking PIC code, or when
                 using -Bsymbolic.  */
+             if (h)
+               h->plt.offset = (bfd_vma) -1;   /* Cancel PLT trampoline.  */
              relocation -= elf_gp (output_bfd);
              break;
            }
@@ -4349,21 +5327,18 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
        case R_NDS32_GOTPC_HI20:
        case R_NDS32_GOTPC_LO12:
-           {
-             /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation
-                bl .+4
-                seth rx,#high(_GLOBAL_OFFSET_TABLE_)
-                or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4)
-                or
-                bl .+4
-                seth rx,#shigh(_GLOBAL_OFFSET_TABLE_)
-                add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4)
-              */
-             relocation = elf_gp (output_bfd);
-             relocation -= (input_section->output_section->vma
-                            + input_section->output_offset + rel->r_offset);
-             break;
-           }
+         /* .got(_GLOBAL_OFFSET_TABLE_) - pc relocation
+            bl .+4
+            seth rx,#high(_GLOBAL_OFFSET_TABLE_)
+            or3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4)
+            or
+            bl .+4
+            seth rx,#shigh(_GLOBAL_OFFSET_TABLE_)
+            add3 rx,rx,#low(_GLOBAL_OFFSET_TABLE_ +4)  */
+         relocation = elf_gp (output_bfd);
+         relocation -= (input_section->output_section->vma
+                        + input_section->output_offset + rel->r_offset);
+         break;
 
        case R_NDS32_GOT20:
          /* Fall through.  */
@@ -4377,14 +5352,16 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
          if (h != NULL)
            {
+             /* External symbol  */
              bfd_boolean dyn;
-             bfd_vma off;
 
              off = h->got.offset;
              BFD_ASSERT (off != (bfd_vma) - 1);
              dyn = htab->root.dynamic_sections_created;
-             if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-                 || (info->shared
+             if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
+                                                   bfd_link_pic (info),
+                                                   h)
+                 || (bfd_link_pic (info)
                      && (info->symbolic
                          || h->dynindx == -1
                          || h->forced_local) && h->def_regular))
@@ -4401,7 +5378,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                     When doing a dynamic link, we create a .rela.got
                     relocation entry to initialize the value.  This
                     is done in the finish_dynamic_symbol routine.  */
-                 if ((off & 1) != 0)
+                 if ((off & 1) != 0)   /* clear LSB  */
                    off &= ~1;
                  else
                    {
@@ -4414,7 +5391,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
            }
          else
            {
-             bfd_vma off;
+             /* Local symbol  */
              bfd_byte *loc;
 
              BFD_ASSERT (local_got_offsets != NULL
@@ -4425,13 +5402,13 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
              /* 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)
+             if ((off & 1) != 0)       /* clear LSB  */
                off &= ~1;
              else
                {
                  bfd_put_32 (output_bfd, relocation, sgot->contents + off);
 
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    {
                      asection *srelgot;
                      Elf_Internal_Rela outrel;
@@ -4477,7 +5454,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
        case R_NDS32_LO12S1_RELA:
        case R_NDS32_LO12S0_RELA:
        case R_NDS32_LO12S0_ORI_RELA:
-         if (info->shared && r_symndx != 0
+         if (bfd_link_pic (info) && r_symndx != 0
              && (input_section->flags & SEC_ALLOC) != 0
              && (eliminate_gc_relocs == 0
                  || (sec && (sec->flags & SEC_EXCLUDE) == 0))
@@ -4511,8 +5488,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                    return FALSE;
 
                  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
-                             && strcmp (bfd_get_section_name (input_bfd,
-                                                              input_section),
+                             && strcmp (bfd_section_name (input_section),
                                         name + 5) == 0);
 
                  sreloc = bfd_get_section_by_name (dynobj, name);
@@ -4549,15 +5525,40 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                     become local.  */
                  if (h == NULL
                      || ((info->symbolic || h->dynindx == -1)
-                         && h->def_regular))
+                         && h->def_regular)
+                     || (bfd_link_pie (info) && h->def_regular))
                    {
                      relocate = TRUE;
                      outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE);
                      outrel.r_addend = relocation + rel->r_addend;
+
+                     if (h)
+                       {
+                         h->plt.offset = (bfd_vma) -1;   /* cancel PLT trampoline.  */
+
+                         BFD_ASSERT (sgot != NULL);
+                         /* If we did not allocate got entry for the symbol,
+                            we can not fill the nonexistent got entry.  */
+                         if (h->got.offset != (bfd_vma) -1
+                             && (h->got.offset & 1) == 0)
+                           {
+                             bfd_put_32 (output_bfd, outrel.r_addend,
+                                         sgot->contents + h->got.offset);
+                           }
+                       }
                    }
                  else
                    {
-                     BFD_ASSERT (h->dynindx != -1);
+                     if (h->dynindx == -1)
+                       {
+                         _bfd_error_handler
+                           (_("%pB: relocation %s against `%s' can not be used when "
+                              "making a shared object; recompile with -fPIC"),
+                            input_bfd, nds32_elf_howto_table[r_type].name, h->root.root.string);
+                         bfd_set_error (bfd_error_bad_value);
+                         return FALSE;
+                       }
+
                      outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
                      outrel.r_addend = rel->r_addend;
                    }
@@ -4578,11 +5579,11 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          break;
 
        case R_NDS32_25_ABS_RELA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
-             (*_bfd_error_handler)
-               (_("%s: warning: cannot deal R_NDS32_25_ABS_RELA in shared mode."),
-                bfd_get_filename (input_bfd));
+             _bfd_error_handler
+               (_("%pB: warning: %s unsupported in shared mode"),
+                input_bfd, "R_NDS32_25_ABS_RELA");
              return FALSE;
            }
          break;
@@ -4594,126 +5595,120 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          goto check_reloc;
 
        case R_NDS32_HI20:
+         /* We allow an arbitrary number of HI20 relocs before the
+            LO12 reloc.  This permits gcc to emit the HI and LO relocs
+            itself.  */
+         for (lorel = rel + 1;
+              (lorel < relend
+               && ELF32_R_TYPE (lorel->r_info) == R_NDS32_HI20); lorel++)
+           continue;
+         if (lorel < relend
+             && (ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S3
+                 || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S2
+                 || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S1
+                 || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S0))
            {
-             Elf_Internal_Rela *lorel;
-
-             /* We allow an arbitrary number of HI20 relocs before the
-                LO12 reloc.  This permits gcc to emit the HI and LO relocs
-                itself.  */
-             for (lorel = rel + 1;
-                  (lorel < relend
-                   && ELF32_R_TYPE (lorel->r_info) == R_NDS32_HI20); lorel++)
-               continue;
-             if (lorel < relend
-                 && (ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S3
-                     || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S2
-                     || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S1
-                     || ELF32_R_TYPE (lorel->r_info) == R_NDS32_LO12S0))
-               {
-                 nds32_elf_relocate_hi20 (input_bfd, r_type, rel, lorel,
-                                          contents, relocation + addend);
-                 r = bfd_reloc_ok;
-               }
-             else
-               r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                             contents, offset, relocation, addend);
+             nds32_elf_relocate_hi20 (input_bfd, r_type, rel, lorel,
+                                      contents, relocation + addend);
+             r = bfd_reloc_ok;
            }
-
+         else
+           r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                         contents, offset, relocation,
+                                         addend);
          goto check_reloc;
 
        case R_NDS32_GOT17S2_RELA:
        case R_NDS32_GOT15S2_RELA:
+         BFD_ASSERT (sgot != NULL);
+
+         if (h != NULL)
            {
-             bfd_vma off;
+             bfd_boolean dyn;
 
-             BFD_ASSERT (sgot != NULL);
+             off = h->got.offset;
+             BFD_ASSERT (off != (bfd_vma) - 1);
 
-             if (h != NULL)
+             dyn = htab->root.dynamic_sections_created;
+             if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL
+                 (dyn, bfd_link_pic (info), h)
+                 || (bfd_link_pic (info)
+                     && (info->symbolic
+                         || h->dynindx == -1
+                         || h->forced_local)
+                     && h->def_regular))
                {
-                 bfd_boolean dyn;
-
-                 off = h->got.offset;
-                 BFD_ASSERT (off != (bfd_vma) - 1);
-
-                 dyn = htab->root.dynamic_sections_created;
-                 if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL
-                     (dyn, info->shared, h) || (info->shared
-                                                && (info->symbolic
-                                                    || h->dynindx == -1
-                                                    || h->forced_local)
-                                                && h->def_regular))
+                 /* This is actually a static link, or it is a
+                    -Bsymbolic link and the symbol is defined
+                    locally, or the symbol was forced to be local
+                    because of a version file.  We must initialize
+                    this entry in the global offset table.  Since the
+                    offset must always be a multiple of 4, we use the
+                    least significant bit to record whether we have
+                    initialized it already.
+
+                    When doing a dynamic link, we create a .rela.got
+                    relocation entry to initialize the value.  This
+                    is done in the finish_dynamic_symbol routine.  */
+                 if ((off & 1) != 0)
+                   off &= ~1;
+                 else
                    {
-                     /* This is actually a static link, or it is a
-                        -Bsymbolic link and the symbol is defined
-                        locally, or the symbol was forced to be local
-                        because of a version file.  We must initialize
-                        this entry in the global offset table.  Since the
-                        offset must always be a multiple of 4, we use the
-                        least significant bit to record whether we have
-                        initialized it already.
-
-                        When doing a dynamic link, we create a .rela.got
-                        relocation entry to initialize the value.  This
-                        is done in the finish_dynamic_symbol routine.  */
-                     if ((off & 1) != 0)
-                       off &= ~1;
-                     else
-                       {
-                         bfd_put_32 (output_bfd, relocation,
-                                     sgot->contents + off);
-                         h->got.offset |= 1;
-                       }
+                     bfd_put_32 (output_bfd, relocation,
+                                 sgot->contents + off);
+                     h->got.offset |= 1;
                    }
                }
-             else
-               {
-                 bfd_byte *loc;
+           }
+         else
+           {
+             bfd_byte *loc;
 
-                 BFD_ASSERT (local_got_offsets != NULL
-                             && local_got_offsets[r_symndx] != (bfd_vma) - 1);
+             BFD_ASSERT (local_got_offsets != NULL
+                         && local_got_offsets[r_symndx] != (bfd_vma) - 1);
 
-                 off = local_got_offsets[r_symndx];
+             off = local_got_offsets[r_symndx];
 
-                 /* 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
+             /* 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_put_32 (output_bfd, relocation, sgot->contents + off);
+
+                 if (bfd_link_pic (info))
                    {
-                     bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+                     asection *srelgot;
+                     Elf_Internal_Rela outrel;
 
-                     if (info->shared)
-                       {
-                         asection *srelgot;
-                         Elf_Internal_Rela outrel;
-
-                         /* We need to generate a R_NDS32_RELATIVE reloc
-                            for the dynamic linker.  */
-                         srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-                         BFD_ASSERT (srelgot != NULL);
-
-                         outrel.r_offset = (elf_gp (output_bfd)
-                                            + sgot->output_offset + off);
-                         outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE);
-                         outrel.r_addend = relocation;
-                         loc = srelgot->contents;
-                         loc +=
-                           srelgot->reloc_count * sizeof (Elf32_External_Rela);
-                         bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
-                         ++srelgot->reloc_count;
-                       }
-                     local_got_offsets[r_symndx] |= 1;
+                     /* We need to generate a R_NDS32_RELATIVE reloc
+                        for the dynamic linker.  */
+                     srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                     BFD_ASSERT (srelgot != NULL);
+
+                     outrel.r_offset = (elf_gp (output_bfd)
+                                        + sgot->output_offset + off);
+                     outrel.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE);
+                     outrel.r_addend = relocation;
+                     loc = srelgot->contents;
+                     loc +=
+                       srelgot->reloc_count * sizeof (Elf32_External_Rela);
+                     bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                     ++srelgot->reloc_count;
                    }
+                 local_got_offsets[r_symndx] |= 1;
                }
-             relocation = sgot->output_section->vma + sgot->output_offset + off
-                          - elf_gp (output_bfd);
            }
+         relocation = sgot->output_section->vma + sgot->output_offset + off
+           - elf_gp (output_bfd);
+
          if (relocation & align)
            {
              /* Incorrect alignment.  */
-             (*_bfd_error_handler)
-               (_("%B: warning: unaligned access to GOT entry."), input_bfd);
+             _bfd_error_handler
+               (_("%pB: warning: unaligned access to GOT entry"), input_bfd);
              ret = FALSE;
              r = bfd_reloc_dangerous;
              goto check_reloc;
@@ -4744,52 +5739,240 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
        case R_NDS32_SDA19S0_RELA:
        case R_NDS32_SDA15S0_RELA:
        case R_NDS32_SDA15S0:
+         align = 0x0;
+       handle_sda:
+         BFD_ASSERT (sec != NULL);
+
+         /* If the symbol is in the abs section, the out_bfd will be null.
+            This happens when the relocation has a symbol@GOTOFF.  */
+         r = nds32_elf_final_sda_base (output_bfd, info, &gp, FALSE);
+         if (r != bfd_reloc_ok)
            {
-             align = 0x0;
-handle_sda:
-             BFD_ASSERT (sec != NULL);
-
-             /* If the symbol is in the abs section, the out_bfd will be null.
-                This happens when the relocation has a symbol@GOTOFF.  */
-             r = nds32_elf_final_sda_base (output_bfd, info, &gp, FALSE);
-             if (r != bfd_reloc_ok)
-               {
-                 (*_bfd_error_handler)
-                   (_("%B: warning: relocate SDA_BASE failed."), input_bfd);
-                 ret = FALSE;
-                 goto check_reloc;
-               }
+             _bfd_error_handler
+               (_("%pB: warning: relocate SDA_BASE failed"), input_bfd);
+             ret = FALSE;
+             goto check_reloc;
+           }
 
-             /* At this point `relocation' contains the object's
-                address.  */
-             if (r_type == R_NDS32_SDA_FP7U2_RELA)
-               {
-                 relocation -= fpbase_addr;
-               }
-             else
-               relocation -= gp;
-             /* Now it contains the offset from _SDA_BASE_.  */
+         /* At this point `relocation' contains the object's
+            address.  */
+         if (r_type == R_NDS32_SDA_FP7U2_RELA)
+           {
+             relocation -= fpbase_addr;
+           }
+         else
+           relocation -= gp;
+         /* Now it contains the offset from _SDA_BASE_.  */
 
-             /* Make sure alignment is correct.  */
+         /* Make sure alignment is correct.  */
 
-             if (relocation & align)
-               {
-                 /* Incorrect alignment.  */
-                 (*_bfd_error_handler)
-                   (_("%B(%A): warning: unaligned small data access of type %d."),
-                    input_bfd, input_section, r_type);
-                 ret = FALSE;
-                 goto check_reloc;
-               }
+         if (relocation & align)
+           {
+             /* Incorrect alignment.  */
+             _bfd_error_handler
+               /* xgettext:c-format */
+               (_("%pB(%pA): warning: unaligned small data access"
+                  " of type %d"),
+                input_bfd, input_section, r_type);
+             ret = FALSE;
+             goto check_reloc;
            }
-
          break;
+
        case R_NDS32_17IFC_PCREL_RELA:
        case R_NDS32_10IFCU_PCREL_RELA:
-         /* do nothing */
+         /* 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:
+         /* We do not have garbage collection for got entries.
+            Therefore, IE to LE may have one empty entry, and DESC to
+            LE may have two.  */
+         if (elf_hash_table (info)->tls_sec != NULL)
+           relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET);
          break;
 
-         /* DON'T   fall through.  */
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+       case R_NDS32_TLS_DESC_HI20:
+       case R_NDS32_TLS_DESC_LO12:
+       case R_NDS32_TLS_IE_LO12:
+       case R_NDS32_TLS_IEGP_HI20:
+       case R_NDS32_TLS_IEGP_LO12:
+       case R_NDS32_TLS_IEGP_LO12S2:
+         {
+           /* Relocation is to the entry for this symbol in the global
+              offset table.  */
+           enum elf_nds32_tls_type tls_type, org_tls_type, eff_tls_type;
+           asection *srelgot;
+           Elf_Internal_Rela outrel;
+           bfd_byte *loc;
+           int indx = 0;
+
+           eff_tls_type = org_tls_type = get_tls_type (r_type, h);
+
+           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, bfd_link_pic (info), h)
+                   && (!bfd_link_pic (info)
+                       || !SYMBOL_REFERENCES_LOCAL (info, h)))
+                 indx = h->dynindx;
+             }
+           else
+             {
+               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 (1 < ones32 (tls_type))
+             {
+               eff_tls_type = 1 << (fls (tls_type) - 1);
+               /* TLS model shall be handled in nds32_elf_unify_tls_model ().  */
+
+               /* TLS model X -> LE is not implement yet!
+                  workaround here!  */
+               if (eff_tls_type == GOT_TLS_LE)
+                 {
+                   eff_tls_type = 1 << (fls (tls_type ^ eff_tls_type) - 1);
+                 }
+             }
+
+           /* The offset must always be a multiple of 4.  We use
+              the least significant bit to record whether we have
+              already processed this entry.  */
+           bfd_boolean need_relocs = FALSE;
+           srelgot = ehtab->srelgot;
+           if ((bfd_link_pic (info) || 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 (off & 1)
+             {
+               off &= ~1;
+               relocation &= ~1;
+
+               if (eff_tls_type & GOT_TLS_DESC)
+                 {
+                   relocation -= elf_gp (output_bfd);
+                   if ((R_NDS32_TLS_DESC_HI20 == r_type) && (!need_relocs))
+                     {
+                       /* TLS model shall be converted.  */
+                       BFD_ASSERT(0);
+                     }
+                 }
+               else if (eff_tls_type & GOT_TLS_IEGP)
+                 {
+                   relocation -= elf_gp (output_bfd);
+                 }
+             }
+           else
+             {
+               if ((eff_tls_type & GOT_TLS_LE) && (tls_type ^ eff_tls_type))
+                 {
+                   /* TLS model workaround shall be applied.  */
+                   BFD_ASSERT(0);
+                 }
+               else if (eff_tls_type & (GOT_TLS_IE | GOT_TLS_IEGP))
+                 {
+                   if (eff_tls_type & GOT_TLS_IEGP)
+                     relocation -= elf_gp(output_bfd);
+
+                   if (need_relocs)
+                     {
+                       if (indx == 0)
+                         outrel.r_addend = gottpoff (info, relocation_sym);
+                       else
+                         outrel.r_addend = 0;
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset + off);
+                       outrel.r_info = ELF32_R_INFO (indx, R_NDS32_TLS_TPOFF);
+
+                       elf32_nds32_add_dynreloc (output_bfd, info, srelgot,
+                                                 &outrel);
+                     }
+                   else
+                     {
+                       bfd_put_32 (output_bfd, gottpoff (info, relocation_sym),
+                                   sgot->contents + off);
+                     }
+                 }
+               else if (eff_tls_type & GOT_TLS_DESC)
+                 {
+                   relocation -= elf_gp (output_bfd);
+                   if (need_relocs)
+                     {
+                       if (indx == 0)
+                         outrel.r_addend = gottpoff (info, relocation_sym);
+                       else
+                         outrel.r_addend = 0;
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset + off);
+                       outrel.r_info = ELF32_R_INFO (indx, R_NDS32_TLS_DESC);
+
+                       if (htab->tls_desc_trampoline)
+                         {
+                           asection *srelplt;
+                           srelplt = ehtab->srelplt;
+                           loc = srelplt->contents;
+                           loc += htab->next_tls_desc_index++ * sizeof (Elf32_External_Rela);
+                           BFD_ASSERT (loc + sizeof (Elf32_External_Rela)
+                                       <= srelplt->contents + srelplt->size);
+
+                           bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                         }
+                       else
+                         {
+                           loc = srelgot->contents;
+                           loc += srelgot->reloc_count * sizeof (Elf32_External_Rela);
+                           bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                           ++srelgot->reloc_count;
+                         }
+                     }
+                   else
+                     {
+                       /* feed me!  */
+                       bfd_put_32 (output_bfd, 0xdeadbeef,
+                                   sgot->contents + off);
+                       bfd_put_32 (output_bfd, gottpoff (info, relocation_sym),
+                                   sgot->contents + off + 4);
+                       patch_tls_desc_to_ie (contents, rel, input_bfd);
+                       BFD_ASSERT(0);
+                     }
+                 }
+               else
+                 {
+                   /* TLS model workaround shall be applied.  */
+                   BFD_ASSERT(0);
+                 }
+
+               if (h != NULL)
+                 h->got.offset |= 1;
+               else
+                 local_got_offsets[r_symndx] |= 1;
+             }
+         }
+       break;
+         /* DON'T fall through.  */
 
        default:
          /* OLD_NDS32_RELOC.  */
@@ -4855,8 +6038,22 @@ 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:
+       case R_NDS32_TLS_DESC_HI20:
+       case R_NDS32_TLS_DESC_LO12:
+       case R_NDS32_TLS_IE_LO12:
+       case R_NDS32_TLS_IEGP_HI20:
+       case R_NDS32_TLS_IEGP_LO12:
+       case R_NDS32_TLS_IEGP_LO12S2:
          /* 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,
@@ -4871,7 +6068,7 @@ handle_sda:
          break;
        }
 
-check_reloc:
+    check_reloc:
 
       if (r != bfd_reloc_ok)
        {
@@ -4885,7 +6082,7 @@ check_reloc:
              name = bfd_elf_string_from_elf_section
                      (input_bfd, symtab_hdr->sh_link, sym->st_name);
              if (name == NULL || *name == '\0')
-               name = bfd_section_name (input_bfd, sec);
+               name = bfd_section_name (sec);
            }
 
          if (errmsg != NULL)
@@ -4894,16 +6091,14 @@ check_reloc:
          switch (r)
            {
            case bfd_reloc_overflow:
-             if (!((*info->callbacks->reloc_overflow)
-                   (info, (h ? &h->root : NULL), name, howto->name,
-                    (bfd_vma) 0, input_bfd, input_section, offset)))
-               return FALSE;
+             (*info->callbacks->reloc_overflow)
+               (info, (h ? &h->root : NULL), name, howto->name,
+                (bfd_vma) 0, input_bfd, input_section, offset);
              break;
 
            case bfd_reloc_undefined:
-             if (!((*info->callbacks->undefined_symbol)
-                   (info, name, input_bfd, input_section, offset, TRUE)))
-               return FALSE;
+             (*info->callbacks->undefined_symbol)
+               (info, name, input_bfd, input_section, offset, TRUE);
              break;
 
            case bfd_reloc_outofrange:
@@ -4922,15 +6117,18 @@ check_reloc:
              errmsg = _("internal error: unknown error");
              /* Fall through.  */
 
-common_error:
-             if (!((*info->callbacks->warning)
-                   (info, errmsg, name, input_bfd, input_section, offset)))
-               return FALSE;
+           common_error:
+             (*info->callbacks->warning) (info, errmsg, name, input_bfd,
+                                          input_section, offset);
              break;
            }
        }
     }
 
+  /* Resotre header size to avoid overflow load.  */
+  if (elf_nds32_tdata (input_bfd)->hdr_size != 0)
+    symtab_hdr->sh_size = elf_nds32_tdata (input_bfd)->hdr_size;
+
   return ret;
 }
 
@@ -4941,10 +6139,12 @@ static bfd_boolean
 nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
 {
-  struct elf_nds32_link_hash_table *htab;
+  struct elf_link_hash_table *ehtab;
+  struct elf_nds32_link_hash_entry *hent;
   bfd_byte *loc;
 
-  htab = nds32_elf_hash_table (info);
+  ehtab = elf_hash_table (info);
+  hent = (struct elf_nds32_link_hash_entry *) h;
 
   if (h->plt.offset != (bfd_vma) - 1)
     {
@@ -4962,9 +6162,9 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
 
       BFD_ASSERT (h->dynindx != -1);
 
-      splt = htab->splt;
-      sgot = htab->sgotplt;
-      srela = htab->srelplt;
+      splt = ehtab->splt;
+      sgot = ehtab->sgotplt;
+      srela = ehtab->srelplt;
       BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
 
       /* Get the index in the procedure linkage table which
@@ -4979,7 +6179,7 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
       got_offset = (plt_index + 3) * 4;
 
       /* Fill in the entry in the procedure linkage table.  */
-      if (!info->shared)
+      if (!bfd_link_pic (info))
        {
          unsigned long insn;
 
@@ -5010,8 +6210,6 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
          unsigned long insn;
          long offset;
 
-         /* FIXME, sda_base is 65536, it will damage opcode.  */
-         /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */
          offset = sgot->output_section->vma + sgot->output_offset + got_offset
                   - elf_gp (output_bfd);
          insn = PLT_PIC_ENTRY_WORD0 + ((offset >> 12) & 0xfffff);
@@ -5062,18 +6260,19 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
        }
     }
 
-  if (h->got.offset != (bfd_vma) - 1)
+  if (h->got.offset != (bfd_vma) - 1
+      && hent->tls_type == GOT_NORMAL)
     {
       asection *sgot;
-      asection *srela;
+      asection *srelagot;
       Elf_Internal_Rela rela;
 
       /* This symbol has an entry in the global offset table.
         Set it up.  */
 
-      sgot = htab->sgot;
-      srela = htab->srelgot;
-      BFD_ASSERT (sgot != NULL && srela != NULL);
+      sgot = ehtab->sgot;
+      srelagot = ehtab->srelgot;
+      BFD_ASSERT (sgot != NULL && srelagot != NULL);
 
       rela.r_offset = (sgot->output_section->vma
                       + sgot->output_offset + (h->got.offset & ~1));
@@ -5083,15 +6282,22 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
         the symbol was forced to be local because of a version file.
         The entry in the global offset table will already have been
         initialized in the relocate_section function.  */
-      if (info->shared
-         && (info->symbolic
-             || h->dynindx == -1 || h->forced_local) && h->def_regular)
+      if ((bfd_link_pic (info)
+          && (info->symbolic || h->dynindx == -1 || h->forced_local)
+          && h->def_regular)
+         || (bfd_link_pie (info) && h->def_regular))
        {
          rela.r_info = ELF32_R_INFO (0, R_NDS32_RELATIVE);
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
-       }
+
+         if ((h->got.offset & 1) == 0)
+           {
+             bfd_put_32 (output_bfd, rela.r_addend,
+                         sgot->contents + h->got.offset);
+           }
+       }
       else
        {
          BFD_ASSERT ((h->got.offset & 1) == 0);
@@ -5101,10 +6307,11 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
          rela.r_addend = 0;
        }
 
-      loc = srela->contents;
-      loc += srela->reloc_count * sizeof (Elf32_External_Rela);
+      loc = srelagot->contents;
+      loc += srelagot->reloc_count * sizeof (Elf32_External_Rela);
       bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-      ++srela->reloc_count;
+      ++srelagot->reloc_count;
+      BFD_ASSERT (loc < (srelagot->contents + srelagot->size));
     }
 
   if (h->needs_copy)
@@ -5146,23 +6353,32 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
 static bfd_boolean
 nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
 {
-  struct elf_nds32_link_hash_table *htab;
   bfd *dynobj;
   asection *sdyn;
-  asection *sgot;
+  asection *sgotplt;
+  struct elf_link_hash_table *ehtab;
+  struct elf_nds32_link_hash_table *htab;
 
+  ehtab = elf_hash_table (info);
   htab = nds32_elf_hash_table (info);
-  dynobj = htab->root.dynobj;
+  if (htab == NULL)
+    return FALSE;
+
+  dynobj = elf_hash_table (info)->dynobj;
 
-  sgot = htab->sgotplt;
+  sgotplt = ehtab->sgotplt;
+  /* A broken linker script might have discarded the dynamic sections.
+     Catch this here so that we do not seg-fault later on.  */
+  if (sgotplt != NULL && bfd_is_abs_section (sgotplt->output_section))
+    return FALSE;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
-  if (htab->root.dynamic_sections_created)
+  if (elf_hash_table (info)->dynamic_sections_created)
     {
       asection *splt;
       Elf32_External_Dyn *dyncon, *dynconend;
 
-      BFD_ASSERT (sgot != NULL && sdyn != NULL);
+      BFD_ASSERT (sgotplt != NULL && sdyn != NULL);
 
       dyncon = (Elf32_External_Dyn *) sdyn->contents;
       dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
@@ -5180,11 +6396,11 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
              break;
 
            case DT_PLTGOT:
-             /* name = ".got"; */
-             s = htab->sgot->output_section;
+             /* name = ".got";  */
+             s = ehtab->sgot->output_section;
              goto get_vma;
            case DT_JMPREL:
-             s = htab->srelplt->output_section;
+             s = ehtab->srelplt->output_section;
            get_vma:
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_ptr = s->vma;
@@ -5192,7 +6408,7 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
              break;
 
            case DT_PLTRELSZ:
-             s = htab->srelplt->output_section;
+             s = ehtab->srelplt->output_section;
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_val = s->size;
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
@@ -5208,33 +6424,44 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
                 the linker script arranges for .rela.plt to follow all
                 other relocation sections, we don't have to worry
                 about changing the DT_RELA entry.  */
-             if (htab->srelplt != NULL)
+             if (ehtab->srelplt != NULL)
                {
-                 s = htab->srelplt->output_section;
+                 s = ehtab->srelplt->output_section;
                  dyn.d_un.d_val -= s->size;
                }
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
+
+           case DT_TLSDESC_PLT:
+             s = htab->root.splt;
+             dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset
+                               + htab->dt_tlsdesc_plt);
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           case DT_TLSDESC_GOT:
+             s = htab->root.sgot;
+             dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset
+                               + htab->dt_tlsdesc_got);
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
            }
        }
 
       /* Fill in the first entry in the procedure linkage table.  */
-      splt = htab->splt;
+      splt = ehtab->splt;
       if (splt && splt->size > 0)
        {
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              unsigned long insn;
              long offset;
 
-             /* FIXME, sda_base is 65536, it will damage opcode.  */
-             /* insn = PLT_PIC_ENTRY_WORD0 + (((got_offset - sda_base) >> 2) & 0x7fff); */
-             offset = sgot->output_section->vma + sgot->output_offset + 4
-                      - elf_gp (output_bfd);
+             offset = sgotplt->output_section->vma + sgotplt->output_offset + 4
+               - elf_gp (output_bfd);
              insn = PLT0_PIC_ENTRY_WORD0 | ((offset >> 12) & 0xfffff);
              bfd_putb32 (insn, splt->contents);
 
-             /* insn = PLT0_PIC_ENTRY_WORD0 | (((8 - sda_base) >> 2) & 0x7fff) ; */
              /* here has a typo?  */
              insn = PLT0_PIC_ENTRY_WORD1 | (offset & 0xfff);
              bfd_putb32 (insn, splt->contents + 4);
@@ -5257,7 +6484,7 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
              unsigned long addr;
 
              /* addr = .got + 4 */
-             addr = sgot->output_section->vma + sgot->output_offset + 4;
+             addr = sgotplt->output_section->vma + sgotplt->output_offset + 4;
              insn = PLT0_ENTRY_WORD0 | ((addr >> 12) & 0xfffff);
              bfd_putb32 (insn, splt->contents);
 
@@ -5277,21 +6504,46 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
          elf_section_data (splt->output_section)->this_hdr.sh_entsize =
            PLT_ENTRY_SIZE;
        }
+
+      if (htab->dt_tlsdesc_plt)
+       {
+         /* Calculate addresses.  */
+         asection *sgot = sgot = ehtab->sgot;
+         bfd_vma pltgot = sgotplt->output_section->vma
+           + sgotplt->output_offset;
+         bfd_vma tlsdesc_got = sgot->output_section->vma + sgot->output_offset
+           + htab->dt_tlsdesc_got;
+
+         /* Get GP offset.  */
+         pltgot -= elf_gp (output_bfd) - 4; /* PLTGOT[1]  */
+         tlsdesc_got -= elf_gp (output_bfd);
+
+         /* Do relocation.  */
+         dl_tlsdesc_lazy_trampoline[0] += ((1 << 20) - 1) & (tlsdesc_got >> 12);
+         dl_tlsdesc_lazy_trampoline[1] += 0xfff & tlsdesc_got;
+         dl_tlsdesc_lazy_trampoline[4] += ((1 << 20) - 1) & (pltgot >> 12);
+         dl_tlsdesc_lazy_trampoline[5] +=  0xfff & pltgot;
+
+         /* Insert .plt.  */
+         nds32_put_trampoline (splt->contents + htab->dt_tlsdesc_plt,
+                               dl_tlsdesc_lazy_trampoline,
+                               ARRAY_SIZE (dl_tlsdesc_lazy_trampoline));
+       }
     }
 
   /* Fill in the first three entries in the global offset table.  */
-  if (sgot && sgot->size > 0)
+  if (sgotplt && sgotplt->size > 0)
     {
       if (sdyn == NULL)
-       bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+       bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents);
       else
        bfd_put_32 (output_bfd,
                    sdyn->output_section->vma + sdyn->output_offset,
-                   sgot->contents);
-      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
-      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+                   sgotplt->contents);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8);
 
-      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+      elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4;
     }
 
   return TRUE;
@@ -5336,9 +6588,8 @@ nds32_elf_object_p (bfd *abfd)
 
 /* Store the machine number in the flags field.  */
 
-static void
-nds32_elf_final_write_processing (bfd *abfd,
-                                 bfd_boolean linker ATTRIBUTE_UNUSED)
+static bfd_boolean
+nds32_elf_final_write_processing (bfd *abfd)
 {
   unsigned long val;
   static unsigned int cur_mach = 0;
@@ -5375,6 +6626,7 @@ nds32_elf_final_write_processing (bfd *abfd,
 
   elf_elfheader (abfd)->e_flags &= ~EF_NDS_ARCH;
   elf_elfheader (abfd)->e_flags |= val;
+  return _bfd_elf_final_write_processing (abfd);
 }
 
 /* Function to keep NDS32 specific file flags.  */
@@ -5433,7 +6685,7 @@ nds32_check_vec_size (bfd *ibfd)
       /* Get vec_size in file.  */
       unsigned int flag_t;
 
-      nds32_get_section_contents (ibfd, sec_t, &contents);
+      nds32_get_section_contents (ibfd, sec_t, &contents, TRUE);
       flag_t = bfd_get_32 (ibfd, contents);
 
       /* The value could only be 4 or 16.  */
@@ -5443,11 +6695,13 @@ nds32_check_vec_size (bfd *ibfd)
        nds32_vec_size = (flag_t & 0x3);
       else if (nds32_vec_size != (flag_t & 0x3))
        {
-         (*_bfd_error_handler) (_("%B: ISR vector size mismatch"
-                                  " with previous modules, previous %u-byte, current %u-byte"),
-                                ibfd,
-                                nds32_vec_size == 1 ? 4 : nds32_vec_size == 2 ? 16 : 0xffffffff,
-                                (flag_t & 0x3) == 1 ? 4 : (flag_t & 0x3) == 2 ? 16 : 0xffffffff);
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB: ISR vector size mismatch"
+              " with previous modules, previous %u-byte, current %u-byte"),
+            ibfd,
+            nds32_vec_size == 1 ? 4 : nds32_vec_size == 2 ? 16 : 0xffffffff,
+            (flag_t & 0x3) == 1 ? 4 : (flag_t & 0x3) == 2 ? 16 : 0xffffffff);
          return FALSE;
        }
       else
@@ -5462,8 +6716,9 @@ nds32_check_vec_size (bfd *ibfd)
    object file when linking.  */
 
 static bfd_boolean
-nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+nds32_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
+  bfd *obfd = info->output_bfd;
   flagword out_flags;
   flagword in_flags;
   flagword out_16regs;
@@ -5475,6 +6730,10 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   flagword out_fpu_config;
   flagword in_fpu_config;
 
+  /* FIXME: What should be checked when linking shared libraries?  */
+  if ((ibfd->flags & DYNAMIC) != 0)
+    return TRUE;
+
   /* TODO: Revise to use object-attributes instead.  */
   if (!nds32_check_vec_size (ibfd))
     return FALSE;
@@ -5485,140 +6744,157 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   if (bfd_little_endian (ibfd) != bfd_little_endian (obfd))
     {
-      (*_bfd_error_handler)
-       (_("%B: warning: Endian mismatch with previous modules."), ibfd);
+      _bfd_error_handler
+       (_("%pB: warning: endian mismatch with previous modules"), ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
 
-  in_version = elf_elfheader (ibfd)->e_flags & EF_NDS32_ELF_VERSION;
-  if (in_version == E_NDS32_ELF_VER_1_2)
+  /* -B option in objcopy cannot work as expected. e_flags = 0 shall be
+     treat as generic one without checking and merging.  */
+  if (elf_elfheader (ibfd)->e_flags)
     {
-      (*_bfd_error_handler)
-       (_("%B: warning: Older version of object file encountered, "
-          "Please recompile with current tool chain."), ibfd);
-    }
+      in_version = elf_elfheader (ibfd)->e_flags & EF_NDS32_ELF_VERSION;
+      if (in_version == E_NDS32_ELF_VER_1_2)
+       {
+         _bfd_error_handler
+           (_("%pB: warning: older version of object file encountered, "
+              "please recompile with current tool chain"), ibfd);
+       }
 
-  /* We may need to merge V1 and V2 arch object files to V2.  */
-  if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
-      != (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH))
-    {
-      /* Need to convert version.  */
+      /* We may need to merge V1 and V2 arch object files to V2.  */
       if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
-         == E_NDS_ARCH_STAR_RESERVED)
+         != (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH))
        {
+         /* Need to convert version.  */
+         if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
+             == E_NDS_ARCH_STAR_RESERVED)
+           {
+             elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+           }
+         else if ((elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
+                  == E_NDS_ARCH_STAR_V3_M
+                  && (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)
+                  == E_NDS_ARCH_STAR_V3_0)
+           {
+             elf_elfheader (ibfd)->e_flags =
+               (elf_elfheader (ibfd)->e_flags & (~EF_NDS_ARCH))
+               | E_NDS_ARCH_STAR_V3_0;
+           }
+         else if ((elf_elfheader (obfd)->e_flags & EF_NDS_ARCH)
+                  == E_NDS_ARCH_STAR_V0_9
+                  || (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
+                  > (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH))
+           {
+             elf_elfheader (obfd)->e_flags =
+               convert_e_flags (elf_elfheader (obfd)->e_flags,
+                                (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH));
+           }
+         else
+           {
+             elf_elfheader (ibfd)->e_flags =
+               convert_e_flags (elf_elfheader (ibfd)->e_flags,
+                                (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH));
+           }
+       }
+
+      /* Extract some flags.  */
+      in_flags = elf_elfheader (ibfd)->e_flags
+       & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION
+            | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF));
+
+      /* The following flags need special treatment.  */
+      in_16regs = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_REDUCED_REGS;
+      in_no_mac = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_NO_MAC_INST;
+      in_fpu_config = elf_elfheader (ibfd)->e_flags & E_NDS32_FPU_REG_CONF;
+
+      /* Extract some flags.  */
+      out_flags = elf_elfheader (obfd)->e_flags
+       & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION
+            | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF));
+
+      /* The following flags need special treatment.  */
+      out_16regs = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_REDUCED_REGS;
+      out_no_mac = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_NO_MAC_INST;
+      out_fpu_config = elf_elfheader (obfd)->e_flags & E_NDS32_FPU_REG_CONF;
+      out_version = elf_elfheader (obfd)->e_flags & EF_NDS32_ELF_VERSION;
+      if (!elf_flags_init (obfd))
+       {
+         /* If the input is the default architecture then do not
+            bother setting the flags for the output architecture,
+            instead allow future merges to do this.  If no future
+            merges ever set these flags then they will retain their
+            unitialised values, which surprise surprise, correspond
+            to the default values.  */
+         if (bfd_get_arch_info (ibfd)->the_default)
+           return TRUE;
+
+         elf_flags_init (obfd) = TRUE;
          elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+
+         if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+             && bfd_get_arch_info (obfd)->the_default)
+           {
+             return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+                                       bfd_get_mach (ibfd));
+           }
+
+         return TRUE;
        }
-      else if ((elf_elfheader (obfd)->e_flags & EF_NDS_ARCH) == E_NDS_ARCH_STAR_V0_9
-              || (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH)
-                 > (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH))
+
+      /* Check flag compatibility.  */
+      if ((in_flags & EF_NDS_ABI) != (out_flags & EF_NDS_ABI))
        {
-         elf_elfheader (obfd)->e_flags =
-           convert_e_flags (elf_elfheader (obfd)->e_flags,
-                            (elf_elfheader (ibfd)->e_flags & EF_NDS_ARCH));
+         _bfd_error_handler
+           (_("%pB: error: ABI mismatch with previous modules"), ibfd);
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
        }
-      else
+
+      if ((in_flags & EF_NDS_ARCH) != (out_flags & EF_NDS_ARCH))
        {
-         elf_elfheader (ibfd)->e_flags =
-           convert_e_flags (elf_elfheader (ibfd)->e_flags,
-                            (elf_elfheader (obfd)->e_flags & EF_NDS_ARCH));
-       }
-    }
-
-  /* Extract some flags.  */
-  in_flags = elf_elfheader (ibfd)->e_flags
-            & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION
-                 | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF));
-
-  /* The following flags need special treatment.  */
-  in_16regs = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_REDUCED_REGS;
-  in_no_mac = elf_elfheader (ibfd)->e_flags & E_NDS32_HAS_NO_MAC_INST;
-  in_fpu_config = elf_elfheader (ibfd)->e_flags & E_NDS32_FPU_REG_CONF;
-
-  /* Extract some flags.  */
-  out_flags = elf_elfheader (obfd)->e_flags
-             & (~(E_NDS32_HAS_REDUCED_REGS | EF_NDS32_ELF_VERSION
-                  | E_NDS32_HAS_NO_MAC_INST | E_NDS32_FPU_REG_CONF));
-
-  /* The following flags need special treatment.  */
-  out_16regs = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_REDUCED_REGS;
-  out_no_mac = elf_elfheader (obfd)->e_flags & E_NDS32_HAS_NO_MAC_INST;
-  out_fpu_config = elf_elfheader (obfd)->e_flags & E_NDS32_FPU_REG_CONF;
-  out_version = elf_elfheader (obfd)->e_flags & EF_NDS32_ELF_VERSION;
-  if (!elf_flags_init (obfd))
-    {
-      /* If the input is the default architecture then do not
-        bother setting the flags for the output architecture,
-        instead allow future merges to do this.  If no future
-        merges ever set these flags then they will retain their
-        unitialised values, which surprise surprise, correspond
-        to the default values.  */
-      if (bfd_get_arch_info (ibfd)->the_default)
-       return TRUE;
+         if (((in_flags & EF_NDS_ARCH) != E_N1_ARCH))
+           {
+             _bfd_error_handler
+               (_("%pB: error: instruction set mismatch with previous modules"),
+                ibfd);
 
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+       }
 
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-         && bfd_get_arch_info (obfd)->the_default)
+      /* When linking with V1.2 and V1.3 objects together the output is V1.2.
+        and perf ext1 and DIV are mergerd to perf ext1.  */
+      if (in_version == E_NDS32_ELF_VER_1_2 || out_version == E_NDS32_ELF_VER_1_2)
        {
-         return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
-                                   bfd_get_mach (ibfd));
+         elf_elfheader (obfd)->e_flags =
+           (in_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
+           | (out_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
+           | (((in_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
+              ?  E_NDS32_HAS_EXT_INST : 0)
+           | (((out_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
+              ?  E_NDS32_HAS_EXT_INST : 0)
+           | (in_16regs & out_16regs) | (in_no_mac & out_no_mac)
+           | ((in_version > out_version) ? out_version : in_version);
        }
-
-      return TRUE;
-    }
-
-  /* Check flag compatibility.  */
-  if ((in_flags & EF_NDS_ABI) != (out_flags & EF_NDS_ABI))
-    {
-      (*_bfd_error_handler)
-       (_("%B: error: ABI mismatch with previous modules."), ibfd);
-
-      bfd_set_error (bfd_error_bad_value);
-      return FALSE;
-    }
-
-  if ((in_flags & EF_NDS_ARCH) != (out_flags & EF_NDS_ARCH))
-    {
-      if (((in_flags & EF_NDS_ARCH) != E_N1_ARCH))
+      else
        {
-         (*_bfd_error_handler)
-           (_("%B: error: Instruction set mismatch with previous modules."), ibfd);
+         if (in_version != out_version)
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%pB: warning: incompatible elf-versions %s and %s"),
+              ibfd, nds32_elfver_strtab[out_version],
+              nds32_elfver_strtab[in_version]);
 
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         elf_elfheader (obfd)->e_flags = in_flags | out_flags
+           | (in_16regs & out_16regs) | (in_no_mac & out_no_mac)
+           | (in_fpu_config > out_fpu_config ? in_fpu_config : out_fpu_config)
+           | (in_version > out_version ?  out_version : in_version);
        }
     }
 
-  /* When linking with V1.2 and V1.3 objects together the output is V1.2.
-     and perf ext1 and DIV are mergerd to perf ext1.  */
-  if (in_version == E_NDS32_ELF_VER_1_2 || out_version == E_NDS32_ELF_VER_1_2)
-    {
-      elf_elfheader (obfd)->e_flags =
-       (in_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
-       | (out_flags & (~(E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
-       | (((in_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
-          ?  E_NDS32_HAS_EXT_INST : 0)
-       | (((out_flags & (E_NDS32_HAS_EXT_INST | E_NDS32_HAS_DIV_INST)))
-          ?  E_NDS32_HAS_EXT_INST : 0)
-       | (in_16regs & out_16regs) | (in_no_mac & out_no_mac)
-       | ((in_version > out_version) ? out_version : in_version);
-    }
-  else
-    {
-      if (in_version != out_version)
-       (*_bfd_error_handler) (_("%B: warning: Incompatible elf-versions %s and  %s."),
-                                ibfd, nds32_elfver_strtab[out_version],
-                                nds32_elfver_strtab[in_version]);
-
-      elf_elfheader (obfd)->e_flags = in_flags | out_flags
-       | (in_16regs & out_16regs) | (in_no_mac & out_no_mac)
-       | (in_fpu_config > out_fpu_config ? in_fpu_config : out_fpu_config)
-       | (in_version > out_version ?  out_version : in_version);
-    }
-
   return TRUE;
 }
 
@@ -5680,131 +6956,76 @@ nds32_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info,
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
 
-static bfd_boolean
-nds32_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, asection *sec,
-                        const Elf_Internal_Rela *relocs)
+static enum elf_nds32_tls_type
+get_tls_type (enum elf_nds32_reloc_type r_type,
+             struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
 {
-  /* Update the got entry reference counts for the section being removed.  */
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
-
-  elf_section_data (sec)->local_dynrel = NULL;
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+  enum elf_nds32_tls_type tls_type;
 
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
+  switch (r_type)
     {
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h = NULL;
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      if (r_symndx >= symtab_hdr->sh_info)
-       {
-         /* External symbol.  */
-         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-       }
+    case R_NDS32_TLS_LE_HI20:
+    case R_NDS32_TLS_LE_LO12:
+      tls_type = GOT_TLS_LE;
+      break;
+    case R_NDS32_TLS_IE_HI20:
+    case R_NDS32_TLS_IE_LO12S2:
+    case R_NDS32_TLS_IE_LO12:
+      tls_type = GOT_TLS_IE;
+      break;
+    case R_NDS32_TLS_IEGP_HI20:
+    case R_NDS32_TLS_IEGP_LO12:
+    case R_NDS32_TLS_IEGP_LO12S2:
+      tls_type = GOT_TLS_IEGP;
+      break;
+    case R_NDS32_TLS_DESC_HI20:
+    case R_NDS32_TLS_DESC_LO12:
+    case R_NDS32_TLS_DESC_ADD:
+    case R_NDS32_TLS_DESC_FUNC:
+    case R_NDS32_TLS_DESC_CALL:
+      tls_type = GOT_TLS_DESC;
+      break;
+    default:
+      tls_type = GOT_NORMAL;
+      break;
+    }
 
-      switch (ELF32_R_TYPE (rel->r_info))
-       {
-       case R_NDS32_GOT_HI20:
-       case R_NDS32_GOT_LO12:
-       case R_NDS32_GOT_LO15:
-       case R_NDS32_GOT_LO19:
-       case R_NDS32_GOT17S2_RELA:
-       case R_NDS32_GOT15S2_RELA:
-       case R_NDS32_GOTOFF:
-       case R_NDS32_GOTOFF_HI20:
-       case R_NDS32_GOTOFF_LO12:
-       case R_NDS32_GOTOFF_LO15:
-       case R_NDS32_GOTOFF_LO19:
-       case R_NDS32_GOT20:
-       case R_NDS32_GOTPC_HI20:
-       case R_NDS32_GOTPC_LO12:
-       case R_NDS32_GOTPC20:
-         if (h != NULL)
-           {
-             if (h->got.refcount > 0)
-               h->got.refcount--;
-           }
-         else
-           {
-             if (local_got_refcounts && local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx]--;
-           }
-         break;
+  return tls_type;
+}
 
-       case R_NDS32_16_RELA:
-       case R_NDS32_20_RELA:
-       case R_NDS32_5_RELA:
-       case R_NDS32_32_RELA:
-       case R_NDS32_HI20_RELA:
-       case R_NDS32_LO12S3_RELA:
-       case R_NDS32_LO12S2_RELA:
-       case R_NDS32_LO12S2_DP_RELA:
-       case R_NDS32_LO12S2_SP_RELA:
-       case R_NDS32_LO12S1_RELA:
-       case R_NDS32_LO12S0_RELA:
-       case R_NDS32_LO12S0_ORI_RELA:
-       case R_NDS32_SDA16S3_RELA:
-       case R_NDS32_SDA17S2_RELA:
-       case R_NDS32_SDA18S1_RELA:
-       case R_NDS32_SDA19S0_RELA:
-       case R_NDS32_SDA15S3_RELA:
-       case R_NDS32_SDA15S2_RELA:
-       case R_NDS32_SDA12S2_DP_RELA:
-       case R_NDS32_SDA12S2_SP_RELA:
-       case R_NDS32_SDA15S1_RELA:
-       case R_NDS32_SDA15S0_RELA:
-       case R_NDS32_SDA_FP7U2_RELA:
-       case R_NDS32_15_PCREL_RELA:
-       case R_NDS32_17_PCREL_RELA:
-       case R_NDS32_25_PCREL_RELA:
-         if (h != NULL)
-           {
-             struct elf_nds32_link_hash_entry *eh;
-             struct elf_nds32_dyn_relocs **pp;
-             struct elf_nds32_dyn_relocs *p;
+/* Ensure that we have allocated bookkeeping structures for ABFD's local
+   symbols.  */
 
-             if (!info->shared && h->plt.refcount > 0)
-               h->plt.refcount -= 1;
+static bfd_boolean
+elf32_nds32_allocate_local_sym_info (bfd *abfd)
+{
+  if (elf_local_got_refcounts (abfd) == NULL)
+    {
+      bfd_size_type num_syms;
+      bfd_size_type size;
+      char *data;
+
+      num_syms = elf_tdata (abfd)->symtab_hdr.sh_info;
+      /* This space is for got_refcounts, got_tls_type, tlsdesc_gotent, and
+        gp_offset.  The details can refer to struct elf_nds32_obj_tdata.  */
+      size = num_syms * (sizeof (bfd_signed_vma) + sizeof (char)
+                        + sizeof (bfd_vma) + sizeof (int)
+                        + sizeof (bfd_boolean) + sizeof (bfd_vma));
+      data = bfd_zalloc (abfd, size);
+      if (data == NULL)
+       return FALSE;
 
-             eh = (struct elf_nds32_link_hash_entry *) h;
+      elf_local_got_refcounts (abfd) = (bfd_signed_vma *) data;
+      data += num_syms * sizeof (bfd_signed_vma);
 
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-               if (p->sec == sec)
-                 {
-                   if (ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA
-                       || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA
-                       || ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA)
-                     p->pc_count -= 1;
-                   p->count -= 1;
-                   if (p->count == 0)
-                     *pp = p->next;
-                   break;
-                 }
-           }
-         break;
+      elf32_nds32_local_got_tls_type (abfd) = (char *) data;
+      data += num_syms * sizeof (char);
 
-       case R_NDS32_9_PLTREL:
-       case R_NDS32_25_PLTREL:
-         if (h != NULL)
-           {
-             if (h->plt.refcount > 0)
-               h->plt.refcount--;
-           }
-         break;
+      elf32_nds32_local_tlsdesc_gotent (abfd) = (bfd_vma *) data;
+      data += num_syms * sizeof (bfd_vma);
 
-       default:
-         break;
-       }
+      elf32_nds32_local_gp_offset (abfd) = (int *) data;
+      data += num_syms * sizeof (int);
     }
 
   return TRUE;
@@ -5822,11 +7043,25 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
+  struct elf_link_hash_table *ehtab;
   struct elf_nds32_link_hash_table *htab;
   bfd *dynobj;
   asection *sreloc = NULL;
 
-  if (info->relocatable)
+  /* No need for relocation if relocatable already.  */
+  if (bfd_link_relocatable (info))
+    {
+      elf32_nds32_check_relax_group (abfd, sec);
+      return TRUE;
+    }
+
+  /* Don't do anything special with non-loaded, non-alloced sections.
+     In particular, any relocs in such sections should not affect GOT
+     and PLT reference counting (ie. we don't allow them to create GOT
+     or PLT entries), there's no possibility or desire to optimize TLS
+     relocs, and there's not much point in propagating relocs to shared
+     libs that the dynamic linker won't relocate.  */
+  if ((sec->flags & SEC_ALLOC) == 0)
     return TRUE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -5836,6 +7071,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   if (!elf_bad_symtab (abfd))
     sym_hashes_end -= symtab_hdr->sh_info;
 
+  ehtab = elf_hash_table (info);
   htab = nds32_elf_hash_table (info);
   dynobj = htab->root.dynobj;
 
@@ -5845,6 +7081,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;
+      enum elf_nds32_tls_type tls_type, old_tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -5858,8 +7095,11 @@ 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.  */
-      if (htab->sgot == NULL)
+      /* Create .got section if necessary.
+        Some relocs require a global offset table.  We create
+        got section here, since these relocation need a got section
+        and if it is not created yet.  */
+      if (ehtab->sgot == NULL)
        {
          switch (r_type)
            {
@@ -5878,6 +7118,14 @@ 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_LO12:
+           case R_NDS32_TLS_IE_LO12S2:
+           case R_NDS32_TLS_IEGP_HI20:
+           case R_NDS32_TLS_IEGP_LO12:
+           case R_NDS32_TLS_IEGP_LO12S2:
+           case R_NDS32_TLS_DESC_HI20:
+           case R_NDS32_TLS_DESC_LO12:
              if (dynobj == NULL)
                htab->root.dynobj = dynobj = abfd;
              if (!create_got_section (dynobj, info))
@@ -5889,6 +7137,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            }
        }
 
+      /* Check relocation type.  */
       switch ((int) r_type)
        {
        case R_NDS32_GOT_HI20:
@@ -5896,30 +7145,55 @@ 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:
-         if (h != NULL)
-           h->got.refcount += 1;
+       case R_NDS32_TLS_LE_HI20:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12:
+       case R_NDS32_TLS_IE_LO12S2:
+       case R_NDS32_TLS_IEGP_HI20:
+       case R_NDS32_TLS_IEGP_LO12:
+       case R_NDS32_TLS_IEGP_LO12S2:
+       case R_NDS32_TLS_DESC_HI20:
+       case R_NDS32_TLS_DESC_LO12:
+         tls_type = get_tls_type (r_type, h);
+         if (h)
+           {
+             if (tls_type != GOT_TLS_LE)
+               h->got.refcount += 1;
+             old_tls_type = elf32_nds32_hash_entry (h)->tls_type;
+           }
          else
            {
-             bfd_signed_vma *local_got_refcounts;
+             /* This is a global offset table entry for a local symbol.  */
+             if (!elf32_nds32_allocate_local_sym_info (abfd))
+               return FALSE;
 
-             /* This is a global offset table entry for a local
-                symbol.  */
-             local_got_refcounts = elf_local_got_refcounts (abfd);
-             if (local_got_refcounts == NULL)
-               {
-                 bfd_size_type size;
+             BFD_ASSERT (r_symndx < symtab_hdr->sh_info);
+             if (tls_type != GOT_TLS_LE)
+               elf_local_got_refcounts (abfd)[r_symndx] += 1;
+             old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx];
+           }
 
-                 size = symtab_hdr->sh_info;
-                 size *= sizeof (bfd_signed_vma);
-                 local_got_refcounts = (bfd_signed_vma *) bfd_zalloc (abfd, size);
-                 if (local_got_refcounts == NULL)
-                   return FALSE;
-                 elf_local_got_refcounts (abfd) = local_got_refcounts;
-               }
-             local_got_refcounts[r_symndx] += 1;
+         /* We would 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;
+
+         /* DESC to IE/IEGP if link to executable.  */
+         if ((tls_type & (GOT_TLS_DESC | GOT_TLS_IEGP))
+             && (bfd_link_executable (info)))
+           tls_type |= (bfd_link_pie (info) ? GOT_TLS_IEGP : GOT_TLS_IE);
+
+         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:
@@ -5941,9 +7215,11 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (h == NULL)
            continue;
 
-         if (h->forced_local)
+         if (h->forced_local
+             || (bfd_link_pie (info) && h->def_regular))
            break;
 
+         elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL;
          h->needs_plt = 1;
          h->plt.refcount += 1;
          break;
@@ -5975,7 +7251,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_NDS32_17_PCREL_RELA:
        case R_NDS32_25_PCREL_RELA:
 
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              h->non_got_ref = 1;
              h->plt.refcount += 1;
@@ -5997,7 +7273,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             If on the other hand, we are creating an executable, we may need
             to keep relocations for symbols satisfied by a dynamic library
             if we manage to avoid copy relocs for the symbol.  */
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (sec->flags & SEC_ALLOC) != 0
               && ((r_type != R_NDS32_25_PCREL_RELA
                    && r_type != R_NDS32_15_PCREL_RELA
@@ -6008,14 +7284,14 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                       && (!info->symbolic
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
-             || (!info->shared
+             || (!bfd_link_pic (info)
                  && (sec->flags & SEC_ALLOC) != 0
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
            {
-             struct elf_nds32_dyn_relocs *p;
-             struct elf_nds32_dyn_relocs **head;
+             struct elf_dyn_relocs *p;
+             struct elf_dyn_relocs **head;
 
              if (dynobj == NULL)
                htab->root.dynobj = dynobj = abfd;
@@ -6034,7 +7310,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    return FALSE;
 
                  BFD_ASSERT (strncmp (name, ".rela", 5) == 0
-                             && strcmp (bfd_get_section_name (abfd, sec),
+                             && strcmp (bfd_section_name (sec),
                                         name + 5) == 0);
 
                  sreloc = bfd_get_section_by_name (dynobj, name);
@@ -6048,8 +7324,8 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                      if ((sec->flags & SEC_ALLOC) != 0)
                        flags |= SEC_ALLOC | SEC_LOAD;
                      if (sreloc == NULL
-                         || !bfd_set_section_flags (dynobj, sreloc, flags)
-                         || !bfd_set_section_alignment (dynobj, sreloc, 2))
+                         || !bfd_set_section_flags (sreloc, flags)
+                         || !bfd_set_section_alignment (sreloc, 2))
                        return FALSE;
 
                      elf_section_type (sreloc) = SHT_RELA;
@@ -6060,10 +7336,11 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* If this is a global symbol, we count the number of
                 relocations we need for this symbol.  */
              if (h != NULL)
-               head = &((struct elf_nds32_link_hash_entry *) h)->dyn_relocs;
+               head = &h->dyn_relocs;
              else
                {
                  asection *s;
+                 void *vpp;
 
                  Elf_Internal_Sym *isym;
                  isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx);
@@ -6075,15 +7352,15 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  if (s == NULL)
                    return FALSE;
 
-                 head = ((struct elf_nds32_dyn_relocs **)
-                       &elf_section_data (s)->local_dynrel);
+                 vpp = &elf_section_data (s)->local_dynrel;
+                 head = (struct elf_dyn_relocs **) vpp;
                }
 
              p = *head;
              if (p == NULL || p->sec != sec)
                {
-                 bfd_size_type amt = sizeof (*p);
-                 p = (struct elf_nds32_dyn_relocs *) bfd_alloc (dynobj, amt);
+                 size_t amt = sizeof (*p);
+                 p = (struct elf_dyn_relocs *) bfd_alloc (dynobj, amt);
                  if (p == NULL)
                    return FALSE;
                  p->next = *head;
@@ -6094,9 +7371,48 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                }
 
              p->count += 1;
+
+             /* Since eh_frame is readonly, R_NDS32_32_RELA
+                reloc for eh_frame will cause shared library has
+                TEXTREL entry in the dynamic section. This lead glibc
+                testsuites to failure (bug-13092) and cause kernel fail
+                (bug-11819).  I think the best solution is to replace
+                absolute reloc with pc relative reloc in the eh_frame.
+                To do that, we need to support the following issues:
+
+                === For GCC ===
+                * gcc/config/nds32/nds32.h: Define
+                ASM_PREFERRED_EH_DATA_FORMAT to encode DW_EH_PE_pcrel
+                and DW_EH_PE_sdata4 into DWARF exception header when
+                option have '-fpic'.
+
+                === For binutils ===
+                * bfd/: Define new reloc R_NDS32_32_PCREL_RELA.
+                * gas/config/tc-nds32.h: Define DIFF_EXPR_OK. This
+                may break our nds DIFF mechanism, therefore, we
+                must disable all linker relaxations to ensure
+                correctness.
+                * gas/config/tc-nds32.c (nds32_apply_fix): Replace
+                R_NDS32_32_RELA with R_NDS32_32_PCREL_RELA, and
+                do the necessary modification.
+
+                Unfortunately, it still have some problems for nds32
+                to support pc relative reloc in the eh_frame. So I use
+                another solution to fix this issue.
+
+                However, I find that ld always emit TEXTREL marker for
+                R_NDS32_NONE relocs in rel.dyn. These none relocs are
+                correspond to R_NDS32_32_RELA for .eh_frame section.
+                It means that we always reserve redundant entries of rel.dyn
+                for these relocs which actually do nothing in dynamic linker.
+
+                Therefore, we regard these relocs as pc relative relocs
+                here and increase the pc_count.  */
              if (ELF32_R_TYPE (rel->r_info) == R_NDS32_25_PCREL_RELA
                  || ELF32_R_TYPE (rel->r_info) == R_NDS32_15_PCREL_RELA
-                 || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA)
+                 || ELF32_R_TYPE (rel->r_info) == R_NDS32_17_PCREL_RELA
+                 || (r_type == R_NDS32_32_RELA
+                     && strcmp (sec->name, ".eh_frame") == 0))
                p->pc_count += 1;
            }
          break;
@@ -6147,8 +7463,7 @@ write_uleb128 (bfd_byte *p, unsigned int val)
 
 static bfd_signed_vma
 calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
-                 Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr,
-                 int *pic_ext_target)
+                 Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr)
 {
   bfd_signed_vma foff;
   bfd_vma symval, addend;
@@ -6177,7 +7492,6 @@ calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
     {
       unsigned long indx;
       struct elf_link_hash_entry *h;
-      bfd *owner;
 
       /* An external symbol.  */
       indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
@@ -6190,9 +7504,6 @@ calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
           symbol.  Just ignore it--it will be caught by the
           regular reloc processing.  */
        return 0;
-      owner = h->root.u.def.section->owner;
-      if (owner && (elf_elfheader (owner)->e_flags & E_NDS32_HAS_PIC))
-       *pic_ext_target = 1;
 
       if (h->root.u.def.section->flags & SEC_MERGE)
        {
@@ -6215,84 +7526,8 @@ calculate_offset (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
          - (irel->r_offset + sec->output_section->vma + sec->output_offset));
   return foff;
 }
-
-static bfd_vma
-calculate_plt_memory_address (bfd *abfd, struct bfd_link_info *link_info,
-                             Elf_Internal_Sym *isymbuf,
-                             Elf_Internal_Rela *irel,
-                             Elf_Internal_Shdr *symtab_hdr)
-{
-  bfd_vma symval;
-
-  if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
-    {
-      Elf_Internal_Sym *isym;
-      asection *sym_sec;
-      /* A local symbol.  */
-      isym = isymbuf + ELF32_R_SYM (irel->r_info);
-
-      if (isym->st_shndx == SHN_UNDEF)
-       sym_sec = bfd_und_section_ptr;
-      else if (isym->st_shndx == SHN_ABS)
-       sym_sec = bfd_abs_section_ptr;
-      else if (isym->st_shndx == SHN_COMMON)
-       sym_sec = bfd_com_section_ptr;
-      else
-       sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
-      symval = isym->st_value + sym_sec->output_section->vma
-              + sym_sec->output_offset;
-    }
-  else
-    {
-      unsigned long indx;
-      struct elf_link_hash_entry *h;
-      struct elf_nds32_link_hash_table *htab;
-      asection *splt;
-
-      /* An external symbol.  */
-      indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-      h = elf_sym_hashes (abfd)[indx];
-      BFD_ASSERT (h != NULL);
-      htab = nds32_elf_hash_table (link_info);
-      splt = htab->splt;
-
-      while (h->root.type == bfd_link_hash_indirect
-            || h->root.type == bfd_link_hash_warning)
-       h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-      if (h->plt.offset == (bfd_vma) - 1)
-       {
-         if (h->root.type != bfd_link_hash_defined
-             && h->root.type != bfd_link_hash_defweak)
-           /* This appears to be a reference to an undefined
-            * symbol.  Just ignore it--it will be caught by the
-            * regular reloc processing.  */
-           return 0;
-         symval = (h->root.u.def.value
-                   + h->root.u.def.section->output_section->vma
-                   + h->root.u.def.section->output_offset);
-       }
-      else
-       symval = splt->output_section->vma + h->plt.offset;
-    }
-
-  return symval;
-}
-
-static bfd_signed_vma
-calculate_plt_offset (bfd *abfd, asection *sec, struct bfd_link_info *link_info,
-                     Elf_Internal_Sym *isymbuf, Elf_Internal_Rela *irel,
-                     Elf_Internal_Shdr *symtab_hdr)
-{
-  bfd_vma foff;
-  if ((foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel,
-                                           symtab_hdr)) == 0)
-    return 0;
-  else
-    return foff - (irel->r_offset
-                  + sec->output_section->vma + sec->output_offset);
-}
 \f
+
 /* Convert a 32-bit instruction to 16-bit one.
    INSN is the input 32-bit instruction, INSN16 is the output 16-bit
    instruction.  If INSN_TYPE is not NULL, it the CGEN instruction
@@ -6303,7 +7538,7 @@ nds32_convert_32_to_16_alu1 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
                             int *pinsn_type)
 {
   uint16_t insn16 = 0;
-  int insn_type;
+  int insn_type = 0;
   unsigned long mach = bfd_get_mach (abfd);
 
   if (N32_SH5 (insn) != 0)
@@ -6518,7 +7753,7 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
 {
   int op6;
   uint16_t insn16 = 0;
-  int insn_type;
+  int insn_type = 0;
   unsigned long mach = bfd_get_mach (abfd);
 
   /* Decode 32-bit instruction.  */
@@ -6602,7 +7837,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 +7963,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 +7978,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
@@ -6828,7 +8066,7 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
       if (!IS_WITHIN_S (N32_IMM14S (insn), 8))
        goto done;
 
-      if ((insn & __BIT (14)) == 0)
+      if ((insn & N32_BIT (14)) == 0)
        {
          /* N32_BR1_BEQ */
          if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5
@@ -6863,7 +8101,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,15 +8115,16 @@ 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;
            }
          break;
 
-       case N32_BR2_IFCALL:
-         if (IS_WITHIN_U (N32_IMM16S (insn), 9))
+       case N32_BR2_SOP0:
+         if (__GF (insn, 20, 5) == 0 && IS_WITHIN_U (N32_IMM16S (insn), 9))
            {
              insn16 = N16_TYPE9 (IFCALL9, N32_IMM16S (insn));
              insn_type = NDS32_INSN_IFCALL9;
@@ -6894,7 +8134,7 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
       break;
 
     case N32_OP6_JI:
-      if ((insn & __BIT (24)) == 0)
+      if ((insn & N32_BIT (24)) == 0)
        {
          /* N32_JI_J */
          if (IS_WITHIN_S (N32_IMM24S (insn), 8))
@@ -6958,7 +8198,7 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
       goto done;
     }
 
-done:
+ done:
   /* Bit-15 of insn16 should be set for a valid instruction.  */
   if ((insn16 & 0x8000) == 0)
     return 0;
@@ -7026,71 +8266,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 +8356,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;
@@ -7113,7 +8370,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       insn = N32_TYPE2 (SLTI, REG_TA, N16_RT4 (insn16), N16_IMM5U (insn16));
       goto done;
     case 0x34:                 /* beqzs8, bnezs8 */
-      if (insn16 & __BIT (8))
+      if (insn16 & N32_BIT (8))
        insn = N32_BR2 (BNEZ, REG_TA, N16_IMM8S (insn16));
       else
        insn = N32_BR2 (BEQZ, REG_TA, N16_IMM8S (insn16));
@@ -7125,37 +8382,42 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       goto done;
 
     case 0x3c:                 /* ifcall9 */
-      insn = N32_BR2 (IFCALL, 0, N16_IMM9U (insn16));
+      insn = N32_BR2 (SOP0, 0, N16_IMM9U (insn16));
       goto done;
     case 0x3d:                 /* movpi45 */
       insn = N32_TYPE1 (MOVI, N16_RT4 (insn16), N16_IMM5U (insn16) + 16);
       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 +8440,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 +8455,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));
@@ -7208,7 +8470,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
   switch (__GF (insn16, 11, 4))
     {
     case 0x7:                  /* lwi37.fp/swi37.fp */
-      if (insn16 & __BIT (7))  /* swi37.fp */
+      if (insn16 & N32_BIT (7))        /* swi37.fp */
        insn = N32_TYPE2 (SWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16));
       else                     /* lwi37.fp */
        insn = N32_TYPE2 (LWI, N16_RT38 (insn16), REG_FP, N16_IMM7U (insn16));
@@ -7225,7 +8487,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       else
        insn = N32_BR1 (BEQ, N16_RT38 (insn16), REG_R5, N16_IMM8S (insn16));
       goto done;
-    case 0xb:                  /* bnes38 and others */
+    case 0xb:                  /* bnes38 and others */
       if (N16_RT38 (insn16) == 5)
        {
          switch (__GF (insn16, 5, 3))
@@ -7258,7 +8520,7 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       goto done;
     }
 
-done:
+ done:
   if (insn & 0x80000000)
     return 0;
 
@@ -7267,6 +8529,7 @@ done:
   return 1;
 }
 \f
+
 static bfd_boolean
 is_sda_access_insn (unsigned long insn)
 {
@@ -7311,7 +8574,7 @@ turn_insn_to_sda_access (uint32_t insn, bfd_signed_vma type, uint32_t *pinsn)
          break;
        case N32_OP6_LBSI:
          /* lbsi.gp */
-         oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), __BIT (19));
+         oinsn = N32_TYPE1 (LBGP, N32_RT5 (insn), N32_BIT (19));
          break;
        case N32_OP6_SBI:
          /* sbi.gp */
@@ -7319,7 +8582,7 @@ turn_insn_to_sda_access (uint32_t insn, bfd_signed_vma type, uint32_t *pinsn)
          break;
        case N32_OP6_ORI:
          /* addi.gp */
-         oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), __BIT (19));
+         oinsn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19));
          break;
        }
       break;
@@ -7333,11 +8596,11 @@ turn_insn_to_sda_access (uint32_t insn, bfd_signed_vma type, uint32_t *pinsn)
          break;
        case N32_OP6_LHSI:
          /* lhsi.gp */
-         oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (18));
+         oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (18));
          break;
        case N32_OP6_SHI:
          /* shi.gp */
-         oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), __BIT (19));
+         oinsn = N32_TYPE1 (HWGP, N32_RT5 (insn), N32_BIT (19));
          break;
        }
       break;
@@ -7482,42 +8745,6 @@ calculate_memory_address (bfd *abfd, Elf_Internal_Rela *irel,
   return foff;
 }
 
-static bfd_vma
-calculate_got_memory_address (bfd *abfd, struct bfd_link_info *link_info,
-                             Elf_Internal_Rela *irel,
-                             Elf_Internal_Shdr *symtab_hdr)
-{
-  int symndx;
-  bfd_vma *local_got_offsets;
-  /* Get the value of the symbol referred to by the reloc.  */
-  struct elf_link_hash_entry *h;
-  struct elf_nds32_link_hash_table *htab = nds32_elf_hash_table (link_info);
-
-  /* An external symbol.  */
-  symndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-  h = elf_sym_hashes (abfd)[symndx];
-  while (h->root.type == bfd_link_hash_indirect
-        || h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-  if (symndx >= 0)
-    {
-      BFD_ASSERT (h != NULL);
-      return htab->sgot->output_section->vma + htab->sgot->output_offset
-            + h->got.offset;
-    }
-  else
-    {
-      local_got_offsets = elf_local_got_offsets (abfd);
-      BFD_ASSERT (local_got_offsets != NULL);
-      return htab->sgot->output_section->vma + htab->sgot->output_offset
-            + local_got_offsets[ELF32_R_SYM (irel->r_info)];
-    }
-
-  /* The _GLOBAL_OFFSET_TABLE_ may be undefweak(or should be?).  */
-  /* The check of h->root.type is passed.  */
-}
-
 static int
 is_16bit_NOP (bfd *abfd ATTRIBUTE_UNUSED,
              asection *sec, Elf_Internal_Rela *rel)
@@ -7553,7 +8780,6 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
   bfd_vma mem_addr;
   uint32_t insn = 0;
   Elf_Internal_Rela *pc_rel;
-  int pic_ext_target = 0;
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Sym *isymbuf = NULL;
   int convert_type;
@@ -7564,7 +8790,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
 
   offset = reloc->r_offset;
 
-  if (!nds32_get_section_contents (abfd, sec, &contents))
+  if (!nds32_get_section_contents (abfd, sec, &contents, TRUE))
     return FALSE;
   insn = bfd_getb32 (contents + offset);
 
@@ -7582,7 +8808,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++)
@@ -7592,21 +8818,30 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
          || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PCREL_RELA
          || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_25_PLTREL)
        {
-         off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr,
-                                 &pic_ext_target);
-         if (off > 0xff || off < -0x100 || off == 0)
+         off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr);
+         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 +8859,17 @@ 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);
+         if (off >= ACCURATE_U9BIT_S1 || off <= 0)
+           return FALSE;
+         break;
+       }
     }
 
   return TRUE;
@@ -7669,6 +8912,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 +8941,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++)
@@ -7717,7 +8963,7 @@ static Elf_Internal_Rela *
 find_relocs_at_address_addr (Elf_Internal_Rela *reloc,
                             Elf_Internal_Rela *relocs,
                             Elf_Internal_Rela *irelend,
-                            unsigned char reloc_type,
+                            enum elf_nds32_reloc_type reloc_type,
                             bfd_vma offset_p)
 {
   Elf_Internal_Rela *rel_t = NULL;
@@ -7749,38 +8995,6 @@ find_relocs_at_address_addr (Elf_Internal_Rela *reloc,
   return find_relocs_at_address (rel_t, relocs, irelend, reloc_type);
 }
 
-static bfd_boolean
-nds32_elf_check_dup_relocs (Elf_Internal_Rela *reloc,
-                           Elf_Internal_Rela *internal_relocs,
-                           Elf_Internal_Rela *irelend,
-                           unsigned char reloc_type)
-{
-  Elf_Internal_Rela *rel_t;
-
-  for (rel_t = reloc;
-       rel_t >= internal_relocs && rel_t->r_offset == reloc->r_offset;
-       rel_t--)
-    if (ELF32_R_TYPE (rel_t->r_info) == reloc_type)
-      {
-       if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info)
-           && rel_t->r_addend == reloc->r_addend)
-         continue;
-       return TRUE;
-      }
-
-  for (rel_t = reloc; rel_t < irelend && rel_t->r_offset == reloc->r_offset;
-       rel_t++)
-    if (ELF32_R_TYPE (rel_t->r_info) == reloc_type)
-      {
-       if (ELF32_R_SYM (rel_t->r_info) == ELF32_R_SYM (reloc->r_info)
-           && rel_t->r_addend == reloc->r_addend)
-         continue;
-       return TRUE;
-      }
-
-  return FALSE;
-}
-
 typedef struct nds32_elf_blank nds32_elf_blank_t;
 struct nds32_elf_blank
 {
@@ -7913,8 +9127,9 @@ insert_nds32_elf_blank (nds32_elf_blank_t **blank_p, bfd_vma addr, bfd_vma len)
 
   if (addr < blank_t->offset + blank_t->size)
     {
-      if (addr > blank_t->offset + blank_t->size)
-       blank_t->size = addr - blank_t->offset;
+      /* Extend the origin blank.  */
+      if (addr + len > blank_t->offset + blank_t->size)
+       blank_t->size = addr + len - blank_t->offset;
     }
   else
     {
@@ -7985,7 +9200,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.  */
@@ -8055,7 +9270,7 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
       if (!(sect->flags & SEC_RELOC))
        continue;
 
-      nds32_get_section_contents (abfd, sect, &contents);
+      nds32_get_section_contents (abfd, sect, &contents, TRUE);
 
       for (irel = internal_relocs; irel < irelend; irel++)
        {
@@ -8066,18 +9281,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 = 0;
 
              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 +9315,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 +9348,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 = _bfd_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;
 
@@ -8133,19 +9365,22 @@ nds32_elf_relax_delete_blanks (bfd *abfd, asection *sec,
              if (p < endp)
                *p |= 0x80;
            }
-done_adjust_diff:
+       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
+                 (_("%pB: error: search_nds32_elf_blank reports wrong node"),
+                  abfd);
 
              /* Mark reloc in deleted portion as NONE.
                 For some relocs like R_NDS32_LABEL that doesn't modify the
@@ -8197,9 +9432,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 +9465,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;
 
            }
        }
@@ -8280,7 +9518,8 @@ done_adjust_diff:
 /* Get the contents of a section.  */
 
 static int
-nds32_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents_p)
+nds32_get_section_contents (bfd *abfd, asection *sec,
+                           bfd_byte **contents_p, bfd_boolean cache)
 {
   /* Get the section contents.  */
   if (elf_section_data (sec)->this_hdr.contents != NULL)
@@ -8289,7 +9528,8 @@ nds32_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents_p)
     {
       if (!bfd_malloc_and_get_section (abfd, sec, contents_p))
        return FALSE;
-      elf_section_data (sec)->this_hdr.contents = *contents_p;
+      if (cache)
+       elf_section_data (sec)->this_hdr.contents = *contents_p;
     }
 
   return TRUE;
@@ -8323,8 +9563,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 +9589,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 = ARRAY_SIZE (sdata_init_range);
 
   if (decide_relax_range)
     return;
@@ -8359,7 +9600,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 +9621,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,5819 +9637,4356 @@ relax_range_measurement (bfd *abfd)
 #define IS_OPTIMIZE(addend)     ((addend) & 0x40000000)
 #define IS_16BIT_ON(addend)     ((addend) & 0x20000000)
 
+static const char * unrecognized_reloc_msg =
+  /* xgettext:c-format */
+  N_("%pB: warning: %s points to unrecognized reloc at %#" PRIx64);
+
+/* 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;
+  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;
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL1",
+                         (uint64_t) 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);
 
-  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 (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;
+  bfd_signed_vma foff;
+
+  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 (is_ITB_BASE_set == 0)
+  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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL2",
+                         (uint64_t) 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);
 
-  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;
+  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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL3",
+                         (uint64_t) 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);
 
-  /* 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 (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);
 
-      if (laddr + seq_len > (bfd_vma) sec->size)
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
+
+      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;
+  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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP1",
+                         (uint64_t) 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);
 
-      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 (foff == 0
+      || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
+
+  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;
+    }
+
+  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 ((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;
+}
 
-         i1_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_INSN16,
-                                                  laddr + i1_offset);
+/* Revert condition branch.  This function does not check if the input
+   instruction is condition branch or not.  */
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+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;
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
+  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 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 < ARRAY_SIZE (checked_types); 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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP2",
+                         (uint64_t) 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);
+  if (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 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;
-               }
-           }
+  convertible = IS_1ST_CONVERT (irel->r_addend);
+
+  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 < ARRAY_SIZE (checked_types); i++)
+    {
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    checked_types[i], laddr);
+      if (cond_irelfn != irelend)
+       break;
+    }
+
+  if (hi_irelfn == irelend
+      || lo_irelfn == irelend
+      || cond_irelfn == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP3",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
+
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr);
+
+  if (foff == 0
+      || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
+
+  /* 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);
+    }
+
+  /* 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 (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 if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP1)
+      else
        {
-         /* 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                    ;
+         /* 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;
 
-            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 (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);
+      }
 
-            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 ((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;
+}
 
-         /* 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;
+/* Relax LONGCALL4 relocation for nds32_elf_relax_section.  */
 
-         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;
+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  */
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel;
+  Elf_Internal_Rela *irelend;
+  bfd_signed_vma foff;
 
-                 continue;
-               }
-           }
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr + i1_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);
 
-         /* 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 (hi_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL4",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         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;
-           }
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr);
 
-         /* 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.  */
+  /* This condition only happened when symbol is undefined.  */
+  if (foff == 0
+      || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         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);
+  /* 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.  */
 
-         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);
-           }
+  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);
 
-         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);
+  if (ptr_irel == irelend || em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL4",
+                         (uint64_t) 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;
 
-         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);
+  /* 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;
 
-             continue;
-           }
+  /* We don't resolve this here but resolve it in relocate_section.  */
+  insn = INSN_JAL;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr);
+  irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         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;
-           }
+  /* 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 (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;
+  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);
 
-               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;
+  return TRUE;
+}
 
-               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;
+/* Relax LONGCALL5 relocation for nds32_elf_relax_section.  */
 
-               default:
-                 comp_insn16 = 0;
-                 insn = 0;
-                 break;
-               }
-           }
+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:  */
 
-         /* 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;
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *cond_irel, *irelend;
+  bfd_signed_vma foff;
 
-         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''.  */
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  /* 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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL5",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-                 /* 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;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr);
 
-                 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.  */
+  if (foff == 0
+      || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-                 /* Save comp_insn16 to buffer.  */
-                 insn16 = comp_insn16;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-                 reloc = R_NDS32_9_PCREL_RELA;
-               }
+  /* Relax to  bgezal   rt, label ; 17_PCREL
+     or                bltzal   rt, label ; 17_PCREL.  */
 
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc);
-             irel->r_addend = i2_irelfn->r_addend;
+  /* Convert to complimentary conditional call.  */
+  insn = CONVERT_CONDITION_CALL (insn);
 
-             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;
+  /* 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 (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;
-           }
+  /* Modify relocation and contents.  */
+  cond_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA);
 
-         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;
+  /* Replace the long call with a bgezal.  */
+  bfd_putb32 (insn, contents + cond_irel->r_offset);
+  *insn_len = 0;
 
-         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;
+  /* Clean unnessary relocations.  */
+  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_LONGJUMP3 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);
+  cond_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
 
-         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;
+  return TRUE;
+}
 
-         /* 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 LONGCALL6 relocation for nds32_elf_relax_section.  */
 
-               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;
+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;
+  bfd_signed_vma foff;
 
-               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;
-                   }
-               }
-           }
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         if (foff < -0x1000000 && foff >= 0x1000000)
-           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);
 
-         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;
-               }
-           }
+  if (em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL6",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         /* 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.  */
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr);
 
-         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);
-               }
+  if (foff == 0
+      || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-             /* Change relocs.  */
-             for (i = 0; i < 2; i++)
-               {
-                 cond_irelfn =
-                   find_relocs_at_address_addr (irel, internal_relocs,
-                                                irelend, checked_types[i],
-                                                laddr);
+  /* 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_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'.  */
+  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.  */
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = R_NDS32_15_PCREL_RELA;
+      /* Convert to complimentary conditional call.  */
+      *insn_len = 0;
+      insn = CONVERT_CONDITION_CALL (insn);
+      bfd_putb32 (insn, contents + em_irel->r_offset);
 
-             /* 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'.  */
+      em_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA);
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = 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)
+       {
+         _bfd_error_handler (unrecognized_reloc_msg, abfd,
+                             "R_NDS32_LONGCALL6", (uint64_t) irel->r_offset);
+         return FALSE;
+       }
+      cond_irel->r_addend = 1;
+
+      /* Clear relocations.  */
+
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+
+      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);
+
+      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);
+
+    }
+  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);
+
+      /* 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);
+
+      /* 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 (unrecognized_reloc_msg, abfd,
+                             "R_NDS32_LONGCALL6", (uint64_t) irel->r_offset);
+         return FALSE;
+       }
+      cond_irel->r_addend = 1;
 
-             /* 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
+      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;
+}
 
-                case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize for space
-                bnes38  rt, $1 ; LONGJUMP2
-                j       label  ; 25_PCREL
-                $1
+/* Relax LONGJUMP4 relocation for nds32_elf_relax_section.  */
 
-                case 4-4; 1st insn not convertible, others don't care
-                bne   rt, ra, $1 ; LONGJUMP2
-                j     label      ; 25_PCREL
-                $1
+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;
+  bfd_signed_vma foff;
 
-                case 4-4; 1st insn convertible, 16-bit on, optimize for speed
-                bne   rt, ra, $1 ; LONGJUMP2/INSN16
-                j     label      ; 25_PCREL
-                $1
-              */
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-             /* Offset for first instruction.  */
+  /* 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 (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;
-               }
+  hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_HI20_RELA, laddr);
 
-             /* 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;
-               }
-           }
+  if (hi_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP4",
+                         (uint64_t) irel->r_offset);
+      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);
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr);
 
-                 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)
-       {
-         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
-           };
+  if (foff == 0
+      || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         insn_len = seq_len;
+  /* 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);
 
-         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;
-           }
+  if (ptr_irel == irelend || em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP4",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         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;
-           }
+  em_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA);
+  ptr_irel->r_addend = 1;
 
-         ls_range_type = (irel->r_addend >> 8) & 0x3f;
+  /* Write instruction.  */
+  insn = INSN_J;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-         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);
+  /* Clear relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-             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;
-                       }
-                   }
-               }
+  /* 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 (!load_store_relax)
-               continue;
+  return TRUE;
+}
 
-             if (((insn >> 20) & 0x1f) == REG_GP)
-               break;
+/* Relax LONGJUMP5 relocation for nds32_elf_relax_section.  */
 
-             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;
+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;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-           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;
+  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 };
 
-           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;
+  laddr = irel->r_offset;
 
-             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);
+  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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP5",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-             if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr);
 
-           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;
+  if (foff == 0
+      || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-             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;
+  /* 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);
 
-           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)
+  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;
+
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc);
+
+  /* Clean relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+  for (i = 0; i < ARRAY_SIZE (checked_types); i++)
+    {
+      cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (cond_irel != irelend)
        {
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < 1022 && foff >= 0)
+         if (*seq_len == 0
+             && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16))
            {
-             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;
-
-             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));
-               }
+             /* 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);
        }
-      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);
+    }
+  *insn_len = 0;
 
-         insn = bfd_getb32 (contents + laddr);
+  return TRUE;
+}
 
-         if (!is_sda_access_insn (insn)
-             && N32_OP6 (insn) != N32_OP6_ORI)
-           continue;
+/* Relax LONGJUMP6 relocation for nds32_elf_relax_section.  */
 
-         access_addr =
-           calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         insn_len = seq_len = 4;
+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;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-         /* 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;
-               }
-           }
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         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;
+  /* 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);
 
-         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;
+  if (em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP6",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         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);
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr);
 
-         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;
-           }
+  if (foff == 0
+      || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         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);
+  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_COUNT);
+  /* 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 (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;
-               }
+  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
 
-             if (--i1_irelfn->r_addend > 0)
-               continue;
+        case 2-4;  1st insn convertible, 16-bit on.
+        bnes38  rt, ra, .L1    ; LONGJUMP5/9_PCREL/INSN16
+        j       label          ; 25_PCREL/INSN16
+        $1:
 
-             /* 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.  */
+        case 4-4; 1st insn not convertible
+        bne  rt, ra, .L1       ; LONGJUMP5/15_PCREL/INSN16
+        j    label             ; 25_PCREL/INSN16
+        .L1:  */
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           continue;
+      /* 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;
 
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF))
-           continue;
+  /* Set all relocations.  */
+  em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc);
 
-         seq_len = insn_len = 4;
-         i1_irelfn =
-           find_relocs_at_address (irel, internal_relocs, irelend,
-                                   R_NDS32_PTR_RESOLVED);
+  cond_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_PTR_RESOLVED, em_irel->r_offset);
+  cond_irel->r_addend = 1;
 
-         /* 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.  */
+  /* 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 (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;
+  if (cond_removed == 1)
+    {
+      *insn_len = 0;
 
-             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)
-           {
-             /* 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;
-           }
-         else
-           continue;
+      /* Clear relocations.  */
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-         bfd_putb32 (insn, contents + laddr);
-         if (i1_irelfn != irelend)
+      for (i = 0; i < ARRAY_SIZE (checked_types); 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);
            }
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_SUFF)
-       {
+    }
+  else
+    {
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                  R_NDS32_LONGJUMP5);
+    }
 
-         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 LONGJUMP7 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_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;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16;
+  uint32_t imm11;
 
-         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.  */
 
-         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;
+  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 (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP7",
+                         (uint64_t) 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, cond_irel, isymbuf, symtab_hdr);
 
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF))
-           continue;
+  if (foff == 0
+      || foff < -CONSERVATIVE_8BIT_S1
+      || foff >= CONSERVATIVE_8BIT_S1)
+    return FALSE;
 
-         seq_len = insn_len = 4;
+  /* 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);
+    }
 
-         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;
+  /* 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 (foff >= 0x3f000 || foff < -0x3f000)
-           continue;
+  bfd_putb32 (re_insn, contents + cond_irel->r_offset);
 
-         /* 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;
-           }
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                   R_NDS32_WORD_9_PCREL_RELA);
 
-         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;
+  /* 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 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;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+  return TRUE;
+}
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           continue;
+/* We figure out and reassign the best gp value in nds32_elf_final_sda_base
+   for each relax round. But the gp may changed dramatically and then cause
+   the truncated to fit errors for the the converted gp instructions.
+   Therefore, we must reserve the minimum but safe enough size to prevent it.  */
 
-         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;
+static bfd_boolean
+nds32_elf_relax_guard (bfd_vma *access_addr, bfd_vma local_sda, asection *sec,
+                      Elf_Internal_Rela *irel, bfd_boolean *again,
+                      bfd_boolean init,
+                      struct elf_nds32_link_hash_table *table,
+                      Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr)
+
+{
+  int offset_to_gp;
+  static bfd_boolean sec_pass = FALSE;
+  static asection *first_sec = NULL, *sym_sec;
+  /* Record the number of instructions which may be removed.  */
+  static int count = 0, record_count;
+  Elf_Internal_Sym *isym;
+  struct elf_link_hash_entry *h = NULL;
+  int indx;
+  unsigned long r_symndx;
+  bfd *abfd = sec->owner;
+  static bfd_vma record_sda = 0;
+  int sda_offset = 0;
 
-         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);
+  /* Force doing relaxation when hyper-relax is high.  */
+  if (table->hyper_relax == 2)
+    return TRUE;
 
-         if (i1_irelfn != irelend)
-           {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
-           }
-         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)
+  /* Do not relax the load/store patterns for the first
+     relax round.  */
+  if (init)
+    {
+      if (!first_sec)
+       first_sec = sec;
+      else if (first_sec == sec)
        {
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PLT_GOTREL_HI20);
-
-         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;
-           }
+         record_count = count;
+         count = 0;
+         sec_pass = 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);
+      if (!sec_pass)
+       *again = TRUE;
 
-         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 */
+      return TRUE;
+    }
 
-                 /* 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);
+  /* Generally, _SDA_BASE_ is fixed or smaller. But the large
+     DATA_SEGMENT_ALIGN size in the linker script may make it
+     get even bigger.  */
+  if (record_sda == 0)
+    record_sda = local_sda;
+  else if (local_sda > record_sda)
+    sda_offset = local_sda - record_sda;
 
-                 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;
+  /* Assume the instruction will be removed in the best case.  */
+  count++;
 
-                 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;
+  /* We record the offset to gp for each symbol, and then check
+     if it is changed dramatically after relaxing.
+     (global symbol): elf32_nds32_hash_entry (h)->offset_to_gp
+     (local symbol) : elf32_nds32_local_gp_offset (abfd)[r_symndx].  */
+  r_symndx = ELF32_R_SYM (irel->r_info);
+  if (r_symndx >= symtab_hdr->sh_info)
+    {
+      /* Global symbols.  */
+      indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+      h = elf_sym_hashes (abfd)[indx];
+      sym_sec = h->root.u.def.section;
+      if (NDS32_GUARD_SEC_P (sym_sec->flags)
+         || bfd_is_abs_section (sym_sec))
+       {
+         /* Forbid doing relaxation when hyper-relax is low.  */
+         if (table->hyper_relax == 0)
+           return FALSE;
 
-           }
-         else
+         offset_to_gp = *access_addr - local_sda;
+         if (elf32_nds32_hash_entry (h)->offset_to_gp == 0)
+           elf32_nds32_hash_entry (h)->offset_to_gp = offset_to_gp;
+         else if (abs (elf32_nds32_hash_entry (h)->offset_to_gp)
+                  < abs (offset_to_gp) - sda_offset)
            {
-             /* 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;
+             /* This may cause the error, so we reserve the
+                safe enough size for relaxing.  */
+             if (*access_addr >= local_sda)
+               *access_addr += (record_count * 4);
+             else
+               *access_addr -= (record_count * 4);
            }
-
-         insn_len = 0;
+         return sec_pass;
        }
-      else
-       continue;
+    }
+  else
+    {
+      /* Local symbols.  */
+      if (!elf32_nds32_allocate_local_sym_info (abfd))
+       return FALSE;
+      isym = isymbuf + r_symndx;
 
-      if (seq_len - insn_len > 0)
+      sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+      if (NDS32_GUARD_SEC_P (sym_sec->flags))
        {
-         if (!insert_nds32_elf_blank
-             (&relax_blank_list, irel->r_offset + insn_len,
-              seq_len - insn_len))
-           goto error_return;
-         *again = TRUE;
+         /* Forbid doing relaxation when hyper-relax is low.  */
+         if (table->hyper_relax == 0)
+           return FALSE;
+
+         offset_to_gp = *access_addr - local_sda;
+         if (elf32_nds32_local_gp_offset (abfd)[r_symndx] == 0)
+           elf32_nds32_local_gp_offset (abfd)[r_symndx] = offset_to_gp;
+         else if (abs (elf32_nds32_local_gp_offset (abfd)[r_symndx])
+                  < abs (offset_to_gp) - sda_offset)
+           {
+             /* This may cause the error, so we reserve the
+                safe enough size for relaxing.  */
+             if (*access_addr >= local_sda)
+               *access_addr += (record_count * 4);
+             else
+               *access_addr -= (record_count * 4);
+           }
+         return sec_pass;
        }
     }
 
-  calc_nds32_blank_total (relax_blank_list);
+  return TRUE;
+}
 
-  if (table->relax_fp_as_gp)
-    {
-      if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs,
-                                irelend, isymbuf))
-       goto error_return;
+#define GET_LOADSTORE_RANGE(addend) (((addend) >> 8) & 0x3f)
 
-      if (*again == FALSE)
-       {
-         if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs,
-                                              irelend))
-           goto error_return;
-       }
-    }
+/* Relax LOADSTORE relocation for nds32_elf_relax_section.  */
+
+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,
+                          struct elf_nds32_link_hash_table *table)
+{
+  int eliminate_sethi = 0, range_type;
+  unsigned int 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.  */
+  struct elf_link_hash_entry *h = NULL;
+  int indx;
+  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
+    };
+
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-  if (*again == FALSE)
+  /* Get the high part relocation.  */
+  for (i = 0; i < ARRAY_SIZE (checked_types); i++)
     {
-      /* This code block is used to adjust 4-byte alignment by relax a pair
-        of instruction a time.
+      hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (hi_irelfn != irelend)
+       break;
+    }
 
-        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.
+  if (hi_irelfn == irelend)
+    {
+      /* Not R_NDS32_HI20_RELA.  */
+      if (i != 0)
+       _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LOADSTORE",
+                           (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-        FIXME: It seems currently implementation only support 4-byte aligment.
-        We should handle any-aligment.  */
+  range_type = GET_LOADSTORE_RANGE (irel->r_addend);
+  nds32_elf_final_sda_base (sec->output_section->owner,
+                           link_info, &local_sda, FALSE);
 
-      Elf_Internal_Rela *insn_rel = NULL;
-      Elf_Internal_Rela *label_rel = NULL;
-      Elf_Internal_Rela *tmp_rel, tmp2_rel, *tmp3_rel = NULL;
+  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);
 
-      /* 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);
+      if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info)
+       {
+         indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info;
+         h = elf_sym_hashes (abfd)[indx];
+       }
 
-      nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                               &local_sda, FALSE);
+      /* Try movi.  */
+      if (range_type == NDS32_LOADSTORE_IMM
+         && access_addr < CONSERVATIVE_20BIT
+         && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0)))
+       {
+         eliminate_sethi = 1;
+         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 (h && strcmp (h->root.root.string, FP_BASE_NAME) == 0)
        {
-         if (ELF32_R_TYPE (label_rel->r_info) != R_NDS32_LABEL)
-           continue;
+         eliminate_sethi = 1;
+         break;
+       }
+      else if (!nds32_elf_relax_guard (&access_addr, local_sda, sec, hi_irelfn,
+                                      NULL, FALSE, table, isymbuf, symtab_hdr))
+       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++;
+      if (!load_store_relax)
+       return 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;
+      /* Case for set gp register.  */
+      if (N32_RT5 (insn) == REG_GP)
+       return FALSE;
 
-         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 (&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));
-           }
+      if (range_type == NDS32_LOADSTORE_FLOAT_S
+         || range_type == NDS32_LOADSTORE_FLOAT_D)
+       {
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
        }
-      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++)
+      else
        {
-         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)
-               {
-                 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;
-               }
-           }
-         else if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16)
+         range_l = sdata_range[1][0];
+         range_h = sdata_range[1][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;
+    }
+
+  return FALSE;
+}
+
+/* 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,
+                     struct elf_nds32_link_hash_table *table)
+{
+  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];
+    }
+
+  /* Try movi.  */
+  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);
+    }
+  else
+    {
+      if (h && strcmp (h->root.root.string, FP_BASE_NAME) == 0)
+       {
+         /* Fall through.  */
+       }
+      else if (!nds32_elf_relax_guard (&access_addr, local_sda, sec, irel, NULL,
+                                      FALSE, table, isymbuf, symtab_hdr))
+       return;
+
+      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)
+         || (h && strcmp (h->root.root.string, FP_BASE_NAME) == 0))
+       {
+         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 PTR relocation for nds32_elf_relax_section.  */
+
+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;
+
+  irelend = internal_relocs + sec->reloc_count;
+
+  re_irel =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_PTR_RESOLVED, irel->r_addend);
+
+  if (re_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_PTR",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
+
+  if (re_irel->r_addend != 1)
+    return FALSE;
+
+  /* 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);
+
+  /* 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 LWC relocation for nds32_elf_relax_section.  */
+
+static void
+nds32_elf_relax_flsi (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)
+{
+  /* Pattern:
+     sethi    ra, hi20(symbol)      ; HI20/LOADSTORE
+     ori      ra, ra, lo12(symbol)  ; LO12S0/PTR/PTR/.../INSN16
+     flsi     fsa, [ra + offset1]   ; LSI/PTR_RESOLVED/INSN16
+     flsi     fsb, [ra + offset2]   ; LSI/PTR_RESOLVED/INSN16
+     ...  */
+
+  uint32_t insn;
+  bfd_vma local_sda, laddr;
+  unsigned long reloc;
+  bfd_vma access_addr, flsi_offset;
+  bfd_vma range_l = 0, range_h = 0;    /* Upper/lower bound.  */
+  Elf_Internal_Rela *irelend, *re_irel;
+  unsigned int opcode;
+
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  if ((insn & 0x80000000) || !is_sda_access_insn (insn))
+    return;
+
+  /* Can not do relaxation for bi format.  */
+  if ((insn & 0x1000))
+    return;
+
+  /* Only deal with flsi, fssi, fldi, fsdi, so far.  */
+  opcode = N32_OP6 (insn);
+  if ((opcode == N32_OP6_LWC) || (opcode == N32_OP6_SWC))
+    reloc = R_NDS32_SDA12S2_SP_RELA;
+  else if ((opcode == N32_OP6_LDC) || (opcode == N32_OP6_SDC))
+    reloc = R_NDS32_SDA12S2_DP_RELA;
+  else
+    return;
+
+  re_irel = find_relocs_at_address (irel, internal_relocs, irelend,
+                                   R_NDS32_PTR_RESOLVED);
+  if (re_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LSI",
+                         (uint64_t) irel->r_offset);
+      return;
+    }
+
+  /* For SDA base relative relaxation.  */
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  flsi_offset = (insn & 0xfff) << 2;
+  access_addr += flsi_offset;
+  range_l = sdata_range[0][0];
+  range_h = sdata_range[0][1];
+
+  if ((local_sda <= access_addr && (access_addr - local_sda) < range_h)
+      || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
+    {
+      /* Turn flsi instruction into sda access format.  */
+      insn = (insn & 0x7ff07000) | (REG_GP << 15);
+
+      /* Add relocation type to flsi.  */
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      irel->r_addend += flsi_offset;
+      bfd_putb32 (insn, contents + re_irel->r_offset);
+
+      re_irel->r_addend |= 1;
+      *again = TRUE;
+    }
+}
+
+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 alignment.
+     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 alignment.
+     We should handle any-alignment.  */
+
+  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)
        {
-         if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16
-             && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL)
-           continue;
+         /* 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));
+       }
+    }
 
-         /* Search for INSN16 reloc.  */
-         if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16)
+  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)
            {
-             if (label_rel)
+             /* 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++)
                {
-                 /* 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;
+                 if (tmp2_rel->r_offset == tmp_rel->r_offset)
+                   break;
+
+                 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);
                }
-             /* A new INSN16 found, resize the old one.  */
-             else if (insn_rel)
+             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->r_offset < sec->size; 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)
                {
-                 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))
+                 /* 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 (!insert_nds32_elf_blank_recalc_total
-                         (&relax_blank_list, insn_rel->r_offset + 2, 2))
-                       goto error_return;
+                         (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))
-                       goto error_return;
+                         (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;
-               }
-
-             if (is_convert_32_to_16
-                 (abfd, sec, irel, internal_relocs, irelend, &insn16)
-                 || is_16bit_NOP (abfd, sec, irel))
-               {
-                 insn_rel = irel;
+                   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.  */
-         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;
-               }
+         int force_relax = 0;
 
-             if (!optimize && (irel->r_addend & 0x1f) < 2)
-               {
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 continue;
-               }
+         /* 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;
+           }
 
-             /* Try to align this label.  */
-             if (insn_rel)
-               {
-                 int force_relax = 0;
+         address =
+           irel->r_offset - get_nds32_elf_blank_total (relax_blank_list,
+                                                       irel->r_offset, 1);
 
-                 /* 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 (!insn_rel)
+           {
+             /* Check if there is case which can not be aligned.  */
+             if (irel->r_addend == 2 && address & 0x2)
+               return FALSE;
+             continue;
+           }
 
-                     /* 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;
-                       }
+         /* Try to align this label.  */
 
-                     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;
-                           }
-                       }
-                   }
+         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.  */
 
-                 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
+             /* 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)))
                    {
-                     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;
-                               }
-                           }
-                       }
-
-                     if (force_relax)
-                       {
-                         label_rel = irel;
-                       }
-
-                     /* INSN16 reloc is used.  */
-                     insn_rel = NULL;
+                     force_relax = 1;
+                     break;
                    }
                }
            }
-       }
 
-      if (insn_rel)
-       {
-         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 (force_relax || irel->r_addend == 1 || address & 0x2)
            {
-             if (is_convert_32_to_16
-                 (abfd, sec, insn_rel, internal_relocs, irelend,
-                  &insn16))
+             /* 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);
+                 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);
+                     (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))
-                   goto error_return;
-                 insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                                  R_NDS32_NONE);
+                     (relax_blank_list, insn_rel->r_offset, 2))
+                   return FALSE;
                }
+
            }
+         /* INSN16 reloc is used.  */
          insn_rel = NULL;
        }
     }
-    /* 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.  */
-
-  if (relax_blank_list)
-    {
-      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
-      relax_blank_list = NULL;
-    }
 
-  if (*again == FALSE)
+  address =
+    sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0);
+  if (insn_rel && (address & 0x2 || opt_size))
     {
-      /* Closing the section, so we don't relax it anymore.  */
-      bfd_vma sec_size_align;
-      Elf_Internal_Rela *tmp_rel;
-
-      /* Pad to alignment boundary.  Only handle current section alignment.  */
-      sec_size_align = (sec->size + (~((-1) << sec->alignment_power)))
-                      & ((-1) << sec->alignment_power);
-      if ((sec_size_align - sec->size) & 0x2)
+      if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs,
+                              irelend, &insn16))
        {
-         insn16 = NDS32_NOP16;
-         bfd_putb16 (insn16, contents + sec->size);
-         sec->size += 2;
+         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);
        }
-
-      while (sec_size_align != sec->size)
+      else if (is_16bit_NOP (abfd, sec, insn_rel))
        {
-         insn = NDS32_NOP32;
-         bfd_putb32 (insn, contents + sec->size);
-         sec->size += 4;
-       }
-
-      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;
-
-      clean_nds32_elf_blank ();
-    }
-
-finish:
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
-    free (internal_relocs);
-
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
-
-  if (isymbuf != NULL && symtab_hdr->contents != (bfd_byte *) isymbuf)
-    free (isymbuf);
-
-  return result;
-
-error_return:
-  result = FALSE;
-  goto finish;
-}
-
-static struct bfd_elf_special_section const nds32_elf_special_sections[] =
-{
-  {".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE},
-  {".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE},
-  {NULL, 0, 0, 0, 0}
-};
-
-static bfd_boolean
-nds32_elf_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
-                           struct bfd_link_info *info,
-                           void *finfo ATTRIBUTE_UNUSED,
-                           bfd_boolean (*func) (void *, const char *,
-                                                Elf_Internal_Sym *,
-                                                asection *,
-                                                struct elf_link_hash_entry *)
-                           ATTRIBUTE_UNUSED)
-{
-  FILE *sym_ld_script = NULL;
-  struct elf_nds32_link_hash_table *table;
-
-  table = nds32_elf_hash_table (info);
-  sym_ld_script = table->sym_ld_script;
-
-  if (check_start_export_sym)
-    fprintf (sym_ld_script, "}\n");
-
-  return TRUE;
-}
-
-static enum elf_reloc_type_class
-nds32_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
-                           const asection *rel_sec ATTRIBUTE_UNUSED,
-                           const Elf_Internal_Rela *rela)
-{
-  switch ((int) ELF32_R_TYPE (rela->r_info))
-    {
-    case R_NDS32_RELATIVE:
-      return reloc_class_relative;
-    case R_NDS32_JMP_SLOT:
-      return reloc_class_plt;
-    case R_NDS32_COPY:
-      return reloc_class_copy;
-    default:
-      return reloc_class_normal;
-    }
-}
-
-/* Put target dependent option into info hash table.  */
-void
-bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info,
-                                  int relax_fp_as_gp,
-                                  int eliminate_gc_relocs,
-                                  FILE * sym_ld_script, int load_store_relax,
-                                  int target_optimize, int relax_status,
-                                  int relax_round, FILE * ex9_export_file,
-                                  FILE * ex9_import_file,
-                                  int update_ex9_table, int ex9_limit,
-                                  bfd_boolean ex9_loop_aware,
-                                  bfd_boolean ifc_loop_aware)
-{
-  struct elf_nds32_link_hash_table *table;
-
-  table = nds32_elf_hash_table (link_info);
-  if (table == NULL)
-    return;
-
-  table->relax_fp_as_gp = relax_fp_as_gp;
-  table->eliminate_gc_relocs = eliminate_gc_relocs;
-  table->sym_ld_script = sym_ld_script;
-  table ->load_store_relax = load_store_relax;
-  table->target_optimize = target_optimize;
-  table->relax_status = relax_status;
-  table->relax_round = relax_round;
-  table->ex9_export_file = ex9_export_file;
-  table->ex9_import_file = ex9_import_file;
-  table->update_ex9_table = update_ex9_table;
-  table->ex9_limit = ex9_limit;
-  table->ex9_loop_aware = ex9_loop_aware;
-  table->ifc_loop_aware = ifc_loop_aware;
-}
-\f
-/* These functions and data-structures are used for fp-as-gp
-   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.  */
-
-/* An nds32_fag represent a gp-relative access.
-   We find best fp-base by using a sliding window
-   to find a base address which can cover most gp-access.  */
-struct nds32_fag
-{
-  struct nds32_fag *next;      /* NULL-teminated linked list.  */
-  bfd_vma addr;                        /* The address of this fag.  */
-  Elf_Internal_Rela **relas;   /* The relocations associated with this fag.
-                                  It is used for applying FP7U2_FLAG.  */
-  int count;                   /* How many times this address is referred.
-                                  There should be exactly `count' relocations
-                                  in relas.  */
-  int relas_capcity;           /* The buffer size of relas.
-                                  We use an array instead of linked-list,
-                                  and realloc is used to adjust buffer size.  */
-};
-
-static void
-nds32_fag_init (struct nds32_fag *head)
-{
-  memset (head, 0, sizeof (struct nds32_fag));
-}
-
-static void
-nds32_fag_verify (struct nds32_fag *head)
-{
-  struct nds32_fag *iter;
-  struct nds32_fag *prev;
-
-  prev = NULL;
-  iter = head->next;
-  while (iter)
-    {
-      if (prev && prev->addr >= iter->addr)
-       puts ("Bug in fp-as-gp insertion.");
-      prev = iter;
-      iter = iter->next;
-    }
-}
-
-/* Insert a fag in ascending order.
-   If a fag of the same address already exists,
-   they are chained by relas array.  */
-
-static void
-nds32_fag_insert (struct nds32_fag *head, bfd_vma addr,
-                 Elf_Internal_Rela * rel)
-{
-  struct nds32_fag *iter;
-  struct nds32_fag *new_fag;
-  const int INIT_RELAS_CAP = 4;
-
-  for (iter = head;
-       iter->next && iter->next->addr <= addr;
-       iter = iter->next)
-    /* Find somewhere to insert.  */ ;
-
-  /* `iter' will be equal to `head' if the list is empty.  */
-  if (iter != head && iter->addr == addr)
-    {
-      /* The address exists in the list.
-        Insert `rel' into relocation list, relas.  */
-
-      /* Check whether relas is big enough.  */
-      if (iter->count >= iter->relas_capcity)
-       {
-         iter->relas_capcity *= 2;
-         iter->relas = bfd_realloc
-           (iter->relas, iter->relas_capcity * sizeof (void *));
-       }
-      iter->relas[iter->count++] = rel;
-      return;
-    }
-
-  /* This is a new address.  Create a fag node for it.  */
-  new_fag = bfd_malloc (sizeof (struct nds32_fag));
-  memset (new_fag, 0, sizeof (*new_fag));
-  new_fag->addr = addr;
-  new_fag->count = 1;
-  new_fag->next = iter->next;
-  new_fag->relas_capcity = INIT_RELAS_CAP;
-  new_fag->relas = (Elf_Internal_Rela **)
-    bfd_malloc (new_fag->relas_capcity * sizeof (void *));
-  new_fag->relas[0] = rel;
-  iter->next = new_fag;
-
-  nds32_fag_verify (head);
-}
-
-static void
-nds32_fag_free_list (struct nds32_fag *head)
-{
-  struct nds32_fag *iter;
-
-  iter = head->next;
-  while (iter)
-    {
-      struct nds32_fag *tmp = iter;
-      iter = iter->next;
-      free (tmp->relas);
-      tmp->relas = NULL;
-      free (tmp);
-    }
-}
-
-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
-   are different, their distance may change too.
-   Therefore, tracking a fixed address is not appriate.  */
-
-static int
-nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp)
-{
-  struct nds32_fag *base;      /* First fag in the window.  */
-  struct nds32_fag *last;      /* First fag outside the window.  */
-  int accu = 0;                        /* Usage accumulation.  */
-  struct nds32_fag *best;      /* Best fag.  */
-  int baccu = 0;               /* Best accumulation.  */
-
-  /* Use first fag for initial, and find the last fag in the window.
-
-     In each iteration, we could simply subtract previous fag
-     and accumulate following fags which are inside the window,
-     untill we each the end.  */
-
-  if (nds32_fag_isempty (head))
-    return 0;
-
-  /* Initialize base.  */
-  base = head->next;
-  best = base;
-  for (last = base;
-       last && last->addr < base->addr + FAG_WINDOW;
-       last = last->next)
-    accu += last->count;
-
-  baccu = accu;
-
-  /* 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;
-       }
-   }
-
-  if (bestpp)
-    *bestpp = best;
-  return baccu;
-}
-
-/* Apply R_NDS32_INSN16_FP7U2_FLAG on gp-relative accesses,
-   so we can convert it fo fp-relative access later.
-   `best_fag' is the best fp-base.  Only those inside the window
-   of best_fag is applied the flag.  */
-
-static bfd_boolean
-nds32_fag_mark_relax (struct bfd_link_info *link_info,
-                     bfd *abfd, struct nds32_fag *best_fag,
-                     Elf_Internal_Rela *internal_relocs,
-                     Elf_Internal_Rela *irelend)
-{
-  struct nds32_fag *ifag;
-  bfd_vma best_fpbase, gp;
-  bfd *output_bfd;
-
-  output_bfd = abfd->sections->output_section->owner;
-  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])
-    return FALSE;
-
-  /* Mark these inside the window R_NDS32_INSN16_FP7U2_FLAG flag,
-     so we know they can be converted to lwi37.fp.   */
-  for (ifag = best_fag;
-       ifag && ifag->addr < best_fpbase + FAG_WINDOW; ifag = ifag->next)
-    {
-      int i;
-
-      for (i = 0; i < ifag->count; i++)
-       {
-         Elf_Internal_Rela *insn16_rel;
-         Elf_Internal_Rela *fag_rel;
-
-         fag_rel = ifag->relas[i];
-
-         /* Only if this is within the WINDOWS, FP7U2_FLAG
-            is applied.  */
-
-         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;
-       }
-    }
-  return TRUE;
-}
-
-/* This is the main function of fp-as-gp optimization.
-   It should be called by relax_section.  */
-
-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,
-                     Elf_Internal_Sym *isymbuf)
-{
-  Elf_Internal_Rela *begin_rel = NULL;
-  Elf_Internal_Rela *irel;
-  struct nds32_fag fag_head;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *contents;
-
-  /* FIXME: Can we bfd_elf_link_read_relocs for the relocs?  */
-
-  /* Per-function fp-base selection.
-     1. Create a list for all the gp-relative access.
-     2. Base on those gp-relative address,
-       find a fp-base which can cover most access.
-     3. Use the fp-base for fp-as-gp relaxation.
-
-     NOTE: If fp-as-gp is not worth to do, (e.g., less than 3 times),
-     we should
-     1. delete the `la $fp, _FP_BASE_' instruction and
-     2. not convert lwi.gp to lwi37.fp.
-
-     To delete the _FP_BASE_ instruction, we simply apply
-     R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG flag in the r_addend to disable it.
-
-     To suppress the conversion, we simply NOT to apply
-     R_NDS32_INSN16_FP7U2_FLAG flag.  */
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-
-  if (!nds32_get_section_contents (abfd, sec, &contents)
-      || !nds32_get_local_syms (abfd, sec, &isymbuf))
-    return FALSE;
-
-  /* Check whether it is worth for fp-as-gp optimization,
-     i.e., at least 3 gp-load.
-
-     Set R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG if we should NOT
-     apply this optimization.  */
-
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      /* We recognize R_NDS32_RELAX_REGION_BEGIN/_END for the region.
-        One we enter the begin of the region, we track all the LW/ST
-        instructions, so when we leave the region, we try to find
-        the best fp-base address for those LW/ST instructions.  */
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
-         && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG))
-       {
-         /* Begin of the region.  */
-         if (begin_rel)
-           (*_bfd_error_handler) (_("%B: Nested OMIT_FP in %A."), abfd, sec);
-
-         begin_rel = irel;
-         nds32_fag_init (&fag_head);
-       }
-      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;
-         int dist;
-
-         /* End of the region.
-            Check whether it is worth to do fp-as-gp.  */
-
-         if (begin_rel == NULL)
-           {
-             (*_bfd_error_handler) (_("%B: Unmatched OMIT_FP in %A."), abfd, sec);
-             continue;
-           }
-
-         accu = nds32_fag_find_base (&fag_head, &best_fag);
-
-         /* 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,
-                                       internal_relocs, irelend))
-           {
-             /* Not worth to do fp-as-gp.  */
-             begin_rel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG;
-             begin_rel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
-             irel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG;
-             irel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
-             nds32_fag_free_list (&fag_head);
-             begin_rel = NULL;
-             continue;
-           }
-
-         /* R_SYM of R_NDS32_RELAX_REGION_BEGIN is not used by assembler,
-            so we use it to record the distance to the reloction of best
-            fp-base.  */
-         dist = best_fag->relas[0] - begin_rel;
-         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 |= dist << 16;
-
-         nds32_fag_free_list (&fag_head);
-         begin_rel = NULL;
-       }
-
-      if (begin_rel == NULL)
-       /* Skip if we are not in the region of fp-as-gp.  */
-       continue;
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA
-         || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA)
-       {
-         bfd_vma addr;
-         uint32_t insn;
-
-         /* A gp-relative access is found.  Insert it to the fag-list.  */
-
-         /* Rt is necessary an RT3, so it can be converted to lwi37.fp.  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (!N32_IS_RT3 (insn))
-           continue;
-
-         addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         nds32_fag_insert (&fag_head, addr, irel);
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA)
-       {
-         begin_rel = NULL;
+         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;
 }
 
-/* Remove unused `la $fp, _FD_BASE_' instruction.  */
-
 static bfd_boolean
-nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec,
-                               Elf_Internal_Rela *internal_relocs,
-                               Elf_Internal_Rela *irelend)
+nds32_elf_relax_section (bfd *abfd, asection *sec,
+                        struct bfd_link_info *link_info, bfd_boolean *again)
 {
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *contents = NULL;
   nds32_elf_blank_t *relax_blank_list = NULL;
-  bfd_boolean result = TRUE;
-  bfd_boolean unused_region = FALSE;
-
-  /*
-     NOTE: Disable fp-as-gp if we encounter ifcall relocations.
-     * R_NDS32_17IFC_PCREL_RELA
-     * R_NDS32_10IFCU_PCREL_RELA
-
-     CASE??????????????
-  */
-
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  nds32_get_section_contents (abfd, sec, &contents);
-
-  for (irel = internal_relocs; irel < irelend; irel++)
-    {
-      /* To remove unused fp-base, we simply find the REGION_NOT_OMIT_FP
-        we marked to in previous pass.
-        DO NOT scan relocations again, since we've alreadly decided it
-        and set the flag.  */
-      const char *syname;
-      int syndx;
-      uint32_t insn;
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
-         && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG))
-       unused_region = TRUE;
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END
-              && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG))
-       unused_region = FALSE;
-
-      /* We're not in the region.  */
-      if (!unused_region)
-       continue;
-
-      /* _FP_BASE_ must be a GLOBAL symbol.  */
-      syndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
-       continue;
-
-      /* The symbol name must be _FP_BASE_.  */
-      syname = elf_sym_hashes (abfd)[syndx]->root.root.string;
-      if (strcmp (syname, FP_BASE_NAME) != 0)
-       continue;
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA19S0_RELA)
-       {
-         /* addi.gp  $fp, -256  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (insn != INSN_ADDIGP_TO_FP)
-           continue;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S0_RELA)
-       {
-         /* addi  $fp, $gp, -256  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (insn != INSN_ADDI_GP_TO_FP)
-           continue;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_20_RELA)
-       {
-         /* movi  $fp, FP_BASE  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (insn != INSN_MOVI_TO_FP)
-           continue;
-       }
-      else
-       continue;
-
-      /* We got here because a FP_BASE instruction is found.  */
-      if (!insert_nds32_elf_blank_recalc_total
-         (&relax_blank_list, irel->r_offset, 4))
-       goto error_return;
-    }
-
-finish:
-  if (relax_blank_list)
-    {
-      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
-      relax_blank_list = NULL;
-    }
-  return result;
-
-error_return:
-  result = FALSE;
-  goto finish;
-}
-\f
-/* Link-time IFC relaxation.
-   In this optimization, we chains jump instructions
-   of the same destination with ifcall.  */
-
-
-/* List to save jal and j relocation.  */
-struct elf_nds32_ifc_symbol_entry
-{
-  asection *sec;
-  struct elf_link_hash_entry *h;
-  struct elf_nds32_ifc_irel_list *irel_head;
-  unsigned long insn;
-  int times;
-  int enable;          /* Apply ifc.  */
-  int ex9_enable;      /* Apply ifc after ex9.  */
-  struct elf_nds32_ifc_symbol_entry *next;
-};
-
-struct elf_nds32_ifc_irel_list
-{
-  Elf_Internal_Rela *irel;
-  asection *sec;
-  bfd_vma addr;
-  /* If this is set, then it is the last instruction for
-     ifc-chain, so it must be keep for the actual branching.  */
-  int keep;
-  struct elf_nds32_ifc_irel_list *next;
-};
-
-static struct elf_nds32_ifc_symbol_entry *ifc_symbol_head = NULL;
-
-/* Insert symbol of jal and j for ifc.  */
-
-static void
-nds32_elf_ifc_insert_symbol (asection *sec,
-                            struct elf_link_hash_entry *h,
-                            Elf_Internal_Rela *irel,
-                            unsigned long insn)
-{
-  struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
-
-  /* Check there is target of existing entry the same as the new one.  */
-  while (ptr != NULL)
-    {
-      if (((h == NULL && ptr->sec == sec
-           && ELF32_R_SYM (ptr->irel_head->irel->r_info) == ELF32_R_SYM (irel->r_info)
-           && ptr->irel_head->irel->r_addend == irel->r_addend)
-          || h != NULL)
-         && ptr->h == h
-         && ptr->insn == insn)
-       {
-         /* The same target exist, so insert into list.  */
-         struct elf_nds32_ifc_irel_list *irel_list = ptr->irel_head;
-
-         while (irel_list->next != NULL)
-           irel_list = irel_list->next;
-         irel_list->next = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list));
-         irel_list = irel_list->next;
-         irel_list->irel = irel;
-         irel_list->keep = 1;
-
-         if (h == NULL)
-           irel_list->sec = NULL;
-         else
-           irel_list->sec = sec;
-         irel_list->next = NULL;
-         return;
-       }
-      if (ptr->next == NULL)
-       break;
-      ptr = ptr->next;
-    }
-
-  /* There is no same target entry, so build a new one.  */
-  if (ifc_symbol_head == NULL)
-    {
-      ifc_symbol_head = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry));
-      ptr = ifc_symbol_head;
-    }
-  else
-    {
-      ptr->next = bfd_malloc (sizeof (struct elf_nds32_ifc_symbol_entry));
-      ptr = ptr->next;
-    }
-
-  ptr->h = h;
-  ptr->irel_head = bfd_malloc (sizeof (struct elf_nds32_ifc_irel_list));
-  ptr->irel_head->irel = irel;
-  ptr->insn = insn;
-  ptr->irel_head->keep = 1;
-
-  if (h == NULL)
-    {
-      /* Local symbols.  */
-      ptr->sec = sec;
-      ptr->irel_head->sec = NULL;
-    }
-  else
-    {
-      /* Global symbol.  */
-      ptr->sec = NULL;
-      ptr->irel_head->sec = sec;
-    }
-
-  ptr->irel_head->next = NULL;
-  ptr->times = 0;
-  ptr->enable = 0;
-  ptr->ex9_enable = 0;
-  ptr->next = NULL;
-}
-
-/* Gather all jal and j instructions.  */
-
-static bfd_boolean
-nds32_elf_ifc_calc (struct bfd_link_info *info,
-                   bfd *abfd, asection *sec)
-{
+  Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irelend;
   Elf_Internal_Rela *irel;
-  Elf_Internal_Shdr *symtab_hdr;
+  Elf_Internal_Rela *irelend;
+  Elf_Internal_Sym *isymbuf = NULL;
   bfd_byte *contents = NULL;
-  unsigned long 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);
+  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;
-  bfd_boolean ifc_loop_aware;
+  int load_store_relax;
 
-  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;
+  relax_blank_list = NULL;
 
-  /* Check if the object enable ifc.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  *again = FALSE;
 
-  if (irel == NULL
-      || irel >= irelend
-      || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY
-      || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY
-         && !(irel->r_addend & R_NDS32_RELAX_ENTRY_IFC_FLAG)))
+  /* Nothing to do for
+   * relocatable link or
+   * non-relocatable section or
+   * non-code section or
+   * empty content or
+   * no reloc entry.  */
+  if (bfd_link_relocatable (link_info)
+      || (sec->flags & SEC_RELOC) == 0
+      || (sec->flags & SEC_EXCLUDE) != 0
+      || (sec->flags & SEC_CODE) == 0
+      || sec->size == 0
+      || sec->reloc_count == 0)
     return TRUE;
 
-  if (!nds32_get_section_contents (abfd, sec, &contents))
-    return FALSE;
-
-  table = nds32_elf_hash_table (info);
-  ifc_loop_aware = table->ifc_loop_aware;
-  while (irel != NULL && irel < irelend)
-    {
-      /* Traverse all relocation and gather all of them to build the list.  */
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN)
-       {
-         if (ifc_loop_aware == 1
-             && (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0)
-           {
-             /* Check the region if loop or not.  If it is true and
-                ifc-loop-aware is true, ignore the region till region end.  */
-             while (irel != NULL
-                    && irel < irelend
-                    && (ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_REGION_END
-                        || (irel->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG) != 0))
-               irel++;
-           }
-       }
-
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA)
-       {
-         insn = bfd_getb32 (contents + irel->r_offset);
-         nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg);
-         r_symndx = ELF32_R_SYM (irel->r_info);
-         if (r_symndx < symtab_hdr->sh_info)
-           {
-             /* Local symbol.  */
-             nds32_elf_ifc_insert_symbol (sec, NULL, irel, insn_with_reg);
-           }
-         else
-           {
-             /* External symbol.  */
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             nds32_elf_ifc_insert_symbol (sec, h, irel, insn_with_reg);
-           }
-       }
-      irel++;
-    }
-  return TRUE;
-}
-
-/* Determine whether j and jal should be substituted.  */
-
-static void
-nds32_elf_ifc_filter (struct bfd_link_info *info)
-{
-  struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
-  struct elf_nds32_ifc_irel_list *irel_ptr = NULL;
-  struct elf_nds32_ifc_irel_list *irel_keeper = NULL;
-  struct elf_nds32_link_hash_table *table;
-  int target_optimize;
-  bfd_vma address;
+  /* 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;
 
-  table = nds32_elf_hash_table (info);
-  target_optimize = table->target_optimize;
-  while (ptr)
-    {
-      irel_ptr = ptr->irel_head;
-      if (ptr->h == NULL)
-       {
-         /* Local symbol.  */
-         irel_keeper = irel_ptr;
-         while (irel_ptr && irel_ptr->next)
-           {
-             /* Check there is jump target can be used.  */
-             if ((irel_ptr->next->irel->r_offset
-                  - irel_keeper->irel->r_offset) > 1022)
-               irel_keeper = irel_ptr->next;
-             else
-               {
-                 ptr->enable = 1;
-                 irel_ptr->keep = 0;
-               }
-             irel_ptr = irel_ptr->next;
-           }
-       }
-      else
-       {
-         /* Global symbol.  We have to get the absolute address
-            and decide whether to keep it or not.*/
+  /* Do TLS model conversion once at first.  */
+  nds32_elf_unify_tls_model (abfd, sec, contents, link_info);
 
-         while (irel_ptr)
-           {
-             address = (irel_ptr->irel->r_offset
-                        + irel_ptr->sec->output_section->vma
-                        + irel_ptr->sec->output_offset);
-             irel_ptr->addr = address;
-             irel_ptr = irel_ptr->next;
-           }
+  /* The optimization type to do.  */
 
-         irel_ptr = ptr->irel_head;
-         while (irel_ptr)
-           {
-             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;
+  table = nds32_elf_hash_table (link_info);
 
-             while (irel_temp->next)
-               {
-                 if (irel_temp->next->addr < irel_dest->addr)
-                   {
-                     irel_dest_prev = irel_temp;
-                     irel_dest = irel_temp->next;
-                   }
-                 irel_temp = irel_temp->next;
-               }
-             if (irel_dest != irel_ptr)
-               {
-                 if (irel_ptr_prev)
-                   irel_ptr_prev->next = irel_dest;
-                 if (irel_dest_prev)
-                   irel_dest_prev->next = irel_ptr;
-                 irel_temp = irel_ptr->next;
-                 irel_ptr->next = irel_dest->next;
-                 irel_dest->next = irel_temp;
-               }
-             irel_ptr_prev = irel_ptr;
-             irel_ptr = irel_ptr->next;
-           }
+  /* Save the first section for abs symbol relaxation.
+     This is used for checking gp relaxation in the
+     nds32_elf_relax_loadstore and nds32_elf_relax_lo12.  */
+  nds32_elf_relax_guard (NULL, 0, sec, NULL, again, TRUE,
+                        table, NULL, NULL);
 
-         irel_ptr = ptr->irel_head;
-         irel_keeper = irel_ptr;
-         while (irel_ptr && irel_ptr->next)
-           {
-             if ((irel_ptr->next->addr - irel_keeper->addr) > 1022)
-               irel_keeper = irel_ptr->next;
-             else
-               {
-                 ptr->enable = 1;
-                 irel_ptr->keep = 0;
-               }
-             irel_ptr = irel_ptr->next;
-           }
-       }
+  /* The begining of general relaxation.  */
 
-       /* Ex9 enable. Reserve it for ex9.  */
-      if ((target_optimize & NDS32_RELAX_EX9_ON)
-         && ptr->irel_head != irel_keeper)
-       ptr->enable = 0;
-      ptr = ptr->next;
+  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);
     }
-}
 
-/* Determine whether j and jal should be substituted after ex9 done.  */
+  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;
 
-static void
-nds32_elf_ifc_filter_after_ex9 (void)
-{
-  struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
-  struct elf_nds32_ifc_irel_list *irel_ptr = NULL;
+  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;
 
-  while (ptr)
+  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY)
     {
-      if (ptr->enable == 0)
-       {
-         /* Check whether ifc is applied or not.  */
-         irel_ptr = ptr->irel_head;
-         ptr->ex9_enable = 1;
-         while (irel_ptr)
-           {
-             if (ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN)
-               {
-                 /* Ex9 already.  */
-                 ptr->ex9_enable = 0;
-                 break;
-               }
-             irel_ptr = irel_ptr->next;
-           }
-       }
-      ptr = ptr->next;
-    }
-}
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG)
+       return TRUE;
 
-/* Wrapper to do ifc relaxation.  */
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG)
+       optimize = 1;
 
-bfd_boolean
-nds32_elf_ifc_finish (struct bfd_link_info *info)
-{
-  int relax_status;
-  struct elf_nds32_link_hash_table *table;
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG)
+       opt_size = 1;
+    }
 
-  table = nds32_elf_hash_table (info);
-  relax_status = table->relax_status;
+  load_store_relax = table->load_store_relax;
 
-  if (!(relax_status & NDS32_RELAX_JUMP_IFC_DONE))
-    nds32_elf_ifc_filter (info);
-  else
-    nds32_elf_ifc_filter_after_ex9 ();
+  /* Get symbol table and section content.  */
+  if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)
+      || !nds32_get_local_syms (abfd, sec, &isymbuf))
+    goto error_return;
 
-  if (!nds32_elf_ifc_replace (info))
-    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++)
+    {
+      int seq_len;             /* Original length of instruction sequence.  */
+      int insn_len = 0;                /* Final length of instruction sequence.  */
+      bfd_boolean removed;
 
-  if (table)
-    table->relax_status |= NDS32_RELAX_JUMP_IFC_DONE;
-  return TRUE;
-}
+      insn = 0;
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
+         && (irel->r_addend & 0x1f) >= 2)
+       optimize = 1;
 
-/* Traverse the result of ifc filter and replace it with ifcall9.  */
+      /* 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);
 
-static bfd_boolean
-nds32_elf_ifc_replace (struct bfd_link_info *info)
-{
-  struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
-  struct elf_nds32_ifc_irel_list *irel_ptr = NULL;
-  nds32_elf_blank_t *relax_blank_list = NULL;
-  bfd_byte *contents = NULL;
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Rela *irelend;
-  unsigned short insn16 = INSN_IFCALL9;
-  struct elf_nds32_link_hash_table *table;
-  int relax_status;
+      /* 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
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LSI)
+       seq_len = 0;
+      else
+       continue;
 
-  table = nds32_elf_hash_table (info);
-  relax_status = table->relax_status;
+      insn_len = seq_len;
+      removed = FALSE;
 
-  while (ptr)
-    {
-      /* 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))
+      switch (ELF32_R_TYPE (irel->r_info))
        {
-         irel_ptr = ptr->irel_head;
-         if (ptr->h == NULL)
-           {
-             /* Local symbol.  */
-             internal_relocs = _bfd_elf_link_read_relocs
-               (ptr->sec->owner, ptr->sec, NULL, NULL, TRUE /* keep_memory */);
-             irelend = internal_relocs + ptr->sec->reloc_count;
+       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, table);
+         break;
+       case R_NDS32_LO12S0_RELA:
+       case R_NDS32_LO12S1_RELA:
+       case R_NDS32_LO12S2_RELA:
+       case R_NDS32_LO12S2_DP_RELA:
+       case R_NDS32_LO12S2_SP_RELA:
+         /* Relax for low part.  */
+         nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs,
+                               contents, isymbuf, symtab_hdr, table);
 
-             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, &contents))
-               return FALSE;
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_PTR:
+         removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs,
+                                        &insn_len, &seq_len, contents);
+         break;
+       case R_NDS32_LSI:
+         nds32_elf_relax_flsi (link_info, abfd, sec, irel, internal_relocs,
+                               contents, isymbuf, symtab_hdr, again);
+         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:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_LE_ADD:
+       case R_NDS32_TLS_LE_LS:
+       case R_NDS32_PLT_GOT_SUFF:
+       case R_NDS32_GOT_SUFF:
+       case R_NDS32_GOTOFF_SUFF:
+         continue;
+       default:
+         continue;
+       }
 
-             while (irel_ptr)
-               {
-                 if (irel_ptr->keep == 0 && irel_ptr->next)
-                   {
-                     /* 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)
-                             || (irel_ptr->next->keep == 1 && irel < irelend))
-                            && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
-                                 && (irel->r_addend & 0x1f) == 2))
-                       irel++;
-                     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))
-                       {
-                         /* Replace by ifcall9.  */
-                         bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
-                         if (!insert_nds32_elf_blank_recalc_total
-                             (&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);
-                       }
-                   }
-                 irel_ptr = irel_ptr->next;
-               }
+      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;
+       }
+    }
 
-             /* Delete the redundant code.  */
-             if (relax_blank_list)
-               {
-                 nds32_elf_relax_delete_blanks (ptr->sec->owner, ptr->sec,
-                                                relax_blank_list);
-                 relax_blank_list = NULL;
-               }
-           }
-         else
-           {
-             /* Global symbol.  */
-             while (irel_ptr)
-               {
-                 if (irel_ptr->keep == 0 && irel_ptr->next)
-                   {
-                     /* The one can be replaced, and we have to check
-                        whether there is any alignment point in the region.  */
-                     internal_relocs = _bfd_elf_link_read_relocs
-                       (irel_ptr->sec->owner, irel_ptr->sec, NULL, NULL,
-                        TRUE /* keep_memory */);
-                     irelend = internal_relocs + irel_ptr->sec->reloc_count;
-                     if (!nds32_get_section_contents
-                            (irel_ptr->sec->owner, irel_ptr->sec, &contents))
-                       return FALSE;
+  calc_nds32_blank_total (relax_blank_list);
 
-                     irel = irel_ptr->irel;
-                     while (((irel_ptr->sec == irel_ptr->next->sec
-                              && irel_ptr->next->keep == 0
-                              && irel < irel_ptr->next->irel)
-                             || ((irel_ptr->sec != irel_ptr->next->sec
-                                  || irel_ptr->next->keep == 1)
-                                 && irel < irelend))
-                            && !(ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
-                                 && (irel->r_addend & 0x1f) == 2))
-                       irel++;
-                     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))
-                       {
-                         /* Replace by ifcall9.  */
-                         bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
-                         if (!insert_nds32_elf_blank_recalc_total
-                             (&relax_blank_list, irel_ptr->irel->r_offset + 2, 2))
-                           return FALSE;
-
-                         /* Delete the redundant code, and clear the relocation.  */
-                         nds32_elf_relax_delete_blanks (irel_ptr->sec->owner,
-                                                        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);
-                         relax_blank_list = NULL;
-                       }
-                   }
+  if (table->relax_fp_as_gp)
+    {
+      if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs,
+                                irelend, isymbuf))
+       goto error_return;
 
-                 irel_ptr = irel_ptr->next;
-               }
-           }
+      if (!*again)
+       {
+         if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs,
+                                              irelend))
+           goto error_return;
        }
-      ptr = ptr->next;
     }
 
-  return TRUE;
-}
-
-/* Relocate ifcall.  */
+  if (!*again)
+    {
+      if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents,
+                                    &relax_blank_list, optimize, opt_size))
+       goto error_return;
+    }
 
-bfd_boolean
-nds32_elf_ifc_reloc (void)
-{
-  struct elf_nds32_ifc_symbol_entry *ptr = ifc_symbol_head;
-  struct elf_nds32_ifc_irel_list *irel_ptr = NULL;
-  struct elf_nds32_ifc_irel_list *irel_keeper = NULL;
-  bfd_vma relocation, address;
-  unsigned short insn16;
+  /* 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.  */
 
-  bfd_byte *contents = NULL;
+  if (relax_blank_list)
+    {
+      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
+      relax_blank_list = NULL;
+    }
 
-  while (ptr)
+  if (!*again)
     {
-      if (ptr->enable == 1 || ptr->ex9_enable == 1)
-       {
-         /* Check the entry is enable ifcall.  */
-         irel_ptr = ptr->irel_head;
-         while (irel_ptr)
-           {
-             if (irel_ptr->keep == 1)
-               {
-                 irel_keeper = irel_ptr;
-                 break;
-               }
-             irel_ptr = irel_ptr->next;
-           }
+      /* Closing the section, so we don't relax it anymore.  */
+      bfd_vma sec_size_align;
+      Elf_Internal_Rela *tmp_rel;
 
-         irel_ptr = ptr->irel_head;
-         if (ptr->h == NULL)
-           {
-             /* Local symbol.  */
-             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, &contents))
-               return FALSE;
+      /* Pad to alignment boundary.  Only handle current section alignment.  */
+      sec_size_align = (sec->size + (~((-1U) << sec->alignment_power)))
+                      & ((-1U) << sec->alignment_power);
+      if ((sec_size_align - sec->size) & 0x2)
+       {
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + sec->size);
+         sec->size += 2;
+       }
 
-             while (irel_ptr)
-               {
-                 if (irel_ptr->keep == 0
-                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN)
-                   {
-                     relocation = irel_keeper->irel->r_offset;
-                     relocation = relocation - irel_ptr->irel->r_offset;
-                     while (irel_keeper && relocation > 1022)
-                       {
-                         irel_keeper = irel_keeper->next;
-                         if (irel_keeper && irel_keeper->keep == 1)
-                           {
-                             relocation = irel_keeper->irel->r_offset;
-                             relocation = relocation - irel_ptr->irel->r_offset;
-                           }
-                       }
-                     if (relocation > 1022)
-                       {
-                         /* Double check.  */
-                         irel_keeper = ptr->irel_head;
-                         while (irel_keeper)
-                           {
-                             if (irel_keeper->keep == 1)
-                               {
-                                 relocation = irel_keeper->irel->r_offset;
-                                 relocation = relocation - irel_ptr->irel->r_offset;
-                               }
-                             if (relocation <= 1022)
-                               break;
-                             irel_keeper = irel_keeper->next;
-                           }
-                         if (!irel_keeper)
-                           return FALSE;
-                       }
+      while (sec_size_align != sec->size)
+       {
+         insn = NDS32_NOP32;
+         bfd_putb32 (insn, contents + sec->size);
+         sec->size += 4;
+       }
 
-                     insn16 = INSN_IFCALL9 | (relocation >> 1);
-                     bfd_putb16 (insn16, contents + irel_ptr->irel->r_offset);
-                   }
-                 irel_ptr = irel_ptr->next;
-               }
-           }
-         else
-           {
-             /* Global symbol.  */
-             while (irel_ptr)
-               {
-                 if (irel_ptr->keep == 0
-                     && ELF32_R_TYPE (irel_ptr->irel->r_info) == R_NDS32_TRAN)
-                   {
-                     relocation = (irel_keeper->irel->r_offset
-                                   + irel_keeper->sec->output_section->vma
-                                   + irel_keeper->sec->output_offset);
-                     address = (irel_ptr->irel->r_offset
-                                + irel_ptr->sec->output_section->vma
-                                + irel_ptr->sec->output_offset);
-                     relocation = relocation - address;
-                     while (irel_keeper && relocation > 1022)
-                       {
-                         irel_keeper = irel_keeper->next;
-                         if (irel_keeper && irel_keeper->keep ==1)
-                           {
-                             relocation = (irel_keeper->irel->r_offset
-                                           + irel_keeper->sec->output_section->vma
-                                           + irel_keeper->sec->output_offset);
-                             relocation = relocation - address;
-                           }
-                       }
+      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;
 
-                     if (relocation > 1022)
-                       {
-                         /* Double check.  */
-                         irel_keeper = ptr->irel_head;
-                         while (irel_keeper)
-                           {
-                             if (irel_keeper->keep == 1)
-                               {
-
-                                 relocation = (irel_keeper->irel->r_offset
-                                               + irel_keeper->sec->output_section->vma
-                                               + irel_keeper->sec->output_offset);
-                                 relocation = relocation - address;
-                               }
-                             if (relocation <= 1022)
-                               break;
-                             irel_keeper = irel_keeper->next;
-                           }
-                         if (!irel_keeper)
-                           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 =irel_ptr->next;
-               }
-           }
-       }
-      ptr = ptr->next;
+      clean_nds32_elf_blank ();
     }
 
-  return TRUE;
-}
+ finish:
+  if (elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
 
-/* End of IFC relaxation.  */
-\f
-/* EX9 Instruction Table Relaxation.  */
+  if (elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
+
+  if (symtab_hdr->contents != (bfd_byte *) isymbuf)
+    free (isymbuf);
+
+  return result;
 
-/* Global hash list.  */
-struct elf_link_hash_entry_list
-{
-  struct elf_link_hash_entry *h;
-  struct elf_link_hash_entry_list *next;
-};
+ error_return:
+  result = FALSE;
+  goto finish;
+}
 
-/* Save different destination but same insn.  */
-struct elf_link_hash_entry_mul_list
+static struct bfd_elf_special_section const nds32_elf_special_sections[] =
 {
-  /* Global symbol times.  */
-  int times;
-  /* Save relocation for each global symbol but useful??  */
-  Elf_Internal_Rela *irel;
-  /* For sethi, two sethi may have the same high-part but different low-parts.  */
-  Elf_Internal_Rela rel_backup;
-  struct elf_link_hash_entry_list *h_list;
-  struct elf_link_hash_entry_mul_list *next;
+  {".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE},
+  {".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE},
+  {NULL, 0, 0, 0, 0}
 };
 
-/* Instruction hash table.  */
-struct elf_nds32_code_hash_entry
+static bfd_boolean
+nds32_elf_section_flags (const Elf_Internal_Shdr *hdr)
 {
-  struct bfd_hash_entry root;
-  int times;
-  /* For insn that can use relocation or constant ex: sethi.  */
-  int const_insn;
-  asection *sec;
-  struct elf_link_hash_entry_mul_list *m_list;
-  /* Using r_addend.  */
-  Elf_Internal_Rela *irel;
-  /* Using r_info.  */
-  Elf_Internal_Rela rel_backup;
-};
+  const char *name = hdr->bfd_section->name;
 
-/* Instruction count list.  */
-struct elf_nds32_insn_times_entry
-{
-  const char *string;
-  int times;
-  int order;
-  asection *sec;
-  struct elf_link_hash_entry_mul_list *m_list;
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Rela rel_backup;
-  struct elf_nds32_insn_times_entry *next;
-};
+  if (strncmp (name, ".sbss", 5) == 0
+      || strncmp (name, ".sdata", 6) == 0)
+    hdr->bfd_section->flags |= SEC_SMALL_DATA;
 
-/* J and JAL symbol list.  */
-struct elf_nds32_symbol_entry
-{
-  char *string;
-  unsigned long insn;
-  struct elf_nds32_symbol_entry *next;
-};
+  return TRUE;
+}
 
-/* Relocation list.  */
-struct elf_nds32_irel_entry
+static bfd_boolean
+nds32_elf_output_arch_syms (bfd *output_bfd ATTRIBUTE_UNUSED,
+                           struct bfd_link_info *info,
+                           void *finfo ATTRIBUTE_UNUSED,
+                           bfd_boolean (*func) (void *, const char *,
+                                                Elf_Internal_Sym *,
+                                                asection *,
+                                                struct elf_link_hash_entry *)
+                           ATTRIBUTE_UNUSED)
 {
-  Elf_Internal_Rela *irel;
-  struct elf_nds32_irel_entry *next;
-};
+  FILE *sym_ld_script = NULL;
+  struct elf_nds32_link_hash_table *table;
 
-/* ex9.it insn need to be fixed.  */
-struct elf_nds32_ex9_refix
-{
-  Elf_Internal_Rela *irel;
-  asection *sec;
-  struct elf_link_hash_entry *h;
-  int order;
-  struct elf_nds32_ex9_refix *next;
-};
+  table = nds32_elf_hash_table (info);
+  sym_ld_script = table->sym_ld_script;
 
-static struct bfd_hash_table ex9_code_table;
-static struct elf_nds32_insn_times_entry *ex9_insn_head = NULL;
-static struct elf_nds32_ex9_refix *ex9_refix_head = NULL;
+  if (check_start_export_sym)
+    fprintf (sym_ld_script, "}\n");
 
-/* EX9 hash function.  */
+  return TRUE;
+}
 
-static struct bfd_hash_entry *
-nds32_elf_code_hash_newfunc (struct bfd_hash_entry *entry,
-                            struct bfd_hash_table *table,
-                            const char *string)
+static enum elf_reloc_type_class
+nds32_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                           const asection *rel_sec ATTRIBUTE_UNUSED,
+                           const Elf_Internal_Rela *rela)
 {
-  struct elf_nds32_code_hash_entry *ret;
-
-  /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
-  if (entry == NULL)
+  switch ((int) ELF32_R_TYPE (rela->r_info))
     {
-      entry = (struct bfd_hash_entry *)
-       bfd_hash_allocate (table, sizeof (*ret));
-      if (entry == NULL)
-       return entry;
+    case R_NDS32_RELATIVE:
+      return reloc_class_relative;
+    case R_NDS32_JMP_SLOT:
+      return reloc_class_plt;
+    case R_NDS32_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
     }
-
-  /* Call the allocation method of the superclass.  */
-  entry = bfd_hash_newfunc (entry, table, string);
-  if (entry == NULL)
-    return entry;
-
-  ret = (struct elf_nds32_code_hash_entry*) entry;
-  ret->times = 0;
-  ret->const_insn = 0;
-  ret->m_list = NULL;
-  ret->sec = NULL;
-  ret->irel = NULL;
-  return &ret->root;
 }
 
-/* Insert ex9 entry
-   this insert must be stable sorted by times.  */
-
-static void
-nds32_elf_ex9_insert_entry (struct elf_nds32_insn_times_entry *ptr)
+/* Put target dependent option into info hash table.  */
+void
+bfd_elf32_nds32_set_target_option (struct bfd_link_info *link_info,
+                                  int relax_fp_as_gp,
+                                  int eliminate_gc_relocs,
+                                  FILE * sym_ld_script,
+                                  int hyper_relax,
+                                  int tls_desc_trampoline,
+                                  int load_store_relax)
 {
-  struct elf_nds32_insn_times_entry *temp;
-  struct elf_nds32_insn_times_entry *temp2;
+  struct elf_nds32_link_hash_table *table;
 
-  if (ex9_insn_head == NULL)
-    {
-      ex9_insn_head = ptr;
-      ptr->next = NULL;
-    }
-  else
-    {
-      temp = ex9_insn_head;
-      temp2 = ex9_insn_head;
-      while (temp->next &&
-            (temp->next->times >= ptr->times
-             || temp->times == -1))
-       {
-         if (temp->times == -1)
-           temp2 = temp;
-         temp = temp->next;
-       }
-      if (ptr->times > temp->times && temp->times != -1)
-       {
-         ptr->next = temp;
-         if (temp2->times == -1)
-           temp2->next = ptr;
-         else
-           ex9_insn_head = ptr;
-       }
-      else if (temp->next == NULL)
-       {
-         temp->next = ptr;
-         ptr->next = NULL;
-       }
-      else
-       {
-         ptr->next = temp->next;
-         temp->next = ptr;
-       }
-    }
+  table = nds32_elf_hash_table (link_info);
+  if (table == NULL)
+    return;
+
+  table->relax_fp_as_gp = relax_fp_as_gp;
+  table->eliminate_gc_relocs = eliminate_gc_relocs;
+  table->sym_ld_script = sym_ld_script;
+  table->hyper_relax = hyper_relax;
+  table->tls_desc_trampoline = tls_desc_trampoline;
+  table ->load_store_relax = load_store_relax;
 }
+\f
 
-/* Examine each insn times in hash table.
-   Handle multi-link hash entry.
+/* These functions and data-structures are used for fp-as-gp
+   optimization.  */
 
-   TODO: This function doesn't assign so much info since it is fake.  */
+#define FAG_THRESHOLD  3       /* At least 3 gp-access.  */
+/* 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)
 
-static int
-nds32_elf_examine_insn_times (struct elf_nds32_code_hash_entry *h)
+/* An nds32_fag represent a gp-relative access.
+   We find best fp-base by using a sliding window
+   to find a base address which can cover most gp-access.  */
+struct nds32_fag
 {
-  struct elf_nds32_insn_times_entry *ptr;
-  int times;
-
-  if (h->m_list == NULL)
-    {
-      /* Local symbol insn or insn without relocation.  */
-      if (h->times < 3)
-       return TRUE;
+  struct nds32_fag *next;      /* NULL-teminated linked list.  */
+  bfd_vma addr;                        /* The address of this fag.  */
+  Elf_Internal_Rela **relas;   /* The relocations associated with this fag.
+                                  It is used for applying FP7U2_FLAG.  */
+  int count;                   /* How many times this address is referred.
+                                  There should be exactly `count' relocations
+                                  in relas.  */
+  int relas_capcity;           /* The buffer size of relas.
+                                  We use an array instead of linked-list,
+                                  and realloc is used to adjust buffer size.  */
+};
 
-      ptr = (struct elf_nds32_insn_times_entry *)
-       bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-      ptr->times = h->times;
-      ptr->string = h->root.string;
-      ptr->m_list = NULL;
-      ptr->sec = h->sec;
-      ptr->irel = h->irel;
-      ptr->rel_backup = h->rel_backup;
-      nds32_elf_ex9_insert_entry (ptr);
-    }
-  else
-    {
-      /* Global symbol insn.  */
-      /* Only sethi insn has multiple m_list.  */
-      struct elf_link_hash_entry_mul_list *m_list = h->m_list;
+static void
+nds32_fag_init (struct nds32_fag *head)
+{
+  memset (head, 0, sizeof (struct nds32_fag));
+}
 
-      times = 0;
-      while (m_list)
-       {
-         times += m_list->times;
-         m_list = m_list->next;
-       }
-      if (times >= 3)
-       {
-         m_list = h->m_list;
-         ptr = (struct elf_nds32_insn_times_entry *)
-           bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-         ptr->times = times; /* Use the total times.  */
-         ptr->string = h->root.string;
-         ptr->m_list = m_list;
-         ptr->sec = h->sec;
-         ptr->irel = m_list->irel;
-         ptr->rel_backup = m_list->rel_backup;
-         nds32_elf_ex9_insert_entry (ptr);
-       }
-      if (h->const_insn == 1)
-       {
-         /* sethi with constant value.  */
-         if (h->times < 3)
-           return TRUE;
+static void
+nds32_fag_verify (struct nds32_fag *head)
+{
+  struct nds32_fag *iter;
+  struct nds32_fag *prev;
 
-         ptr = (struct elf_nds32_insn_times_entry *)
-           bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-         ptr->times = h->times;
-         ptr->string = h->root.string;
-         ptr->m_list = NULL;
-         ptr->sec = NULL;
-         ptr->irel = NULL;
-         ptr->rel_backup = h->rel_backup;
-         nds32_elf_ex9_insert_entry (ptr);
-       }
+  prev = NULL;
+  iter = head->next;
+  while (iter)
+    {
+      if (prev && prev->addr >= iter->addr)
+       puts ("Bug in fp-as-gp insertion.");
+      prev = iter;
+      iter = iter->next;
     }
-  return TRUE;
 }
 
-/* Count each insn times in hash table.
-   Handle multi-link hash entry.  */
+/* Insert a fag in ascending order.
+   If a fag of the same address already exists,
+   they are chained by relas array.  */
 
-static int
-nds32_elf_count_insn_times (struct elf_nds32_code_hash_entry *h)
+static void
+nds32_fag_insert (struct nds32_fag *head, bfd_vma addr,
+                 Elf_Internal_Rela * rel)
 {
-  int reservation, times;
-  unsigned long relocation, min_relocation;
-  struct elf_nds32_insn_times_entry *ptr;
-
-  if (h->m_list == NULL)
-    {
-      /* Local symbol insn or insn without relocation.  */
-      if (h->times < 3)
-       return TRUE;
-      ptr = (struct elf_nds32_insn_times_entry *)
-       bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-      ptr->times = h->times;
-      ptr->string = h->root.string;
-      ptr->m_list = NULL;
-      ptr->sec = h->sec;
-      ptr->irel = h->irel;
-      ptr->rel_backup = h->rel_backup;
-      nds32_elf_ex9_insert_entry (ptr);
-    }
-  else
-    {
-      /* Global symbol insn.  */
-      /* Only sethi insn has multiple m_list.  */
-      struct elf_link_hash_entry_mul_list *m_list = h->m_list;
+  struct nds32_fag *iter;
+  struct nds32_fag *new_fag;
+  const int INIT_RELAS_CAP = 4;
 
-      if (ELF32_R_TYPE (m_list->rel_backup.r_info) == R_NDS32_HI20_RELA
-         && m_list->next != NULL)
-       {
-         /* Sethi insn has different symbol or addend but has same hi20.  */
-         times = 0;
-         reservation = 1;
-         relocation = 0;
-         min_relocation = 0xffffffff;
-         while (m_list)
-           {
-             /* Get the minimum sethi address
-                and calculate how many entry the sethi-list have to use.  */
-             if ((m_list->h_list->h->root.type == bfd_link_hash_defined
-                  || m_list->h_list->h->root.type == bfd_link_hash_defweak)
-                 && (m_list->h_list->h->root.u.def.section != NULL
-                     && m_list->h_list->h->root.u.def.section->output_section != NULL))
-               {
-                 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);
-                 relocation += m_list->irel->r_addend;
-               }
-             else
-               relocation = 0;
-             if (relocation < min_relocation)
-               min_relocation = relocation;
-             times += m_list->times;
-             m_list = m_list->next;
-           }
-         if (min_relocation < ex9_relax_size)
-           reservation = (min_relocation >> 12) + 1;
-         else
-           reservation = (min_relocation >> 12)
-                         - ((min_relocation - ex9_relax_size) >> 12) + 1;
-         if (reservation < (times / 3))
-           {
-             /* Efficient enough to use ex9.  */
-             int i;
+  for (iter = head;
+       iter->next && iter->next->addr <= addr;
+       iter = iter->next)
+    /* Find somewhere to insert.  */ ;
 
-             for (i = reservation ; i > 0; i--)
-               {
-                 /* Allocate number of reservation ex9 entry.  */
-                 ptr = (struct elf_nds32_insn_times_entry *)
-                   bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-                 ptr->times = h->m_list->times / reservation;
-                 ptr->string = h->root.string;
-                 ptr->m_list = h->m_list;
-                 ptr->sec = h->sec;
-                 ptr->irel = h->m_list->irel;
-                 ptr->rel_backup = h->m_list->rel_backup;
-                 nds32_elf_ex9_insert_entry (ptr);
-               }
-           }
-       }
-      else
-       {
-         /* Normal global symbol that means no different address symbol
-            using same ex9 entry.  */
-         if (m_list->times >= 3)
-           {
-             ptr = (struct elf_nds32_insn_times_entry *)
-               bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-             ptr->times = m_list->times;
-             ptr->string = h->root.string;
-             ptr->m_list = h->m_list;
-             ptr->sec = h->sec;
-             ptr->irel = h->m_list->irel;
-             ptr->rel_backup = h->m_list->rel_backup;
-             nds32_elf_ex9_insert_entry (ptr);
-           }
-       }
+  /* `iter' will be equal to `head' if the list is empty.  */
+  if (iter != head && iter->addr == addr)
+    {
+      /* The address exists in the list.
+        Insert `rel' into relocation list, relas.  */
 
-      if (h->const_insn == 1)
+      /* Check whether relas is big enough.  */
+      if (iter->count >= iter->relas_capcity)
        {
-         /* sethi with constant value.  */
-         if (h->times < 3)
-           return TRUE;
-
-         ptr = (struct elf_nds32_insn_times_entry *)
-           bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-         ptr->times = h->times;
-         ptr->string = h->root.string;
-         ptr->m_list = NULL;
-         ptr->sec = NULL;
-         ptr->irel = NULL;
-         ptr->rel_backup = h->rel_backup;
-         nds32_elf_ex9_insert_entry (ptr);
+         iter->relas_capcity *= 2;
+         iter->relas = bfd_realloc
+           (iter->relas, iter->relas_capcity * sizeof (void *));
        }
+      iter->relas[iter->count++] = rel;
+      return;
     }
 
-  return TRUE;
-}
+  /* This is a new address.  Create a fag node for it.  */
+  new_fag = bfd_malloc (sizeof (struct nds32_fag));
+  memset (new_fag, 0, sizeof (*new_fag));
+  new_fag->addr = addr;
+  new_fag->count = 1;
+  new_fag->next = iter->next;
+  new_fag->relas_capcity = INIT_RELAS_CAP;
+  new_fag->relas = (Elf_Internal_Rela **)
+    bfd_malloc (new_fag->relas_capcity * sizeof (void *));
+  new_fag->relas[0] = rel;
+  iter->next = new_fag;
 
-/* Hash table traverse function.  */
+  nds32_fag_verify (head);
+}
 
 static void
-nds32_elf_code_hash_traverse (int (*func) (struct elf_nds32_code_hash_entry*))
+nds32_fag_free_list (struct nds32_fag *head)
 {
-  unsigned int i;
+  struct nds32_fag *iter;
 
-  ex9_code_table.frozen = 1;
-  for (i = 0; i < ex9_code_table.size; i++)
+  iter = head->next;
+  while (iter)
     {
-      struct bfd_hash_entry *p;
-
-      for (p = ex9_code_table.table[i]; p != NULL; p = p->next)
-       if (!func ((struct elf_nds32_code_hash_entry *) p))
-         goto out;
+      struct nds32_fag *tmp = iter;
+      iter = iter->next;
+      free (tmp->relas);
+      tmp->relas = NULL;
+      free (tmp);
     }
-out:
-  ex9_code_table.frozen = 0;
 }
 
+/* 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.
 
-/* Give order number to insn list.  */
+   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
+   are different, their distance may change too.
+   Therefore, tracking a fixed address is not appriate.  */
 
-static void
-nds32_elf_order_insn_times (struct bfd_link_info *info)
+static int
+nds32_fag_find_base (struct nds32_fag *head, struct nds32_fag **bestpp)
 {
-  struct elf_nds32_insn_times_entry *ex9_insn;
-  struct elf_nds32_insn_times_entry *temp;
-  struct elf_nds32_link_hash_table *table;
-  char *insn;
-  int ex9_limit;
-  int number = 0, total = 0;
-  struct bfd_link_hash_entry *bh;
+  struct nds32_fag *base;      /* First fag in the window.  */
+  struct nds32_fag *last;      /* First fag outside the window.  */
+  int accu = 0;                        /* Usage accumulation.  */
+  struct nds32_fag *best;      /* Best fag.  */
+  int baccu = 0;               /* Best accumulation.  */
 
-/* The max number of entries is 512.  */
-  ex9_insn = ex9_insn_head;
-  table = nds32_elf_hash_table (info);
-  ex9_limit = table->ex9_limit;
+  /* Use first fag for initial, and find the last fag in the window.
+
+     In each iteration, we could simply subtract previous fag
+     and accumulate following fags which are inside the window,
+     untill we each the end.  */
 
-  /* Get the minimun one of ex9 list and limitation.  */
-  while (ex9_insn)
+  if (head->next == NULL)
     {
-      total++;
-      ex9_insn = ex9_insn->next;
+      *bestpp = NULL;
+      return 0;
     }
-  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;
+  /* Initialize base.  */
+  base = head->next;
+  best = base;
+  for (last = base;
+       last && last->addr < base->addr + FAG_WINDOW;
+       last = last->next)
+    accu += last->count;
 
-  ex9_insn = ex9_insn_head;
+  baccu = accu;
 
-  while (ex9_insn != NULL && number <= ex9_limit)
+  /* Record the best base in each iteration.  */
+  while (base->next)
     {
-      /* 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;
-
-      number++;
+      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;
 
-      if (number == 234)
+      /* A better fp-base?  */
+      if (accu > baccu)
        {
-         /* 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;
+         best = base;
+         baccu = accu;
        }
-      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;
-    }
-
-  while (ex9_insn != NULL)
-    {
-      /* Free useless entry.  */
-      temp = ex9_insn;
-      ex9_insn = ex9_insn->next;
-      free (temp);
-    }
+  if (bestpp)
+    *bestpp = best;
+  return baccu;
 }
 
-/* Build .ex9.itable section.  */
+/* Apply R_NDS32_INSN16_FP7U2_FLAG on gp-relative accesses,
+   so we can convert it fo fp-relative access later.
+   `best_fag' is the best fp-base.  Only those inside the window
+   of best_fag is applied the flag.  */
 
-static void
-nds32_elf_ex9_build_itable (struct bfd_link_info *link_info)
+static bfd_boolean
+nds32_fag_mark_relax (struct bfd_link_info *link_info,
+                     asection *sec, struct nds32_fag *best_fag,
+                     Elf_Internal_Rela *internal_relocs,
+                     Elf_Internal_Rela *irelend)
 {
-  asection *table_sec;
-  struct elf_nds32_insn_times_entry *ptr;
-  bfd *it_abfd;
-  int number = 0;
-  bfd_byte *contents = NULL;
+  struct nds32_fag *ifag;
+  bfd_vma best_fpbase, gp;
+  bfd *output_bfd;
+
+  output_bfd = sec->output_section->owner;
+  nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
+  best_fpbase = best_fag->addr;
 
-  for (it_abfd = link_info->input_bfds; it_abfd != NULL;
-       it_abfd = it_abfd->link_next)
+  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,
+     so we know they can be converted to lwi37.fp.   */
+  for (ifag = best_fag;
+       ifag && ifag->addr < best_fpbase + FAG_WINDOW; ifag = ifag->next)
     {
-      /* Find the section .ex9.itable, and put all entries into it.  */
-      table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable");
-      if (table_sec != NULL)
-       {
-         if (!nds32_get_section_contents (it_abfd, table_sec, &contents))
-           return;
+      int i;
 
-         for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next)
-           number++;
+      for (i = 0; i < ifag->count; i++)
+       {
+         Elf_Internal_Rela *insn16_rel;
+         Elf_Internal_Rela *fag_rel;
 
-         table_sec->size = number * 4;
+         fag_rel = ifag->relas[i];
 
-         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;
-           }
+         /* Only if this is within the WINDOWS, FP7U2_FLAG
+            is applied.  */
 
-         elf_elfheader (link_info->output_bfd)->e_flags |= E_NDS32_HAS_EX9_INST;
-         number = 0;
-         for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next)
-           {
-             long val;
+         insn16_rel = find_relocs_at_address
+           (fag_rel, internal_relocs, irelend, R_NDS32_INSN16);
 
-             val = strtol (ptr->string, NULL, 16);
-             bfd_putb32 ((bfd_vma) val, (char *) contents + (number * 4));
-             number++;
-           }
-         break;
+         if (insn16_rel != irelend)
+           insn16_rel->r_addend = R_NDS32_INSN16_FP7U2_FLAG;
        }
     }
+  return TRUE;
 }
 
-/* Get insn with regs according to relocation type.  */
+/* Reset INSN16 to clean fp as gp.  */
 
 static void
-nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel,
-                            unsigned long insn, unsigned long *insn_with_reg)
+nds32_fag_unmark_relax (struct nds32_fag *fag,
+                       Elf_Internal_Rela *internal_relocs,
+                       Elf_Internal_Rela *irelend)
 {
-  reloc_howto_type *howto = NULL;
+  struct nds32_fag *ifag;
+  int i;
+  Elf_Internal_Rela *insn16_rel;
+  Elf_Internal_Rela *fag_rel;
 
-  if (irel == NULL
-      || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table)
-         && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY)
-            >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table)))
+  for (ifag = fag; ifag; ifag = ifag->next)
     {
-      *insn_with_reg = insn;
-      return;
-    }
+      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);
 
-  howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info));
-  *insn_with_reg = insn & (0xffffffff ^ howto->dst_mask);
+         if (insn16_rel != irelend)
+           insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG;
+       }
+    }
 }
 
-/* Mask number of address bits according to relocation.  */
+/* This is the main function of fp-as-gp optimization.
+   It should be called by relax_section.  */
 
-static unsigned long
-nds32_elf_irel_mask (Elf_Internal_Rela *irel)
+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,
+                     Elf_Internal_Sym *isymbuf)
 {
-  reloc_howto_type *howto = NULL;
+  Elf_Internal_Rela *begin_rel = NULL;
+  Elf_Internal_Rela *irel;
+  struct nds32_fag fag_head;
+  Elf_Internal_Shdr *symtab_hdr;
+  bfd_byte *contents;
+  bfd_boolean ifc_inside = FALSE;
 
-  if (irel == NULL
-      || (ELF32_R_TYPE (irel->r_info) >= (int) ARRAY_SIZE (nds32_elf_howto_table)
-         && (ELF32_R_TYPE (irel->r_info) - R_NDS32_RELAX_ENTRY)
-            >= (int) ARRAY_SIZE (nds32_elf_relax_howto_table)))
-    return 0;
+  /* FIXME: Can we bfd_elf_link_read_relocs for the relocs?  */
 
-  howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info));
-  return howto->dst_mask;
-}
+  /* Per-function fp-base selection.
+     1. Create a list for all the gp-relative access.
+     2. Base on those gp-relative address,
+       find a fp-base which can cover most access.
+     3. Use the fp-base for fp-as-gp relaxation.
 
-static void
-nds32_elf_insert_irel_entry (struct elf_nds32_irel_entry **irel_list,
-                            struct elf_nds32_irel_entry *irel_ptr)
-{
-  if (*irel_list == NULL)
-    {
-      *irel_list = irel_ptr;
-      irel_ptr->next = NULL;
-    }
-  else
-    {
-      irel_ptr->next = *irel_list;
-      *irel_list = irel_ptr;
-    }
-}
+     NOTE: If fp-as-gp is not worth to do, (e.g., less than 3 times),
+     we should
+     1. delete the `la $fp, _FP_BASE_' instruction and
+     2. not convert lwi.gp to lwi37.fp.
 
-static void
-nds32_elf_ex9_insert_fix (asection * sec, Elf_Internal_Rela * irel,
-                         struct elf_link_hash_entry *h, int order)
-{
-  struct elf_nds32_ex9_refix *ptr;
+     To delete the _FP_BASE_ instruction, we simply apply
+     R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG flag in the r_addend to disable it.
 
-  ptr = bfd_malloc (sizeof (struct elf_nds32_ex9_refix));
-  ptr->sec = sec;
-  ptr->irel = irel;
-  ptr->h = h;
-  ptr->order = order;
-  ptr->next = NULL;
+     To suppress the conversion, we simply NOT to apply
+     R_NDS32_INSN16_FP7U2_FLAG flag.  */
 
-  if (ex9_refix_head == NULL)
-    ex9_refix_head = ptr;
-  else
-    {
-      struct elf_nds32_ex9_refix *temp = ex9_refix_head;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
-      while (temp->next != NULL)
-       temp = temp->next;
-      temp->next = ptr;
-    }
-}
+  if (!nds32_get_section_contents (abfd, sec, &contents, TRUE)
+      || !nds32_get_local_syms (abfd, sec, &isymbuf))
+    return FALSE;
 
-enum
-{
-  DATA_EXIST = 1,
-  CLEAN_PRE = 1 << 1,
-  PUSH_PRE = 1 << 2
-};
+  /* Check whether it is worth for fp-as-gp optimization,
+     i.e., at least 3 gp-load.
 
-/* Check relocation type if supporting for ex9.  */
+     Set R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG if we should NOT
+     apply this optimization.  */
 
-static int
-nds32_elf_ex9_relocation_check (struct bfd_link_info *info,
-                               Elf_Internal_Rela **irel,
-                               Elf_Internal_Rela *irelend,
-                               nds32_elf_blank_t *relax_blank_list,
-                               asection *sec,
-                               long unsigned int *off,
-                               bfd_byte *contents)
-{
-  /* Suppress ex9 if `.no_relax ex9' or inner loop.  */
-  bfd_boolean nested_ex9, nested_loop;
-  bfd_boolean ex9_loop_aware;
-  /* We use the highest 1 byte of result to record
-     how many bytes location counter has to move.  */
-  int result = 0;
-  Elf_Internal_Rela *irel_save = NULL;
-  struct elf_nds32_link_hash_table *table;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      /* We recognize R_NDS32_RELAX_REGION_BEGIN/_END for the region.
+        One we enter the begin of the region, we track all the LW/ST
+        instructions, so when we leave the region, we try to find
+        the best fp-base address for those LW/ST instructions.  */
 
-  table = nds32_elf_hash_table (info);
-  ex9_loop_aware = table->ex9_loop_aware;
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
+         && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG))
+       {
+         /* Begin of the region.  */
+         if (begin_rel)
+           /* xgettext:c-format */
+           _bfd_error_handler (_("%pB: nested OMIT_FP in %pA"), abfd, sec);
 
-  while ((*irel) != NULL && (*irel) < irelend && *off == (*irel)->r_offset)
-    {
-      switch (ELF32_R_TYPE ((*irel)->r_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))
        {
-       case R_NDS32_RELAX_REGION_BEGIN:
-         /* Ignore code block.  */
-         nested_ex9 = FALSE;
-         nested_loop = FALSE;
-         if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG)
-             || (ex9_loop_aware
-                 && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG)))
-           {
-             /* Check the region if loop or not.  If it is true and
-                ex9-loop-aware is true, ignore the region till region end.  */
-             /* To save the status for in .no_relax ex9 region and
-                loop region to conform the block can do ex9 relaxation.  */
-             nested_ex9 = ((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG);
-             nested_loop = (ex9_loop_aware
-                            && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG));
-             while ((*irel) && (*irel) < irelend && (nested_ex9 || nested_loop))
-               {
-                 (*irel)++;
-                 if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_BEGIN)
-                   {
-                     /* There may be nested region.  */
-                     if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0)
-                       nested_ex9 = TRUE;
-                     else if (ex9_loop_aware
-                              && ((*irel)->r_addend & R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG))
-                       nested_loop = TRUE;
-                   }
-                 else if (ELF32_R_TYPE ((*irel)->r_info) == R_NDS32_RELAX_REGION_END)
-                   {
-                     /* The end of region.  */
-                     if (((*irel)->r_addend & R_NDS32_RELAX_REGION_NO_EX9_FLAG) != 0)
-                       nested_ex9 = FALSE;
-                     else if (ex9_loop_aware
-                              && ((*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
-                          && ((*irel)->r_addend & 0x1f) == 2)
-                   {
-                     /* Alignment exist in the region.  */
-                     result |= CLEAN_PRE;
-                     if (((*irel)->r_offset -
-                          get_nds32_elf_blank_total (&relax_blank_list,
-                                                     (*irel)->r_offset, 0)) & 0x02)
-                       result |= PUSH_PRE;
-                   }
-               }
-             if ((*irel) >= irelend)
-               *off = sec->size;
-             else
-               *off = (*irel)->r_offset;
+         int accu;
+         struct nds32_fag *best_fag, *tmp_fag;
+         int dist;
 
-             /* The final instruction in the region, regard this one as data to ignore it.  */
-             result |= DATA_EXIST;
-             return result;
-           }
-         break;
+         /* End of the region.
+            Check whether it is worth to do fp-as-gp.  */
 
-       case R_NDS32_LABEL:
-         if (relax_blank_list && ((*irel)->r_addend & 0x1f) == 2)
+         if (begin_rel == NULL)
            {
-             /* Check this point is align and decide to do ex9 or not.  */
-             result |= CLEAN_PRE;
-             if (((*irel)->r_offset -
-                  get_nds32_elf_blank_total (&relax_blank_list,
-                                             (*irel)->r_offset, 0)) & 0x02)
-               result |= PUSH_PRE;
+             /* xgettext:c-format */
+             _bfd_error_handler (_("%pB: unmatched OMIT_FP in %pA"),
+                                 abfd, sec);
+             continue;
            }
-         break;
-       case R_NDS32_32_RELA:
-         /* Data.  */
-         result |= (4 << 24);
-         result |= DATA_EXIST;
-         break;
-       case R_NDS32_16_RELA:
-         /* Data.  */
-         result |= (2 << 24);
-         result |= DATA_EXIST;
-         break;
-       case R_NDS32_DATA:
-         /* Data.  */
-         /* The least code alignment is 2.  If the data is only one byte,
-            we have to shift one more byte.  */
-         if ((*irel)->r_addend == 1)
-           result |= ((*irel)->r_addend << 25) ;
-         else
-           result |= ((*irel)->r_addend << 24) ;
 
-         result |= DATA_EXIST;
-         break;
+         accu = nds32_fag_find_base (&fag_head, &best_fag);
 
-       case R_NDS32_25_PCREL_RELA:
-       case R_NDS32_SDA16S3_RELA:
-       case R_NDS32_SDA15S3_RELA:
-       case R_NDS32_SDA15S3:
-       case R_NDS32_SDA17S2_RELA:
-       case R_NDS32_SDA15S2_RELA:
-       case R_NDS32_SDA12S2_SP_RELA:
-       case R_NDS32_SDA12S2_DP_RELA:
-       case R_NDS32_SDA15S2:
-       case R_NDS32_SDA18S1_RELA:
-       case R_NDS32_SDA15S1_RELA:
-       case R_NDS32_SDA15S1:
-       case R_NDS32_SDA19S0_RELA:
-       case R_NDS32_SDA15S0_RELA:
-       case R_NDS32_SDA15S0:
-       case R_NDS32_HI20_RELA:
-       case R_NDS32_LO12S0_ORI_RELA:
-       case R_NDS32_LO12S0_RELA:
-       case R_NDS32_LO12S1_RELA:
-       case R_NDS32_LO12S2_RELA:
-         /* These relocation is supported ex9 relaxation currently.  */
-         /* We have to save the relocation for using later, since we have
-            to check there is any alignment in the same address.  */
-         irel_save = *irel;
-         break;
-       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)
+         /* 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, sec, best_fag,
+                                       internal_relocs, irelend))
            {
-             /* Note: To optimize aggressively, it maybe can ignore R_NDS32_INSN16 here.
-                But we have to consider if there is any side-effect.  */
-             if (!(result & DATA_EXIST))
-               {
-                 /* We have to confirm there is no data relocation in the
-                    same address.  In general case, this won't happen.  */
-                 /* We have to do ex9 conservative, for those relocation not
-                    considerd we ignore instruction.  */
-                 result |= DATA_EXIST;
-                 if (*(contents + *off) & 0x80)
-                   result |= (2 << 24);
-                 else
-                   result |= (4 << 24);
-                 break;
-               }
+             /* Not worth to do fp-as-gp.  */
+             begin_rel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG;
+             begin_rel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
+             irel->r_addend |= R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG;
+             irel->r_addend &= ~R_NDS32_RELAX_REGION_OMIT_FP_FLAG;
+             nds32_fag_free_list (&fag_head);
+             begin_rel = NULL;
+             continue;
            }
+
+         /* R_SYM of R_NDS32_RELAX_REGION_BEGIN is not used by assembler,
+            so we use it to record the distance to the reloction of best
+            fp-base.  */
+         dist = best_fag->relas[0] - begin_rel;
+         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 ((*irel) < irelend
-         && ((*irel) + 1) < irelend
-         && (*irel)->r_offset == ((*irel) + 1)->r_offset)
-       /* There are relocations pointing to the same address, we have to
-          check all of them.  */
-       (*irel)++;
-      else
+
+      if (begin_rel == NULL || ifc_inside)
+       /* Skip if we are not in the region of fp-as-gp.  */
+       continue;
+
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA
+         || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA)
+       {
+         bfd_vma addr;
+         uint32_t insn;
+
+         /* A gp-relative access is found.  Insert it to the fag-list.  */
+
+         /* Rt is necessary an RT3, so it can be converted to lwi37.fp.  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (!N32_IS_RT3 (insn))
+           continue;
+
+         addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+         nds32_fag_insert (&fag_head, addr, irel);
+       }
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA)
        {
-         if (irel_save)
-           *irel = irel_save;
-         return result;
+         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 result;
+
+  return TRUE;
 }
 
-/* Replace input file instruction which is in ex9 itable.  */
+/* Remove unused `la $fp, _FD_BASE_' instruction.  */
 
 static bfd_boolean
-nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asection *sec)
+nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec,
+                               Elf_Internal_Rela *internal_relocs,
+                               Elf_Internal_Rela *irelend)
 {
-  struct elf_nds32_insn_times_entry *ex9_insn = ex9_insn_head;
-  bfd_byte *contents = NULL;
-  long unsigned int off;
-  unsigned short 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;
-  struct elf_nds32_irel_entry *pre_irel_ptr = NULL;
-  Elf_Internal_Rela *internal_relocs;
   Elf_Internal_Rela *irel;
-  Elf_Internal_Rela *irelend;
   Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Sym *isym = NULL;
+  bfd_byte *contents = 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;
-  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;
-
-  /* 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 */);
-  irelend = internal_relocs + sec->reloc_count;
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  bfd_boolean result = TRUE;
+  bfd_boolean unused_region = FALSE;
 
-  off = 0;
+  /*
+     NOTE: Disable fp-as-gp if we encounter ifcall relocations:
+       R_NDS32_17IFC_PCREL_RELA
+       R_NDS32_10IFCU_PCREL_RELA.  */
 
-  /* Check if the object enable ex9.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  nds32_get_section_contents (abfd, sec, &contents, TRUE);
 
-  /* Check this section trigger ex9 relaxation.  */
-  if (irel == NULL
-      || irel >= irelend
-      || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY
-      || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY
-         && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG)))
-    return TRUE;
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      /* To remove unused fp-base, we simply find the REGION_NOT_OMIT_FP
+        we marked to in previous pass.
+        DO NOT scan relocations again, since we've alreadly decided it
+        and set the flag.  */
+      const char *syname;
+      int syndx;
+      uint32_t insn;
 
-  irel = internal_relocs;
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
+         && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG))
+       unused_region = TRUE;
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END
+              && (irel->r_addend & R_NDS32_RELAX_REGION_NOT_OMIT_FP_FLAG))
+       unused_region = FALSE;
 
-  /* Check alignment and fetch proper relocation.  */
-  while (off < sec->size)
-    {
-      struct elf_link_hash_entry *h = NULL;
-      struct elf_nds32_irel_entry *irel_ptr = NULL;
+      /* We're not in the region.  */
+      if (!unused_region)
+       continue;
 
-      /* Syn the instruction and the relocation.  */
-      while (irel != NULL && irel < irelend && irel->r_offset < off)
-       irel++;
+      /* _FP_BASE_ must be a GLOBAL symbol.  */
+      syndx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+       continue;
 
-      data_flag = nds32_elf_ex9_relocation_check (info, &irel, irelend,
-                                                 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);
-           }
-       }
+      /* The symbol name must be _FP_BASE_.  */
+      syname = elf_sym_hashes (abfd)[syndx]->root.root.string;
+      if (strcmp (syname, FP_BASE_NAME) != 0)
+       continue;
 
-      if (data_flag & CLEAN_PRE)
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA19S0_RELA)
        {
-         pre_off = 0;
-         pre_insn16 = 0;
-         pre_irel_ptr = NULL;
+         /* addi.gp  $fp, -256  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (insn != INSN_ADDIGP_TO_FP)
+           continue;
        }
-      if (data_flag & DATA_EXIST)
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S0_RELA)
        {
-         /* We save the move offset in the highest byte.  */
-         off += (data_flag >> 24);
-         continue;
+         /* addi  $fp, $gp, -256  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (insn != INSN_ADDI_GP_TO_FP)
+           continue;
        }
-
-      if (*(contents + off) & 0x80)
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_20_RELA)
        {
-         /* 2-byte instruction.  */
-         off += 2;
-         continue;
+         /* movi  $fp, FP_BASE  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (insn != INSN_MOVI_TO_FP)
+           continue;
        }
+      else
+       continue;
 
-      /* Load the instruction and its opcode with register for comparing.  */
-      ex9_insn = ex9_insn_head;
-      insn = bfd_getb32 (contents + off);
-      insn_with_reg = 0;
-      while (ex9_insn)
-       {
-         it_insn = strtol (ex9_insn->string, NULL, 16);
-         it_insn_with_reg = 0;
-         do_replace = 0;
-         save_irel = 0;
+      /* We got here because a FP_BASE instruction is found.  */
+      if (!insert_nds32_elf_blank_recalc_total
+         (&relax_blank_list, irel->r_offset, 4))
+       goto error_return;
+    }
 
-         if (irel != NULL && irel < irelend && irel->r_offset == off)
-           {
-             /* Insn with relocation.  */
-             nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg);
+ finish:
+  if (relax_blank_list)
+    {
+      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
+      relax_blank_list = NULL;
+    }
+  return result;
 
-             if (ex9_insn->irel != NULL)
-                 nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, &it_insn_with_reg);
+ error_return:
+  result = FALSE;
+  goto finish;
+}
 
-             if (ex9_insn->irel != NULL
-                 && 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.  */
-
-                 if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA
-                     || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA
-                     || 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_RELA
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA
-                         && ELF32_R_TYPE (irel->r_info) <=
-                         R_NDS32_SDA12S2_SP_RELA)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA))
-                   {
-                     r_symndx = ELF32_R_SYM (irel->r_info);
-                     if (r_symndx < symtab_hdr->sh_info)
-                       {
-                         /* Local symbol.  */
-                         int shndx = isym[r_symndx].st_shndx;
+/* 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.  */
 
-                         isec = elf_elfsections (abfd)[shndx]->bfd_section;
-                         if (ex9_insn->sec == isec
-                             && ex9_insn->irel->r_addend == irel->r_addend
-                             && ex9_insn->irel->r_info == irel->r_info)
-                           {
-                             do_replace = 1;
-                             save_irel = 1;
-                           }
-                       }
-                     else
-                       {
-                         /* External symbol.  */
-                         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)
-                                   {
-                                     do_replace = 1;
-                                     save_irel = 1;
-                                     break;
-                                   }
-                                 h_list = h_list->next;
-                               }
-                           }
-                       }
-                   }
-                 else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA)
-                   {
-                     r_symndx = ELF32_R_SYM (irel->r_info);
-                     if (r_symndx < symtab_hdr->sh_info)
-                       {
-                         /* Local symbols.  Compare its base symbol and offset.  */
-                         int shndx = isym[r_symndx].st_shndx;
+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;
 
-                         isec = elf_elfsections (abfd)[shndx]->bfd_section;
-                         if (ex9_insn->sec == isec
-                             && ex9_insn->irel->r_addend == irel->r_addend
-                             && ex9_insn->irel->r_info == irel->r_info)
-                           {
-                             do_replace = 1;
-                             save_irel = 1;
-                           }
-                       }
-                     else
-                       {
-                         /* External symbol.  */
-                         struct elf_link_hash_entry_mul_list *m_list;
+  /* Read in the section.  */
+  if (!nds32_get_section_contents (input_bfd, input_section, &data, FALSE))
+    return NULL;
 
-                         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-                         m_list = ex9_insn->m_list;
+  if (reloc_size == 0)
+    return data;
 
-                         while (m_list)
-                           {
-                             struct elf_link_hash_entry_list *h_list = m_list->h_list;
-
-                             while (h_list)
-                               {
-                                 if (h == h_list->h
-                                     && m_list->irel->r_addend == irel->r_addend)
-                                   {
-                                     do_replace = 1;
-                                     save_irel = 1;
-                                     if (ex9_insn->next
-                                         && ex9_insn->m_list
-                                         && ex9_insn->m_list == ex9_insn->next->m_list)
-                                       {
-                                         /* sethi multiple entry must be fixed */
-                                         nds32_elf_ex9_insert_fix (sec, irel,
-                                                                   h, ex9_insn->order);
-                                       }
-                                     break;
-                                   }
-                                 h_list = h_list->next;
-                               }
-                             m_list = m_list->next;
-                           }
-                       }
-                   }
-               }
+  reloc_vector = (arelent **) bfd_malloc (reloc_size);
+  if (reloc_vector == NULL)
+    return NULL;
 
-             /* Import table: Check the symbol hash table and the
-                jump target.  Only R_NDS32_25_PCREL_RELA now.  */
-             else if (ex9_insn->times == -1
-                      && ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA)
-               {
-                 nds32_elf_get_insn_with_reg (irel, it_insn, &it_insn_with_reg);
-                 if (insn_with_reg == it_insn_with_reg)
-                   {
-                     char code[10];
-                     bfd_vma relocation;
+  reloc_count = bfd_canonicalize_reloc (input_bfd, input_section,
+                                       reloc_vector, symbols);
+  if (reloc_count < 0)
+    goto error_return;
 
-                     r_symndx = ELF32_R_SYM (irel->r_info);
-                     if (r_symndx >= symtab_hdr->sh_info)
-                       {
-                         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->gc_mark == 1
-                             && strcmp (h->root.u.def.section->name,
-                                        BFD_ABS_SECTION_NAME) == 0
-                             && 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 += irel->r_addend;
-                             insn = insn_with_reg | ((relocation >> 1) & 0xffffff);
-                             snprintf (code, sizeof (code), "%08lx", insn);
-                             if (strcmp (code, ex9_insn->string) == 0)
-                               {
-                                 do_replace = 1;
-                                 save_irel = 1;
-                               }
-                           }
-                       }
-                   }
-               }
-             else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
-                      || ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_END)
-               {
-                 /* These relocations do not have to relocate contens, so it can
-                    be regard as instruction without relocation.  */
-                 if (insn == it_insn && ex9_insn->irel == NULL)
-                   do_replace = 1;
-               }
+  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_vma off;
+             static reloc_howto_type none_howto
+               = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL,
+                        "unused", FALSE, 0, 0, FALSE);
+
+             off = (*parent)->address * OCTETS_PER_BYTE (input_bfd,
+                                                         input_section);
+             _bfd_clear_contents ((*parent)->howto, input_bfd,
+                                  input_section, data, off);
+             (*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)
            {
-             /* Instruction without relocation, we only
-                have to compare their byte code.  */
-             if (insn == it_insn && ex9_insn->irel == NULL)
-               do_replace = 1;
+             asection *os = input_section->output_section;
+
+             /* A partial link, so keep the relocs.  */
+             os->orelocation[os->reloc_count] = *parent;
+             os->reloc_count++;
            }
 
-         /* Insntruction match so replacing the code here.  */
-         if (do_replace == 1)
+         if (r != bfd_reloc_ok)
            {
-             /* There are two formats of ex9 instruction.  */
-             if (ex9_insn->order < 32)
-               insn_ex9 = INSN_EX9_IT_2;
-             else
-               insn_ex9 = INSN_EX9_IT_1;
-             insn16 = insn_ex9 | ex9_insn->order;
-
-             if (pre_insn16 != 0)
+             switch (r)
                {
-                 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);
-               }
-             pre_off = off;
-             pre_insn16 = insn16;
+               case bfd_reloc_undefined:
+                 (*link_info->callbacks->undefined_symbol)
+                   (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+                    input_bfd, input_section, (*parent)->address, TRUE);
+                 break;
+               case bfd_reloc_dangerous:
+                 BFD_ASSERT (error_message != NULL);
+                 (*link_info->callbacks->reloc_dangerous)
+                   (link_info, error_message,
+                    input_bfd, input_section, (*parent)->address);
+                 break;
+               case bfd_reloc_overflow:
+                 (*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);
+                 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
+                   /* xgettext:c-format */
+                   (_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"),
+                    abfd, input_section, * parent);
+                 goto error_return;
 
-             if (save_irel)
-               {
-                 /* For instuction with relocation do relax.  */
-                 irel_ptr = (struct elf_nds32_irel_entry *)
-                   bfd_malloc (sizeof (struct elf_nds32_irel_entry));
-                 irel_ptr->irel = irel;
-                 irel_ptr->next = NULL;
-                 pre_irel_ptr = irel_ptr;
+               default:
+                 abort ();
+                 break;
                }
-             else
-               pre_irel_ptr = NULL;
-             break;
            }
-         ex9_insn = ex9_insn->next;
        }
-      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);
-    }
+  free (reloc_vector);
+  return data;
 
-  /* Delete the redundant code.  */
-  if (relax_blank_list)
-    {
-      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
-      relax_blank_list = NULL;
-    }
+ error_return:
+  free (reloc_vector);
+  return NULL;
+}
 
-  /* Clear the relocation that is replaced by ex9.  */
-  while (irel_list)
-    {
-      struct elf_nds32_irel_entry *irel_ptr;
+/* Check target symbol.  */
 
-      irel_ptr = irel_list;
-      irel_list = irel_ptr->next;
-      irel_ptr->irel->r_info =
-       ELF32_R_INFO (ELF32_R_SYM (irel_ptr->irel->r_info), R_NDS32_TRAN);
-      free (irel_ptr);
-    }
+static bfd_boolean
+nds32_elf_is_target_special_symbol (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
+{
+  if (!sym || !sym->name || sym->name[0] != '$')
+    return FALSE;
   return TRUE;
 }
 
-/* Initialize ex9 hash table.  */
+/* nds32 find maybe function sym.  Ignore target special symbol
+   first, and then go the general function.  */
+
+static bfd_size_type
+nds32_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                             bfd_vma *code_off)
+{
+  if (nds32_elf_is_target_special_symbol (NULL, (asymbol *) sym))
+    return 0;
+
+  return _bfd_elf_maybe_function_sym (sym, sec, code_off);
+}
+\f
+
+/* Do TLS model conversion.  */
+
+typedef struct relax_group_list_t
+{
+  Elf_Internal_Rela *relo;
+  struct relax_group_list_t *next;
+  struct relax_group_list_t *next_sibling;
+  int id;
+} relax_group_list_t;
+
+int
+list_insert (relax_group_list_t *pHead, Elf_Internal_Rela *pElem);
+
+int
+list_insert_sibling (relax_group_list_t *pNode, Elf_Internal_Rela *pElem);
+
+void
+dump_chain (relax_group_list_t *pHead);
 
 int
-nds32_elf_ex9_init (void)
+list_insert (relax_group_list_t *pHead, Elf_Internal_Rela *pElem)
 {
-  if (!bfd_hash_table_init_n (&ex9_code_table, nds32_elf_code_hash_newfunc,
-                             sizeof (struct elf_nds32_code_hash_entry),
-                             1023))
+  relax_group_list_t *pNext = pHead;
+
+  /* Find place.  */
+  while (pNext->next)
     {
-      (*_bfd_error_handler) (_("Linker: cannot init ex9 hash table error \n"));
-      return FALSE;
+      if (pNext->next->id > (int) pElem->r_addend)
+       break;
+
+      pNext = pNext->next;
     }
+
+  /* Insert node.  */
+  relax_group_list_t *pNew = bfd_malloc (sizeof (relax_group_list_t));
+  if (!pNew)
+    return FALSE;
+
+  relax_group_list_t *tmp = pNext->next;
+  pNext->next = pNew;
+
+  pNew->id = pElem->r_addend;
+  pNew->relo = pElem;
+  pNew->next = tmp;
+  pNew->next_sibling = NULL;
+
   return TRUE;
 }
 
-/* Predict how many bytes will be relaxed with ex9 and ifc.  */
-
-static void
-nds32_elf_ex9_total_relax (struct bfd_link_info *info)
+int
+list_insert_sibling (relax_group_list_t *pNode, Elf_Internal_Rela *pElem)
 {
-  struct elf_nds32_insn_times_entry *ex9_insn;
-  struct elf_nds32_insn_times_entry *temp;
-  int target_optimize;
-  struct elf_nds32_link_hash_table *table;
-
-  if (ex9_insn_head == NULL)
-    return;
+  relax_group_list_t *pNext = pNode;
 
-  table = nds32_elf_hash_table (info);
-  target_optimize  = table->target_optimize;
-  ex9_insn = ex9_insn_head;
-  while (ex9_insn)
+  /* Find place.  */
+  while (pNext->next_sibling)
     {
-      ex9_relax_size = ex9_insn->times * 2 + ex9_relax_size;
-      temp = ex9_insn;
-      ex9_insn = ex9_insn->next;
-      free (temp);
+      pNext = pNext->next_sibling;
     }
-  ex9_insn_head = NULL;
 
-  if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON))
-    {
-      /* Examine ifc reduce size.  */
-      struct elf_nds32_ifc_symbol_entry *ifc_ent = ifc_symbol_head;
-      struct elf_nds32_ifc_irel_list *irel_ptr = NULL;
-      int size = 0;
+  /* Insert node.  */
+  relax_group_list_t *pNew = bfd_malloc (sizeof (relax_group_list_t));
+  if (!pNew)
+    return FALSE;
+
+  relax_group_list_t *tmp = pNext->next_sibling;
+  pNext->next_sibling = pNew;
+
+  pNew->id = -1;
+  pNew->relo = pElem;
+  pNew->next = NULL;
+  pNew->next_sibling = tmp;
 
-      while (ifc_ent)
+  return TRUE;
+}
+
+void
+dump_chain (relax_group_list_t *pHead)
+{
+  relax_group_list_t *pNext = pHead->next;
+  while (pNext)
+    {
+      printf("group %d @ 0x%08x", pNext->id, (unsigned)pNext->relo->r_offset);
+      relax_group_list_t *pNextSib = pNext->next_sibling;
+      while (pNextSib)
        {
-         if (ifc_ent->enable == 0)
-           {
-             /* Not ifc yet.  */
-             irel_ptr = ifc_ent->irel_head;
-             while (irel_ptr)
-               {
-                 size += 2;
-                 irel_ptr = irel_ptr->next;
-               }
-           }
-         size -= 2;
-         ifc_ent = ifc_ent->next;
+         printf(", %d", (unsigned) ELF32_R_TYPE (pNextSib->relo->r_info));
+         pNextSib = pNextSib->next_sibling;
        }
-      ex9_relax_size += size;
+      pNext = pNext->next;
+      printf("\n");
     }
 }
 
-/* Finish ex9 table.  */
+/* Check R_NDS32_RELAX_GROUP of each section.
+   There might be multiple sections in one object file.  */
 
-void
-nds32_elf_ex9_finish (struct bfd_link_info *link_info)
+int
+elf32_nds32_check_relax_group (bfd *abfd, asection *asec)
 {
-  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);
-  /* Traverse the hash table and count its times.  */
-  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;
-}
+  elf32_nds32_relax_group_t *relax_group_ptr =
+    elf32_nds32_relax_group_ptr (abfd);
 
-/* Relocate the entries in ex9 table.  */
+  int min_id = relax_group_ptr->min_id;
+  int max_id = relax_group_ptr->max_id;
 
-static bfd_vma
-nds32_elf_ex9_reloc_insn (struct elf_nds32_insn_times_entry *ptr,
-                         struct bfd_link_info *link_info)
-{
-  Elf_Internal_Sym *isym = NULL;
-  bfd_vma relocation = -1;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  Elf_Internal_Rela *relocs;
+  enum elf_nds32_reloc_type rtype;
 
-  if (ptr->m_list != NULL)
+  do
     {
-      /* 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))
+      /* Relocations MUST be kept in memory, because relaxation adjust them.  */
+      relocs = _bfd_elf_link_read_relocs (abfd, asec, NULL, NULL,
+                                         TRUE /* keep_memory  */);
+      if (relocs == NULL)
+       break;
+
+      /* Check R_NDS32_RELAX_GROUP.  */
+      relend = relocs + asec->reloc_count;
+      for (rel = relocs; rel < relend; rel++)
        {
+         int id;
+         rtype = ELF32_R_TYPE (rel->r_info);
+         if (rtype != R_NDS32_RELAX_GROUP)
+           continue;
 
-         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 += ptr->m_list->irel->r_addend;
+         id = rel->r_addend;
+         if (id < min_id)
+           min_id = id;
+         else if (id > max_id)
+           max_id = id;
        }
-      else
-       relocation = 0;
     }
-  else if (ptr->sec !=NULL)
+  while (FALSE);
+
+  if (elf_section_data (asec)->relocs != relocs)
+    free (relocs);
+
+  if ((min_id != relax_group_ptr->min_id)
+      || (max_id != relax_group_ptr->max_id))
     {
-      /* Local symbol.  */
-      Elf_Internal_Sym sym;
-      asection *sec = NULL;
-      asection isec;
-      asection *isec_ptr = &isec;
-      Elf_Internal_Rela irel_backup = *(ptr->irel);
-      asection *sec_backup = ptr->sec;
-      bfd *abfd = ptr->sec->owner;
+      relax_group_ptr->count = max_id - min_id + 1;
+      BFD_ASSERT(min_id <= relax_group_ptr->min_id);
+      relax_group_ptr->min_id = min_id;
+      BFD_ASSERT(max_id >= relax_group_ptr->max_id);
+      relax_group_ptr->max_id = max_id;
+    }
 
-      if (!nds32_get_local_syms (abfd, sec, &isym))
-       return FALSE;
-      isym = isym + ELF32_R_SYM (ptr->irel->r_info);
+  return relax_group_ptr->count;
+}
+
+/* Reorder RELAX_GROUP ID when command line option '-r' is applied.  */
+struct section_id_list_t *relax_group_section_id_list = NULL;
+
+struct section_id_list_t *
+elf32_nds32_lookup_section_id (int id, struct section_id_list_t **lst_ptr)
+{
+  struct section_id_list_t *result = NULL;
+  struct section_id_list_t *lst = *lst_ptr;
 
-      sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
-      if (sec != NULL)
-       *isec_ptr = *sec;
-      sym = *isym;
+  if (NULL == lst)
+    {
+      result = (struct section_id_list_t *) calloc
+       (1, sizeof (struct section_id_list_t));
+      BFD_ASSERT (result); /* Feed me.  */
+      result->id = id;
+      *lst_ptr = result;
+    }
+  else
+    {
+      struct section_id_list_t *cur = lst;
+      struct section_id_list_t *prv = NULL;
+      struct section_id_list_t *sec = NULL;
 
-      /* The purpose is same as elf_link_input_bfd.  */
-      if (isec_ptr != NULL
-         && isec_ptr->sec_info_type == SEC_INFO_TYPE_MERGE
-         && ELF_ST_TYPE (isym->st_info) != STT_SECTION)
+      while (cur)
        {
-         sym.st_value =
-           _bfd_merged_section_offset (ptr->sec->output_section->owner, &isec_ptr,
-                                       elf_section_data (isec_ptr)->sec_info,
-                                       isym->st_value);
+         if (cur->id < id)
+           {
+             prv = cur;
+             cur = cur->next;
+             continue;
+           }
+
+         if (cur->id > id)
+           {
+             cur = NULL; /* To insert after prv.  */
+             sec = cur;  /* In case prv == NULL.  */
+           }
+
+         break;
        }
-      relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, &sym,
-                                           &ptr->sec, ptr->irel);
-      if (ptr->irel != NULL)
-       relocation += ptr->irel->r_addend;
 
-      /* Restore origin value since there may be some insntructions that
-        could not be replaced with ex9.it.  */
-      *(ptr->irel) = irel_backup;
-      ptr->sec = sec_backup;
+      if (NULL == cur)
+       {
+         /* Insert after prv.  */
+         result = (struct section_id_list_t *) calloc
+           (1, sizeof (struct section_id_list_t));
+         BFD_ASSERT (result); /* Feed me.  */
+         result->id = id;
+         if (NULL != prv)
+           {
+             result->next = prv->next;
+             prv->next = result;
+           }
+         else
+           {
+             *lst_ptr = result;
+             result->next = sec;
+           }
+       }
     }
 
-  return relocation;
+  return result;
 }
 
-/* Import ex9 table and build list.  */
-
-void
-nds32_elf_ex9_import_table (struct bfd_link_info *info)
+int
+elf32_nds32_unify_relax_group (bfd *abfd, asection *asec)
 {
-  int count = 0, num = 1;
-  bfd_byte *contents;
-  unsigned long insn;
-  FILE *ex9_import_file;
-  int update_ex9_table;
-  struct elf_nds32_link_hash_table *table;
+  static int next_relax_group_bias = 0;
 
-  table = nds32_elf_hash_table (info);
-  ex9_import_file = table->ex9_import_file;
+  elf32_nds32_relax_group_t *relax_group_ptr =
+    elf32_nds32_relax_group_ptr (abfd);
 
-  contents = bfd_malloc (sizeof (bfd_byte) * 4);
+  bfd_boolean result = TRUE;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  Elf_Internal_Rela *relocs = NULL;
+  enum elf_nds32_reloc_type rtype;
+  struct section_id_list_t *node = NULL;
+  int count = 0;
 
-  /* 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)
+  do
     {
-      char *code;
-      struct elf_nds32_insn_times_entry *ptr;
-      size_t nread;
+      if (0 == relax_group_ptr->count)
+       break;
+
+      /* Check if this section has been handled.  */
+      node = elf32_nds32_lookup_section_id (asec->id, &relax_group_section_id_list);
+      if (NULL == node)
+       break; /* Hit, the section id has handled.  */
 
-      nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file);
-      if (nread < sizeof (bfd_byte) * 4)
+      /* Relocations MUST be kept in memory, because relaxation adjust them.  */
+      relocs = _bfd_elf_link_read_relocs (abfd, asec, NULL, NULL,
+                                         TRUE /* keep_memory  */);
+      if (relocs == NULL)
        {
-         (*_bfd_error_handler) ("Unexpected size of imported ex9 table.");
+         BFD_ASSERT (0); /* feed me */
          break;
        }
-      insn = bfd_getb32 (contents);
-      code = bfd_malloc (sizeof (char) * 9);
-      snprintf (code, 9, "%08lx", insn);
-      ptr = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-      ptr->string = code;
-      ptr->order = num;
-      ptr->times = -1;
-      ptr->sec = NULL;
-      ptr->m_list = NULL;
-      ptr->rel_backup.r_offset = 0;
-      ptr->rel_backup.r_info = 0;
-      ptr->rel_backup.r_addend = 0;
-      ptr->irel = NULL;
-      ptr->next = NULL;
-      nds32_elf_ex9_insert_entry (ptr);
-      count--;
-      num++;
-    }
-
-  update_ex9_table = table->update_ex9_table;
-  if (update_ex9_table == 1)
-    {
-      /* It has to consider of sethi need to use multiple page
-        but it not be done yet.  */
-      nds32_elf_code_hash_traverse (nds32_elf_examine_insn_times);
-      nds32_elf_order_insn_times (info);
-    }
-}
 
-/* Export ex9 table.  */
+      /* Allocate group id bias for this bfd!  */
+      if (0 == relax_group_ptr->init)
+       {
+         relax_group_ptr->bias = next_relax_group_bias;
+         next_relax_group_bias += relax_group_ptr->count;
+         relax_group_ptr->init = 1;
+       }
 
-static void
-nds32_elf_ex9_export (struct bfd_link_info *info,
-                     bfd_byte *contents, int size)
-{
-  FILE *ex9_export_file;
-  struct elf_nds32_link_hash_table *table;
+      /* Reorder relax group groups.  */
+      relend = relocs + asec->reloc_count;
+      for (rel = relocs; rel < relend; rel++)
+       {
+         rtype = ELF32_R_TYPE(rel->r_info);
+         if (rtype != R_NDS32_RELAX_GROUP)
+           continue;
 
-  table = nds32_elf_hash_table (info);
-  ex9_export_file = table->ex9_export_file;
-  fwrite (contents, sizeof (bfd_byte), size, ex9_export_file);
-  fclose (ex9_export_file);
+         /* Change it.  */
+         rel->r_addend += relax_group_ptr->bias;
+         /* Debugging count.  */
+         count++;
+       }
+    }
+  while (FALSE);
+
+  if (elf_section_data (asec)->relocs != relocs)
+    free (relocs);
+
+  return result;
 }
 
-/* Adjust relocations of J and JAL in ex9.itable.
-   Export ex9 table.  */
+int
+nds32_elf_unify_tls_model (bfd *inbfd, asection *insec, bfd_byte *incontents,
+                          struct bfd_link_info *lnkinfo)
+{
+  bfd_boolean result = TRUE;
+  Elf_Internal_Rela *irel;
+  Elf_Internal_Rela *irelend;
+  Elf_Internal_Rela *internal_relocs;
+  unsigned long r_symndx;
+  enum elf_nds32_reloc_type r_type;
 
-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;
-  bfd_byte *contents = NULL, *source_contents = NULL;
-  int size = 0;
-  bfd_vma gp;
-  int shift, update_ex9_table, offset = 0;
-  reloc_howto_type *howto = NULL;
-  Elf_Internal_Rela rel_backup;
-  unsigned short insn_ex9;
-  struct elf_nds32_link_hash_table *table;
-  FILE *ex9_export_file, *ex9_import_file;
+  Elf_Internal_Sym *local_syms = NULL;
+  bfd_byte *contents = NULL;
 
-  table = nds32_elf_hash_table (link_info);
-  if (table)
-    table->relax_status |= NDS32_RELAX_EX9_DONE;
+  relax_group_list_t chain = { .id = -1, .next = NULL, .next_sibling = NULL };
 
+  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (inbfd)->symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  sym_hashes = elf_sym_hashes (inbfd);
+  sym_hashes_end =
+    sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+  if (!elf_bad_symtab (inbfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
 
-  update_ex9_table = table->update_ex9_table;
-  /* Generated ex9.itable exactly.  */
-  if (update_ex9_table == 0)
+  /* Reorder RELAX_GROUP when command line option '-r' is applied.  */
+  if (bfd_link_relocatable (lnkinfo))
     {
-      for (it_abfd = link_info->input_bfds; it_abfd != NULL;
-          it_abfd = it_abfd->link_next)
-       {
-         table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable");
-         if (table_sec != NULL)
-           break;
-       }
+      elf32_nds32_unify_relax_group (inbfd, insec);
+      return result;
+    }
 
-      if (table_sec != NULL)
-       {
-         bfd *output_bfd;
-         struct bfd_link_hash_entry *bh = NULL;
+  /* Relocations MUST be kept in memory, because relaxation adjust them.  */
+  internal_relocs = _bfd_elf_link_read_relocs (inbfd, insec, NULL, NULL,
+                                              TRUE /* keep_memory  */);
+  if (internal_relocs == NULL)
+    goto error_return;
 
-         output_bfd = table_sec->output_section->owner;
-         nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
-         if (table_sec->size == 0)
-           return;
+  irelend = internal_relocs + insec->reloc_count;
+  irel = find_relocs_at_address (internal_relocs, internal_relocs,
+                                irelend, R_NDS32_RELAX_ENTRY);
+  if (irel == irelend)
+    goto finish;
 
-         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
+  /* Chain/remove groups.  */
+  for (irel = internal_relocs; irel < irelend; irel++)
     {
-      /* Set gp.  */
-      bfd *output_bfd;
+      r_symndx = ELF32_R_SYM (irel->r_info);
+      r_type = ELF32_R_TYPE (irel->r_info);
+      if (r_type != R_NDS32_RELAX_GROUP)
+       continue;
 
-      output_bfd = link_info->input_bfds->sections->output_section->owner;
-      nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
-      contents = bfd_malloc (sizeof (bfd_byte) * 2048);
+      /* Remove it.  */
+      irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_NONE);
+      /* Chain it now.  */
+      if (!list_insert (&chain, irel))
+       goto error_return;
     }
 
-  /* Relocate instruction.  */
-  while (ex9_insn)
+  /* Collect group relocations.  */
+  /* Presume relocations are sorted.  */
+  relax_group_list_t *pNext = chain.next;
+  while (pNext)
     {
-      bfd_vma relocation, min_relocation = 0xffffffff;
-
-      insn = strtol (ex9_insn->string, NULL, 16);
-      insn_with_reg = 0;
-      if (ex9_insn->m_list != NULL || ex9_insn->sec != NULL)
+      for (irel = internal_relocs; irel < irelend; irel++)
        {
-         if (ex9_insn->m_list)
-           rel_backup = ex9_insn->m_list->rel_backup;
-         else
-           rel_backup = ex9_insn->rel_backup;
-
-         nds32_elf_get_insn_with_reg (&rel_backup, insn, &insn_with_reg);
-         howto =
-           bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE
-                                                  (rel_backup.r_info));
-         shift = howto->rightshift;
-         if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_25_PCREL_RELA
-             || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_ORI_RELA
-             || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S0_RELA
-             || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S1_RELA
-             || ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_LO12S2_RELA)
-           {
-             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);
-           }
-         else if ((ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3
-                   && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0)
-                  || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA15S3_RELA
-                      && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA15S0_RELA)
-                  || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA12S2_DP_RELA
-                      && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA12S2_SP_RELA)
-                  || (ELF32_R_TYPE (rel_backup.r_info) >= R_NDS32_SDA16S3_RELA
-                      && ELF32_R_TYPE (rel_backup.r_info) <= R_NDS32_SDA19S0_RELA))
+         if (irel->r_offset == pNext->relo->r_offset)
            {
-             relocation = nds32_elf_ex9_reloc_insn (ex9_insn, link_info);
-             insn =
-               insn_with_reg | (((relocation - gp) >> shift) &
-                                nds32_elf_irel_mask (&rel_backup));
-             bfd_putb32 (insn, contents + (ex9_insn->order) * 4 + offset);
+             /* Ignore Non-TLS relocation types.  */
+             r_type = ELF32_R_TYPE (irel->r_info);
+             if ((R_NDS32_TLS_LE_HI20 > r_type)
+                 || (R_NDS32_RELAX_ENTRY == r_type))
+               continue;
+
+             if (!list_insert_sibling (pNext, irel))
+               goto error_return;
            }
-         else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA)
+         else if (irel->r_offset > pNext->relo->r_offset)
            {
-             /* 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)))
-               {
-                 struct elf_link_hash_entry_mul_list *m_list;
-                 struct elf_nds32_ex9_refix *fix_ptr;
-
-                 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);
-                     relocation += m_list->irel->r_addend;
-
-                     if (relocation < min_relocation)
-                       min_relocation = relocation;
-                     m_list = m_list->next;
-                   }
-                 relocation = min_relocation;
-
-                 /* 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);
-                 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)))
-                   {
-                     /* 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);
-                     relocation = relocation + 0x1000; /* hi20 */
-                   }
-
-                 fix_ptr = ex9_refix_head;
-                 while (fix_ptr)
-                   {
-                     /* Fix ex9 insn.  */
-                     /* temp_ptr2 points to the head of multiple sethi.  */
-                     temp_ptr = temp_ptr2;
-                     while (fix_ptr->order != temp_ptr->order && fix_ptr->next)
-                       {
-                         fix_ptr = fix_ptr->next;
-                       }
-                     if (fix_ptr->order != temp_ptr->order)
-                       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->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;
-                           }
+             pNext = pNext->next;
+             if (!pNext)
+               break;
 
-                         /* Match entry and source code.  */
-                         insn = bfd_getb32 (contents + (temp_ptr->order) * 4 + offset);
-                         if (insn == source_insn)
-                           {
-                             /* Fix the ex9 insn.  */
-                             if (temp_ptr->order != fix_ptr->order)
-                               {
-                                 if (!nds32_get_section_contents
-                                        (fix_ptr->sec->owner, fix_ptr->sec,
-                                         &source_contents))
-                                   (*_bfd_error_handler)
-                                     (_("Linker: error cannot fixed ex9 relocation \n"));
-                                 if (temp_ptr->order < 32)
-                                   insn_ex9 = INSN_EX9_IT_2;
-                                 else
-                                   insn_ex9 = INSN_EX9_IT_1;
-                                 insn_ex9 = insn_ex9 | temp_ptr->order;
-                                 bfd_putb16 (insn_ex9, source_contents + fix_ptr->irel->r_offset);
-                               }
-                               break;
-                           }
-                         else
-                           {
-                             if (!temp_ptr->next || temp_ptr->m_list != temp_ptr->next->m_list)
-                               (*_bfd_error_handler)
-                                 (_("Linker: error cannot fixed ex9 relocation \n"));
-                             else
-                               temp_ptr = temp_ptr->next;
-                           }
-                       }
-                     fix_ptr = fix_ptr->next;
-                   }
-               }
+             bfd_vma current_offset = pNext->relo->r_offset;
+             if (irel->r_offset > current_offset)
+               irel = internal_relocs; /* restart from head */
              else
-               {
-                 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);
-               }
+               --irel; /* Check current irel again.  */
+             continue;
+           }
+         else
+           {
+             /* This shouldn't be reached.  */
            }
        }
-      else
-       {
-         /* Insn without relocation does not have to be fixed
-            if need to update export table.  */
-         if (update_ex9_table == 1)
-           bfd_putb32 (insn, contents + (ex9_insn->order) * 4);
-       }
-      ex9_insn = ex9_insn->next;
-      size += 4;
-    }
-
-  ex9_export_file = table->ex9_export_file;
-  if (ex9_export_file != NULL)
-    nds32_elf_ex9_export (link_info, contents + 4, table_sec->size - 4);
-  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);
+      if (pNext)
+       pNext = pNext->next;
     }
-}
-
-/* Generate ex9 hash table.  */
 
-static bfd_boolean
-nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
-                               struct bfd_link_info *link_info)
-{
-  Elf_Internal_Rela *internal_relocs;
-  Elf_Internal_Rela *irelend;
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Rela *jrel;
-  Elf_Internal_Rela rel_backup;
-  Elf_Internal_Shdr *symtab_hdr;
-  Elf_Internal_Sym *isym = NULL;
-  asection *isec;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_byte *contents = NULL;
-  long unsigned int off = 0;
-  unsigned long r_symndx;
-  unsigned long insn;
-  unsigned long insn_with_reg;
-  struct elf_link_hash_entry *h;
-  int data_flag, shift, align;
-  bfd_vma relocation;
-  /* Suppress ex9 if `.no_relax ex9' or inner loop.  */
-  reloc_howto_type *howto = NULL;
+#ifdef DUBUG_VERBOSE
+  dump_chain(&chain);
+#endif
 
-  sym_hashes = elf_sym_hashes (abfd);
-  /* Load section instructions, relocations, and symbol table.  */
-  if (!nds32_get_section_contents (abfd, sec, &contents))
-    return FALSE;
+  /* Get symbol table and section content.  */
+  if (incontents)
+    contents = incontents;
+  else if (!nds32_get_section_contents (inbfd, insec, &contents, TRUE)
+          || !nds32_get_local_syms (inbfd, insec, &local_syms))
+    goto error_return;
 
-  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;
-  if (!nds32_get_local_syms (abfd, sec, &isym))
-    return FALSE;
+  char *local_got_tls_type = elf32_nds32_local_got_tls_type (inbfd);
 
-  /* Check the object if enable ex9.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  /* Convert TLS model each group if necessary.  */
+  pNext = chain.next;
 
-  /* Check this section trigger ex9 relaxation.  */
-  if (irel == NULL
-      || irel >= irelend
-      || ELF32_R_TYPE (irel->r_info) != R_NDS32_RELAX_ENTRY
-      || (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY
-         && !(irel->r_addend & R_NDS32_RELAX_ENTRY_EX9_FLAG)))
-    return TRUE;
+  int cur_grp_id = -1;
+  int sethi_rt = -1;
+  int add_rt = -1;
+  enum elf_nds32_tls_type tls_type, org_tls_type, eff_tls_type;
 
-  irel = internal_relocs;
+  tls_type = org_tls_type = eff_tls_type = 0;
 
-  /* Push each insn into hash table.  */
-  while (off < sec->size)
+  while (pNext)
     {
-      char code[10];
-      struct elf_nds32_code_hash_entry *entry;
-
-      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);
-      if (data_flag & DATA_EXIST)
+      relax_group_list_t *pNextSig = pNext->next_sibling;
+      while (pNextSig)
        {
-         /* We save the move offset in the highest byte.  */
-         off += (data_flag >> 24);
-         continue;
-       }
+         struct elf_link_hash_entry *h = NULL;
 
-      if (*(contents + off) & 0x80)
-       {
-         off += 2;
-       }
-      else
-       {
-         h = NULL;
-         isec = NULL;
-         jrel = NULL;
-         rel_backup.r_info = 0;
-         rel_backup.r_offset = 0;
-         rel_backup.r_addend = 0;
-         /* Load the instruction and its opcode with register for comparing.  */
-         insn = bfd_getb32 (contents + off);
-         insn_with_reg = 0;
-         if (irel != NULL && irel < irelend && irel->r_offset == off)
+         irel = pNextSig->relo;
+         r_symndx = ELF32_R_SYM(irel->r_info);
+         r_type = ELF32_R_TYPE(irel->r_info);
+
+         if (pNext->id != cur_grp_id)
            {
-             nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg);
-             howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info));
-             shift = howto->rightshift;
-             align = (1 << shift) - 1;
-             if (ELF32_R_TYPE (irel->r_info) == R_NDS32_25_PCREL_RELA
-                 || ELF32_R_TYPE (irel->r_info) == R_NDS32_HI20_RELA
-                 || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_ORI_RELA
-                 || 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_RELA
-                 ||(ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3
-                    && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0)
-                 || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA
-                     && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA)
-                 || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA
-                     && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA)
-                 || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA
-                     && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA))
+             cur_grp_id = pNext->id;
+             org_tls_type = get_tls_type (r_type, NULL);
+             if (r_symndx >= symtab_hdr->sh_info)
                {
-                 r_symndx = ELF32_R_SYM (irel->r_info);
-                 jrel = irel;
-                 rel_backup = *irel;
-                 if (r_symndx < symtab_hdr->sh_info)
-                   {
-                     /* Local symbol.  */
-                     int shndx = isym[r_symndx].st_shndx;
+                 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+                 while (h->root.type == bfd_link_hash_indirect
+                        || h->root.type == bfd_link_hash_warning)
+                   h = (struct elf_link_hash_entry *) h->root.u.i.link;
+                 tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type;
+               }
+             else
+               {
+                 tls_type = local_got_tls_type
+                   ? local_got_tls_type[r_symndx]
+                   : GOT_NORMAL;
+               }
 
-                     bfd_vma st_value = (isym + r_symndx)->st_value;
-                     isec = elf_elfsections (abfd)[shndx]->bfd_section;
-                     relocation = (isec->output_section->vma + isec->output_offset
-                                   + st_value + irel->r_addend);
-                   }
-                 else
+             eff_tls_type = 1 << (fls (tls_type) - 1);
+             sethi_rt = N32_RT5(bfd_getb32 (contents + irel->r_offset));
+           }
+
+         if (eff_tls_type != org_tls_type)
+           {
+             switch (org_tls_type)
+               {
+                 /* DESC to IEGP/IE/LE.  */
+               case GOT_TLS_DESC:
+                 switch (eff_tls_type)
                    {
-                     /* External symbol.  */
-                     bfd_boolean warned ATTRIBUTE_UNUSED;
-                     bfd_boolean ignored ATTRIBUTE_UNUSED;
-                     bfd_boolean unresolved_reloc ATTRIBUTE_UNUSED;
-                     asection *sym_sec;
-
-                     /* Maybe there is a better way to get h and relocation */
-                     RELOC_FOR_GLOBAL_SYMBOL (link_info, abfd, sec, irel,
-                                              r_symndx, symtab_hdr, sym_hashes,
-                                              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)
+                   case GOT_TLS_IE:
+                     switch (r_type)
                        {
-                         off += 4;
-                         continue;
+                       case R_NDS32_TLS_DESC_HI20:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IE_HI20);
+                         break;
+                       case R_NDS32_TLS_DESC_LO12:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IE_LO12);
+                         break;
+                       case R_NDS32_TLS_DESC_ADD:
+                         {
+                           uint32_t insn = bfd_getb32 (contents + irel->r_offset);
+                           add_rt = N32_RT5 (insn);
+                           insn = N32_TYPE2 (LWI, add_rt, sethi_rt, 0);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+
+                           irel->r_info = ELF32_R_INFO(r_symndx, R_NDS32_NONE);
+                         }
+                         break;
+                       case R_NDS32_TLS_DESC_FUNC:
+                         bfd_putb32 (INSN_NOP, contents + irel->r_offset);
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_RELAX_REMOVE);
+                         break;
+                       case R_NDS32_TLS_DESC_CALL:
+                         {
+                           uint32_t insn = N32_ALU1(ADD, REG_R0, add_rt,
+                                                    REG_TP);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+
+                           irel->r_info = ELF32_R_INFO(r_symndx, R_NDS32_NONE);
+                         }
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_PTR_RESOLVED:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
+                         break;
                        }
-                   }
-
-                 /* Check for gp relative instruction alignment.  */
-                 if ((ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3
-                      && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA15S3_RELA
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA15S0_RELA)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA12S2_DP_RELA
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA12S2_SP_RELA)
-                     || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_SDA16S3_RELA
-                         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_SDA19S0_RELA))
-                   {
-                     bfd_vma gp;
-                     bfd *output_bfd = sec->output_section->owner;
-                     bfd_reloc_status_type r;
-
-                     /* If the symbol is in the abs section, the out_bfd will be null.
-                        This happens when the relocation has a symbol@GOTOFF.  */
-                     r = nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
-                     if (r != bfd_reloc_ok)
+                     break;
+                   case GOT_TLS_IEGP:
+                     switch (r_type)
                        {
-                         off += 4;
-                         continue;
+                       case R_NDS32_TLS_DESC_HI20:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IEGP_HI20);
+                         break;
+                       case R_NDS32_TLS_DESC_LO12:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IEGP_LO12);
+                         break;
+                       case R_NDS32_TLS_DESC_ADD:
+                         {
+                           uint32_t insn = bfd_getb32 (contents + irel->r_offset);
+                           add_rt = N32_RT5 (insn);
+                           insn = N32_MEM(LW, add_rt, sethi_rt, REG_GP, 0);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+
+                           irel->r_info = ELF32_R_INFO(r_symndx, R_NDS32_NONE);
+                         }
+                         break;
+                       case R_NDS32_TLS_DESC_FUNC:
+                         bfd_putb32 (INSN_NOP, contents + irel->r_offset);
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_RELAX_REMOVE);
+                         break;
+                       case R_NDS32_TLS_DESC_CALL:
+                         {
+                           uint32_t insn = N32_ALU1(ADD, REG_R0, add_rt,
+                                                    REG_TP);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+
+                           irel->r_info = ELF32_R_INFO(r_symndx, R_NDS32_NONE);
+                         }
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_PTR_RESOLVED:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
+                         break;
                        }
+                     break;
+                   case GOT_TLS_LE:
+                     switch (r_type)
+                       {
+                       case R_NDS32_TLS_DESC_HI20:
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_HI20);
+                         break;
+                       case R_NDS32_TLS_DESC_LO12:
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_LO12);
+                         break;
+                       case R_NDS32_TLS_DESC_ADD:
+                         {
+                           uint32_t insn = bfd_getb32 (contents + irel->r_offset);
 
-                     relocation -= gp;
+                           add_rt = N32_RT5 (insn);
+                           insn = N32_ALU1 (ADD, REG_R0, sethi_rt, REG_TP);
+                           bfd_putb32 (insn, contents + irel->r_offset);
 
-                     /* Make sure alignment is correct.  */
-                     if (relocation & align)
-                       {
-                         /* Incorrect alignment.  */
-                         (*_bfd_error_handler)
-                           (_("%s: warning: unaligned small data access. "
-                              "For entry: {%d, %d, %d}, addr = 0x%x, align = 0x%x."),
-                            bfd_get_filename (abfd), irel->r_offset,
-                            irel->r_info, irel->r_addend, relocation, align);
-                         off += 4;
-                         continue;
+                           irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_ADD);
+                         }
+                         break;
+                       case R_NDS32_TLS_DESC_FUNC:
+                         bfd_putb32 (INSN_NOP, contents + irel->r_offset);
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_RELAX_REMOVE);
+                         break;
+                       case R_NDS32_TLS_DESC_CALL:
+                         bfd_putb32 (INSN_NOP, contents + irel->r_offset);
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_RELAX_REMOVE);
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_PTR_RESOLVED:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
+                         break;
                        }
+                     break;
+                   default:
+                     break;
                    }
-
-                 insn = insn_with_reg
-                   | ((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)
-               {
-                 /* These relocations do not have to relocate contens, so it can
-                    be regard as instruction without relocation.  */
-               }
-             else
-               {
-                 off += 4;
-                 continue;
-               }
-           }
-
-         snprintf (code, sizeof (code), "%08lx", insn);
-         /* Copy "code".  */
-         entry = (struct elf_nds32_code_hash_entry*)
-           bfd_hash_lookup (&ex9_code_table, code, TRUE, TRUE);
-         if (entry == NULL)
-           {
-             (*_bfd_error_handler)
-               (_("%P%F: failed creating ex9.it %s hash table: %E\n"), code);
-             return FALSE;
-           }
-         if (h)
-           {
-             if (h->root.type == bfd_link_hash_undefined)
-               return TRUE;
-             /* Global symbol.  */
-             /* In order to do sethi with different symbol but same value.  */
-             if (entry->m_list == NULL)
-               {
-                 struct elf_link_hash_entry_mul_list *m_list_new;
-                 struct elf_link_hash_entry_list *h_list_new;
-
-                 m_list_new = (struct elf_link_hash_entry_mul_list *)
-                   bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list));
-                 h_list_new = (struct elf_link_hash_entry_list *)
-                   bfd_malloc (sizeof (struct elf_link_hash_entry_list));
-                 entry->m_list = m_list_new;
-                 m_list_new->h_list = h_list_new;
-                 m_list_new->rel_backup = rel_backup;
-                 m_list_new->times = 1;
-                 m_list_new->irel = jrel;
-                 m_list_new->next = NULL;
-                 h_list_new->h = h;
-                 h_list_new->next = NULL;
-               }
-             else
-               {
-                 struct elf_link_hash_entry_mul_list *m_list = entry->m_list;
-                 struct elf_link_hash_entry_list *h_list;
-
-                 while (m_list)
+                 break;
+                 /* IEGP to IE/LE.  */
+               case GOT_TLS_IEGP:
+                 switch (eff_tls_type)
                    {
-                     /* Build the different symbols that point to the same address.  */
-                     h_list = m_list->h_list;
-                     if (h_list->h->root.u.def.value == h->root.u.def.value
-                         && h_list->h->root.u.def.section->output_section->vma
-                            == h->root.u.def.section->output_section->vma
-                         && h_list->h->root.u.def.section->output_offset
-                            == h->root.u.def.section->output_offset
-                         && m_list->rel_backup.r_addend == rel_backup.r_addend)
+                   case GOT_TLS_IE:
+                     switch (r_type)
                        {
-                         m_list->times++;
-                         m_list->irel = jrel;
-                         while (h_list->h != h && h_list->next)
-                           h_list = h_list->next;
-                         if (h_list->h != h)
-                           {
-                             struct elf_link_hash_entry_list *h_list_new;
-
-                             h_list_new = (struct elf_link_hash_entry_list *)
-                               bfd_malloc (sizeof (struct elf_link_hash_entry_list));
-                             h_list->next = h_list_new;
-                             h_list_new->h = h;
-                             h_list_new->next = NULL;
-                           }
+                       case R_NDS32_TLS_IEGP_HI20:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IE_HI20);
+                         break;
+                       case R_NDS32_TLS_IEGP_LO12:
+                         irel->r_info = ELF32_R_INFO(r_symndx,
+                                                     R_NDS32_TLS_IE_LO12);
+                         break;
+                       case R_NDS32_PTR_RESOLVED:
+                         {
+                           uint32_t insn = bfd_getb32 (contents + irel->r_offset);
+
+                           add_rt = N32_RT5 (insn);
+                           insn = N32_TYPE2 (LWI, add_rt, sethi_rt, 0);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+                         }
+                         break;
+                       case R_NDS32_TLS_IEGP_LW:
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
                          break;
                        }
-                     /* The sethi case may have different address but the
-                        hi20 is the same.  */
-                     else if (ELF32_R_TYPE (jrel->r_info) == R_NDS32_HI20_RELA
-                              && m_list->next == NULL)
+                     break;
+                   case GOT_TLS_LE:
+                     switch (r_type)
                        {
-                         struct elf_link_hash_entry_mul_list *m_list_new;
-                         struct elf_link_hash_entry_list *h_list_new;
-
-                         m_list_new = (struct elf_link_hash_entry_mul_list *)
-                           bfd_malloc (sizeof (struct elf_link_hash_entry_mul_list));
-                         h_list_new = (struct elf_link_hash_entry_list *)
-                           bfd_malloc (sizeof (struct elf_link_hash_entry_list));
-                         m_list->next = m_list_new;
-                         m_list_new->h_list = h_list_new;
-                         m_list_new->rel_backup = rel_backup;
-                         m_list_new->times = 1;
-                         m_list_new->irel = jrel;
-                         m_list_new->next = NULL;
-                         h_list_new->h = h;
-                         h_list_new->next = NULL;
+                       case R_NDS32_TLS_IEGP_HI20:
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_HI20);
+                         break;
+                       case R_NDS32_TLS_IEGP_LO12:
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_LO12);
+                         break;
+                       case R_NDS32_TLS_IEGP_LW:
+                         bfd_putb32 (INSN_NOP, contents + irel->r_offset);
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_RELAX_REMOVE);
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                       case R_NDS32_PTR_RESOLVED:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
                          break;
                        }
-                     m_list = m_list->next;
+                     break;
+                   default:
+                     break;
                    }
-                 if (!m_list)
+                 break;
+                 /* IE to LE. */
+               case GOT_TLS_IE:
+                 switch (eff_tls_type)
                    {
-                     off += 4;
-                     continue;
+                   case GOT_TLS_LE:
+                     switch (r_type)
+                       {
+                       case R_NDS32_TLS_IE_HI20:
+                         irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_HI20);
+                         break;
+                       case R_NDS32_TLS_IE_LO12S2:
+                         {
+                           uint32_t insn = bfd_getb32 (contents + irel->r_offset);
+
+                           add_rt = N32_RT5 (insn);
+                           insn = N32_TYPE2 (ORI, add_rt, sethi_rt, 0);
+                           bfd_putb32 (insn, contents + irel->r_offset);
+
+                           irel->r_info = ELF32_R_INFO (r_symndx, R_NDS32_TLS_LE_LO12);
+                         }
+                         break;
+                       case R_NDS32_LOADSTORE:
+                       case R_NDS32_PTR:
+                       case R_NDS32_NONE:
+                       case R_NDS32_LABEL:
+                         break;
+                       default:
+                         BFD_ASSERT(0);
+                         break;
+                       }
+                     break;
+                   default:
+                     break;
                    }
+                 break;
+               default:
+                 break;
                }
            }
-         else
-           {
-             /* Local symbol and insn without relocation*/
-             entry->times++;
-             entry->rel_backup = rel_backup;
-           }
+         pNextSig = pNextSig->next_sibling;
+       }
 
-         /* Use in sethi insn with constant and global symbol in same format.  */
-         if (!jrel)
-           entry->const_insn = 1;
-         else
-           entry->irel = jrel;
-         entry->sec = isec;
-         off += 4;
+#if 1
+      pNext = pNext->next;
+#else
+      while (pNext)
+       {
+         if (pNext->id != cur_grp_id)
+           break;
+         pNext = pNext->next;
        }
+#endif
     }
-  return TRUE;
-}
-
-/* Set the _ITB_BASE, and point it to ex9 table.  */
 
-bfd_boolean
-nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
-{
-  bfd *abfd;
-  asection *sec;
-  bfd *output_bfd = NULL;
-  struct bfd_link_hash_entry *bh = NULL;
-  int target_optimize;
-  struct elf_nds32_link_hash_table *table;
+ finish:
+  if (incontents)
+    contents = NULL;
 
-  if (is_ITB_BASE_set == 1)
-    return TRUE;
+  if (elf_section_data (insec)->relocs != internal_relocs)
+    free (internal_relocs);
 
-  is_ITB_BASE_set = 1;
+  if (elf_section_data (insec)->this_hdr.contents != contents)
+    free (contents);
 
-  table = nds32_elf_hash_table (link_info);
-  target_optimize  = table->target_optimize;
+  if (symtab_hdr->contents != (bfd_byte *) local_syms)
+    free (local_syms);
 
-  for (abfd = link_info->input_bfds; abfd != NULL;
-       abfd = abfd->link_next)
+  if (chain.next)
     {
-      sec = bfd_get_section_by_name (abfd, ".ex9.itable");
-      if (sec != NULL)
+      pNext = chain.next;
+      relax_group_list_t *pDel;
+      while (pNext)
        {
-         output_bfd = sec->output_section->owner;
-         break;
+         pDel = pNext;
+         pNext = pNext->next;
+         free (pDel);
        }
     }
-  if (output_bfd == NULL)
-    {
-      output_bfd = link_info->output_bfd;
-      if (output_bfd->sections == NULL)
-       return TRUE;
-      else
-       sec = bfd_abs_section_ptr;
-    }
-  bh = bfd_link_hash_lookup (link_info->hash, "_ITB_BASE_",
-                            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),
-          (const char *) NULL, FALSE, get_elf_backend_data
-          (output_bfd)->collect, &bh));
-} /* End EX9.IT  */
-\f
+
+  return result;
+
+ error_return:
+  result = FALSE;
+  goto finish;
+}
+
+/* End TLS model conversion.  */
 
 #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                         bfd_elf32_nds32be_vec
+#define TARGET_BIG_SYM                         nds32_elf32_be_vec
 #define TARGET_BIG_NAME                                "elf32-nds32be"
-#define TARGET_LITTLE_SYM                      bfd_elf32_nds32le_vec
+#define TARGET_LITTLE_SYM                      nds32_elf32_le_vec
 #define TARGET_LITTLE_NAME                     "elf32-nds32le"
 
 #define elf_info_to_howto                      nds32_info_to_howto
@@ -14221,6 +13998,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
@@ -14231,7 +14009,6 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define elf_backend_size_dynamic_sections      nds32_elf_size_dynamic_sections
 #define elf_backend_relocate_section           nds32_elf_relocate_section
 #define elf_backend_gc_mark_hook               nds32_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook              nds32_elf_gc_sweep_hook
 #define elf_backend_grok_prstatus              nds32_elf_grok_prstatus
 #define elf_backend_grok_psinfo                        nds32_elf_grok_psinfo
 #define elf_backend_reloc_type_class           nds32_elf_reloc_type_class
@@ -14241,6 +14018,11 @@ 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 elf_backend_section_flags              nds32_elf_section_flags
+#define bfd_elf32_bfd_get_relocated_section_contents \
+                               nds32_elf_get_relocated_section_contents
+#define bfd_elf32_bfd_is_target_special_symbol nds32_elf_is_target_special_symbol
+#define elf_backend_maybe_function_sym         nds32_elf_maybe_function_sym
 
 #define elf_backend_can_gc_sections            1
 #define elf_backend_can_refcount               1
@@ -14251,21 +14033,22 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define elf_backend_may_use_rel_p              1
 #define elf_backend_default_use_rela_p         1
 #define elf_backend_may_use_rela_p             1
+#define elf_backend_dtrel_excludes_plt         0
 
 #include "elf32-target.h"
 
 #undef ELF_MAXPAGESIZE
 #define ELF_MAXPAGESIZE                                0x2000
 
-#undef TARGET_BIG_SYM
-#define TARGET_BIG_SYM                         bfd_elf32_nds32belin_vec
-#undef TARGET_BIG_NAME
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM                         nds32_elf32_linux_be_vec
+#undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME                                "elf32-nds32be-linux"
-#undef TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM                      bfd_elf32_nds32lelin_vec
-#undef TARGET_LITTLE_NAME
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                      nds32_elf32_linux_le_vec
+#undef  TARGET_LITTLE_NAME
 #define TARGET_LITTLE_NAME                     "elf32-nds32le-linux"
-#undef elf32_bed
+#undef  elf32_bed
 #define elf32_bed                              elf32_nds32_lin_bed
 
 #include "elf32-target.h"
This page took 0.27671 seconds and 4 git commands to generate.