x86: Don't set eh->local_ref to 1 for linker defined symbols
[deliverable/binutils-gdb.git] / bfd / elf32-nds32.c
index d1a2c3035cd084fa720b0211840733fcb96451d4..1b30d127a5ae19684409ffd7c413d655060304fc 100644 (file)
@@ -1,5 +1,5 @@
 /* NDS32-specific support for 32-bit ELF.
-   Copyright (C) 2012-2014 Free Software Foundation, Inc.
+   Copyright (C) 2012-2018 Free Software Foundation, Inc.
    Contributed by Andes Technology Corporation.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -17,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-   02110-1301, USA.*/
+   02110-1301, USA.  */
 
 
 #include "sysdep.h"
@@ -56,70 +56,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 *);
+(bfd *, Elf_Internal_Rela *, Elf_Internal_Sym *, Elf_Internal_Shdr *);
+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,
@@ -154,39 +98,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,26 +176,6 @@ 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
-{
-  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;
-};
-
 /* Nds32 ELF linker hash entry.  */
 
 struct elf_nds32_link_hash_entry
@@ -242,14 +183,45 @@ 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;
+  struct elf_dyn_relocs *dyn_relocs;
+
+  /* For checking relocation type.  */
+#define GOT_UNKNOWN     0
+#define GOT_NORMAL      1
+#define GOT_TLS_IE      2
+  unsigned int tls_type;
 };
 
 /* Get the nds32 ELF linker hash table from a link_info structure.  */
 
 #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
+
+struct elf_nds32_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+};
+
+#define elf_nds32_tdata(bfd) \
+  ((struct elf_nds32_obj_tdata *) (bfd)->tdata.any)
+
+#define elf32_nds32_local_got_tls_type(bfd) \
+  (elf_nds32_tdata (bfd)->local_got_tls_type)
+
+#define elf32_nds32_hash_entry(ent) ((struct elf_nds32_link_hash_entry *)(ent))
+
+static bfd_boolean
+nds32_elf_mkobject (bfd *abfd)
+{
+  return bfd_elf_allocate_object (abfd, sizeof (struct elf_nds32_obj_tdata),
+                                 NDS32_ELF_DATA);
+}
 
 /* Relocations used for relocation.  */
 static reloc_howto_type nds32_elf_howto_table[] =
@@ -257,11 +229,11 @@ 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 */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_NDS32_NONE",        /* name */
         FALSE,                 /* partial_inplace */
@@ -1704,6 +1676,234 @@ static reloc_howto_type nds32_elf_howto_table[] =
         0x1ff,                 /* src_mask */
         0x1ff,                 /* dst_mask */
         TRUE),                 /* pcrel_offset */
+
+  /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol.  */
+  HOWTO (R_NDS32_TLS_LE_HI20,  /* type */
+        12,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_HI20", /* name */
+        FALSE,                 /* partial_inplace */
+        0x000fffff,            /* src_mask */
+        0x000fffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_LO12,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        12,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_LO12", /* name */
+        FALSE,                 /* partial_inplace */
+        0x00000fff,            /* src_mask */
+        0x00000fff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like R_NDS32_HI20, but referring to the TLS entry for the symbol.  */
+  HOWTO (R_NDS32_TLS_IE_HI20,  /* type */
+        12,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_IE_HI20", /* name */
+        FALSE,                 /* partial_inplace */
+        0x000fffff,            /* src_mask */
+        0x000fffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_IE_LO12S2,        /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        10,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_IE_LO12S2",       /* name */
+        FALSE,                 /* partial_inplace */
+        0x000003ff,            /* src_mask */
+        0x000003ff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* Mark a TLS IE entry in GOT.  */
+  HOWTO (R_NDS32_TLS_TPOFF,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,    /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_TPOFF",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  /* A 20 bit address.  */
+  HOWTO (R_NDS32_TLS_LE_20,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_20",   /* name */
+        FALSE,         /* partial_inplace */
+        0xfffff,               /* src_mask */
+        0xfffff,               /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S0,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S0", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S1,  /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S1", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_15S2,  /* type */
+        2,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        15,                    /* bitsize */
+        FALSE,         /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed,      /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_NDS32_TLS_LE_15S2", /* name */
+        FALSE,         /* partial_inplace */
+        0x7fff,                /* src_mask */
+        0x7fff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for unconditional call sequence  */
+  HOWTO (R_NDS32_LONGCALL4,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL4",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional call sequence.  */
+  HOWTO (R_NDS32_LONGCALL5,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL5",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional call sequence.  */
+  HOWTO (R_NDS32_LONGCALL6,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGCALL6",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for unconditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP4,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP4",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP5,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP5",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP6,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP6",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Relax hint for conditional branch sequence.  */
+  HOWTO (R_NDS32_LONGJUMP7,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_LONGJUMP7",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 /* Relocations used for relaxation.  */
@@ -1956,6 +2156,45 @@ static reloc_howto_type nds32_elf_relax_howto_table[] =
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_ADD,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_TLS_LE_ADD",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_TLS_LE_LS,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_TLS_LE_LS",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_NDS32_EMPTY,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        nds32_elf_ignore_reloc,        /* special_function */
+        "R_NDS32_EMPTY",               /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 };
 
 \f
@@ -1967,8 +2206,8 @@ 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 = xmalloc (size);
 
   /* If i is less than j, i is inserted before j.
 
@@ -1977,19 +2216,22 @@ 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);
       memcpy (ptr + j * size, tmp, size);
     }
+  free (tmp);
 }
 
 /* Sort relocation by r_offset.
@@ -2065,7 +2307,8 @@ nds32_elf_9_pcrel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 static bfd_reloc_status_type
 nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto,
                            asection *input_section, bfd_byte *data,
-                           bfd_vma offset, asection *symbol_section ATTRIBUTE_UNUSED,
+                           bfd_vma offset,
+                           asection *symbol_section ATTRIBUTE_UNUSED,
                            bfd_vma symbol_value, bfd_vma addend)
 {
   bfd_signed_vma relocation;
@@ -2084,7 +2327,7 @@ nds32_elf_do_9_pcrel_reloc (bfd *abfd, reloc_howto_type *howto,
      before doing pcrel calculations.  */
   relocation -= (offset & -(bfd_vma) 2);
 
-  if (relocation < -0x100 || relocation > 0xff)
+  if (relocation < -ACCURATE_8BIT_S1 || relocation >= ACCURATE_8BIT_S1)
     status = bfd_reloc_overflow;
   else
     status = bfd_reloc_ok;
@@ -2495,9 +2738,16 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_LONGCALL1, R_NDS32_LONGCALL1},
   {BFD_RELOC_NDS32_LONGCALL2, R_NDS32_LONGCALL2},
   {BFD_RELOC_NDS32_LONGCALL3, R_NDS32_LONGCALL3},
+  {BFD_RELOC_NDS32_LONGCALL4, R_NDS32_LONGCALL4},
+  {BFD_RELOC_NDS32_LONGCALL5, R_NDS32_LONGCALL5},
+  {BFD_RELOC_NDS32_LONGCALL6, R_NDS32_LONGCALL6},
   {BFD_RELOC_NDS32_LONGJUMP1, R_NDS32_LONGJUMP1},
   {BFD_RELOC_NDS32_LONGJUMP2, R_NDS32_LONGJUMP2},
   {BFD_RELOC_NDS32_LONGJUMP3, R_NDS32_LONGJUMP3},
+  {BFD_RELOC_NDS32_LONGJUMP4, R_NDS32_LONGJUMP4},
+  {BFD_RELOC_NDS32_LONGJUMP5, R_NDS32_LONGJUMP5},
+  {BFD_RELOC_NDS32_LONGJUMP6, R_NDS32_LONGJUMP6},
+  {BFD_RELOC_NDS32_LONGJUMP7, R_NDS32_LONGJUMP7},
   {BFD_RELOC_NDS32_LOADSTORE, R_NDS32_LOADSTORE},
   {BFD_RELOC_NDS32_9_FIXED, R_NDS32_9_FIXED_RELA},
   {BFD_RELOC_NDS32_15_FIXED, R_NDS32_15_FIXED_RELA},
@@ -2538,6 +2788,7 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_RELAX_REGION_END, R_NDS32_RELAX_REGION_END},
   {BFD_RELOC_NDS32_MINUEND, R_NDS32_MINUEND},
   {BFD_RELOC_NDS32_SUBTRAHEND, R_NDS32_SUBTRAHEND},
+  {BFD_RELOC_NDS32_EMPTY, R_NDS32_EMPTY},
 
   {BFD_RELOC_NDS32_DIFF8, R_NDS32_DIFF8},
   {BFD_RELOC_NDS32_DIFF16, R_NDS32_DIFF16},
@@ -2548,6 +2799,17 @@ static const struct nds32_reloc_map_entry nds32_reloc_map[] =
   {BFD_RELOC_NDS32_TRAN, R_NDS32_TRAN},
   {BFD_RELOC_NDS32_17IFC_PCREL, R_NDS32_17IFC_PCREL_RELA},
   {BFD_RELOC_NDS32_10IFCU_PCREL, R_NDS32_10IFCU_PCREL_RELA},
+  {BFD_RELOC_NDS32_TLS_LE_HI20, R_NDS32_TLS_LE_HI20},
+  {BFD_RELOC_NDS32_TLS_LE_LO12, R_NDS32_TLS_LE_LO12},
+  {BFD_RELOC_NDS32_TLS_LE_ADD, R_NDS32_TLS_LE_ADD},
+  {BFD_RELOC_NDS32_TLS_LE_LS, R_NDS32_TLS_LE_LS},
+  {BFD_RELOC_NDS32_TLS_IE_HI20, R_NDS32_TLS_IE_HI20},
+  {BFD_RELOC_NDS32_TLS_IE_LO12S2, R_NDS32_TLS_IE_LO12S2},
+  {BFD_RELOC_NDS32_TLS_TPOFF, R_NDS32_TLS_TPOFF},
+  {BFD_RELOC_NDS32_TLS_LE_20, R_NDS32_TLS_LE_20},
+  {BFD_RELOC_NDS32_TLS_LE_15S0, R_NDS32_TLS_LE_15S0},
+  {BFD_RELOC_NDS32_TLS_LE_15S1, R_NDS32_TLS_LE_15S1},
+  {BFD_RELOC_NDS32_TLS_LE_15S2, R_NDS32_TLS_LE_15S2},
 };
 
 /* Patch tag.  */
@@ -2605,25 +2867,43 @@ 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);
-  BFD_ASSERT (ELF32_R_TYPE (dst->r_info) <= R_NDS32_GNU_VTENTRY);
+  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;
+    }
   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.
@@ -2687,6 +2967,7 @@ nds32_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
        _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;
@@ -2802,7 +3083,7 @@ nds32_elf_add_symbol_hook (bfd *abfd,
 
 static asection *sda_rela_sec = NULL;
 
-#define SDA_SECTION_NUM 11
+#define SDA_SECTION_NUM 10
 
 static bfd_reloc_status_type
 nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
@@ -2811,6 +3092,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
   int relax_fp_as_gp;
   struct elf_nds32_link_hash_table *table;
   struct bfd_link_hash_entry *h, *h2;
+  long unsigned int total = 0;
 
   h = bfd_link_hash_lookup (info->hash, "_SDA_BASE_", FALSE, FALSE, TRUE);
   if (!h || (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak))
@@ -2823,7 +3105,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
       static const char sec_name[SDA_SECTION_NUM][10] =
        {
          ".data", ".got", ".sdata_d", ".sdata_w", ".sdata_h", ".sdata_b",
-         ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d", ".bss"
+         ".sbss_b", ".sbss_h", ".sbss_w", ".sbss_d"
        };
       size_t i = 0;
 
@@ -2834,24 +3116,49 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
        }
 
       /* Get the first and final section.  */
-      while (i < sizeof (sec_name) / 10)
+      while (i < sizeof (sec_name) / sizeof (sec_name [0]))
        {
          temp = bfd_get_section_by_name (output_bfd, sec_name[i]);
          if (temp && !first && (temp->size != 0 || temp->rawsize != 0))
            first = temp;
          if (temp && (temp->size != 0 || temp->rawsize != 0))
            final = temp;
+
+         /* Summarize the sections in order to check if joining .bss.  */
+         if (temp && temp->size != 0)
+           total += temp->size;
+         else if (temp && temp->rawsize != 0)
+           total += temp->rawsize;
+
          i++;
        }
 
+      /* Check .bss size.  */
+      temp = bfd_get_section_by_name (output_bfd, ".bss");
+      if (temp)
+       {
+         if (temp->size != 0)
+           total += temp->size;
+         else if (temp->rawsize != 0)
+           total += temp->rawsize;
+
+         if (total < 0x80000)
+           {
+             if (!first && (temp->size != 0 || temp->rawsize != 0))
+               first = temp;
+             if ((temp->size != 0 || temp->rawsize != 0))
+               final = temp;
+           }
+       }
+
       if (first && final)
        {
          /* The middle of data region.  */
-         sda_base = (final->vma + final->rawsize + first->vma) / 2;
+         sda_base = final->vma / 2 + final->rawsize / 2 + first->vma / 2;
 
          /* Find the section sda_base located.  */
          i = 0;
-         while (i < sizeof (sec_name) / 10)
+         while (i < sizeof (sec_name) / sizeof (sec_name [0]))
            {
              final = bfd_get_section_by_name (output_bfd, sec_name[i]);
              if (final && (final->size != 0 || final->rawsize != 0)
@@ -2876,7 +3183,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
              *psb = elf_gp (output_bfd);
              return bfd_reloc_ok;
            }
-         sda_base = first->vma;
+         sda_base = first->vma + first->rawsize;
        }
 
       sda_base -= first->vma;
@@ -2907,7 +3214,7 @@ nds32_elf_final_sda_base (bfd *output_bfd, struct bfd_link_info *info,
        }
     }
 
-  if (add_symbol == TRUE)
+  if (add_symbol)
     {
       if (h)
        {
@@ -2918,7 +3225,7 @@ 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;
        }
     }
@@ -2963,6 +3270,7 @@ nds32_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
 
       eh = (struct elf_nds32_link_hash_entry *) ret;
       eh->dyn_relocs = NULL;
+      eh->tls_type = GOT_UNKNOWN;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -2991,51 +3299,10 @@ 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;
 }
 
-/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
-   shortcuts to them in our hash table.  */
-
-static bfd_boolean
-create_got_section (bfd *dynobj, struct bfd_link_info *info)
-{
-  struct elf_nds32_link_hash_table *htab;
-
-  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)
-    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,
-                                (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                 | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                                 | SEC_READONLY))
-      || !bfd_set_section_alignment (dynobj, htab->srelgot, 2))
-    return FALSE;
-
-  return TRUE;
-}
-
-/* Create dynamic sections when linking against a dynamic object.  */
+/* Create dynamic sections when linking against a dynamic object.  */
 
 static bfd_boolean
 nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
@@ -3064,7 +3331,7 @@ nds32_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
     pltflags |= SEC_READONLY;
 
   s = bfd_make_section (abfd, ".plt");
-  htab->splt = s;
+  htab->root.splt = s;
   if (s == NULL
       || !bfd_set_section_flags (abfd, s, pltflags)
       || !bfd_set_section_alignment (abfd, s, bed->plt_alignment))
@@ -3087,19 +3354,19 @@ 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;
+  htab->root.srelplt = s;
   if (s == NULL
       || !bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
       || !bfd_set_section_alignment (abfd, s, ptralign))
     return FALSE;
 
-  if (htab->sgot == NULL && !create_got_section (abfd, info))
+  if (htab->root.sgot == NULL && !_bfd_elf_create_got_section (abfd, info))
     return FALSE;
 
   {
@@ -3152,7 +3419,7 @@ 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"));
@@ -3182,8 +3449,8 @@ nds32_elf_copy_indirect_symbol (struct bfd_link_info *info,
     {
       if (edir->dyn_relocs != NULL)
        {
-         struct elf_nds32_dyn_relocs **pp;
-         struct elf_nds32_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          if (ind->root.type == bfd_link_hash_indirect)
            abort ();
@@ -3192,7 +3459,7 @@ nds32_elf_copy_indirect_symbol (struct bfd_link_info *info,
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL;)
            {
-             struct elf_nds32_dyn_relocs *q;
+             struct elf_dyn_relocs *q;
 
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
@@ -3215,6 +3482,22 @@ nds32_elf_copy_indirect_symbol (struct bfd_link_info *info,
   _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 \f
+/* Find dynamic relocs for H that apply to read-only sections.  */
+
+static asection *
+readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+  struct elf_dyn_relocs *p;
+
+  for (p = elf32_nds32_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+    {
+      asection *s = p->sec->output_section;
+
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+       return p->sec;
+    }
+  return NULL;
+}
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
@@ -3227,8 +3510,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 +3519,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 +3528,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 +3551,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 +3567,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 +3576,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 (0 && !readonly_dynrelocs (h))
     {
       h->non_got_ref = 0;
       return TRUE;
@@ -3379,7 +3651,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct bfd_link_info *info;
   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;
@@ -3405,9 +3677,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 = htab->root.splt;
 
          /* If this is the first .plt entry, make room for the special
             first entry.  */
@@ -3421,7 +3693,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 +3704,10 @@ 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;
+         htab->root.sgotplt->size += 4;
 
          /* We also need to make an entry in the .rel.plt section.  */
-         htab->srelplt->size += sizeof (Elf32_External_Rela);
+         htab->root.srelplt->size += sizeof (Elf32_External_Rela);
        }
       else
        {
@@ -3453,6 +3725,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       asection *s;
       bfd_boolean dyn;
+      int tls_type = elf32_nds32_hash_entry (h)->tls_type;
 
       /* Make sure this symbol is output as a dynamic symbol.
         Undefined weak syms won't yet be marked as dynamic.  */
@@ -3462,13 +3735,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            return FALSE;
        }
 
-      s = htab->sgot;
-
+      s = htab->root.sgot;
       h->got.offset = s->size;
-      s->size += 4;
+
+      if (tls_type == GOT_UNKNOWN)
+       abort ();
+      else if (tls_type == GOT_NORMAL
+              || tls_type == GOT_TLS_IE)
+       /* Need a GOT slot.  */
+       s->size += 4;
+
       dyn = htab->root.dynamic_sections_created;
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h))
-       htab->srelgot->size += sizeof (Elf32_External_Rela);
+      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h))
+       htab->root.srelgot->size += sizeof (Elf32_External_Rela);
     }
   else
     h->got.offset = (bfd_vma) - 1;
@@ -3482,11 +3761,11 @@ 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;)
            {
@@ -3540,31 +3819,29 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
-/* Find any dynamic relocs that apply to read-only sections.  */
+/* Set DF_TEXTREL if we find any dynamic relocs that apply to
+   read-only sections.  */
 
 static bfd_boolean
-readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
 {
-  struct elf_nds32_link_hash_entry *eh;
-  struct elf_nds32_dyn_relocs *p;
+  asection *sec;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
 
-  eh = (struct elf_nds32_link_hash_entry *) h;
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  sec = readonly_dynrelocs (h);
+  if (sec != NULL)
     {
-      asection *s = p->sec->output_section;
+      struct bfd_link_info *info = (struct bfd_link_info *) info_p;
 
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
-       {
-         struct bfd_link_info *info = (struct bfd_link_info *) inf;
+      info->flags |= DF_TEXTREL;
+      info->callbacks->minfo
+       (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
+        sec->owner, h->root.root.string, sec);
 
-         info->flags |= DF_TEXTREL;
-
-         /* Not an error, just cut short the traversal.  */
-         return FALSE;
-       }
+      /* Not an error, just cut short the traversal.  */
+      return FALSE;
     }
   return TRUE;
 }
@@ -3588,7 +3865,7 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->root.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);
@@ -3612,9 +3889,9 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       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)
            {
@@ -3643,15 +3920,15 @@ 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;
+      s = htab->root.sgot;
+      srel = htab->root.srelgot;
       for (; local_got < end_local_got; ++local_got)
        {
          if (*local_got > 0)
            {
              *local_got = s->size;
              s->size += 4;
-             if (info->shared)
+             if (bfd_link_pic (info))
                srel->size += sizeof (Elf32_External_Rela);
            }
          else
@@ -3671,22 +3948,22 @@ nds32_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       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.  */
        }
-      else if (s == htab->sgot)
+      else if (s == htab->root.sgot)
        {
          got_size += s->size;
        }
-      else if (s == htab->sgotplt)
+      else if (s == htab->root.sgotplt)
        {
          got_size += s->size;
        }
       else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
        {
-         if (s->size != 0 && s != htab->srelplt)
+         if (s->size != 0 && s != htab->root.srelplt)
            relocs = TRUE;
 
          /* We use the reloc_count field as a counter if we need
@@ -3735,13 +4012,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_pic (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
        }
 
-      if (htab->splt->size != 0)
+      if (htab->root.splt->size != 0)
        {
          if (!add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
@@ -3760,7 +4037,7 @@ 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, maybe_set_textrel,
                                    (void *) info);
 
          if ((info->flags & DF_TEXTREL) != 0)
@@ -3795,11 +4072,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 +4234,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)
@@ -4060,15 +4331,24 @@ nds32_elf_output_symbol_hook (struct bfd_link_info *info,
    section, which means that the addend must be adjusted
    accordingly.  */
 
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
 static bfd_boolean
-nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
+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;
@@ -4095,8 +4375,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
   dynobj = htab->root.dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
-  sgot = htab->sgot;
-  splt = htab->splt;
+  sgot = htab->root.sgot;
+  splt = htab->root.splt;
   sreloc = NULL;
 
   rel = relocs;
@@ -4105,7 +4385,7 @@ 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))
+  if ((!bfd_link_relocatable (info)))
     {
       is_SDA_BASE_set = 1;
       r = nds32_elf_final_sda_base (output_bfd, info, &gp, TRUE);
@@ -4139,8 +4419,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;
@@ -4153,10 +4434,12 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          || r_type == R_NDS32_RELA_GNU_VTINHERIT
          || (r_type >= R_NDS32_INSN16 && r_type <= R_NDS32_25_FIXED_RELA)
          || r_type == R_NDS32_DATA
-         || r_type == R_NDS32_TRAN)
+         || r_type == R_NDS32_TRAN
+         || (r_type >= R_NDS32_LONGCALL4 && r_type <= R_NDS32_LONGJUMP7))
        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))
        {
@@ -4175,7 +4458,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
       if (((r_type >= R_NDS32_DWARF2_OP1_RELA
            && r_type <= R_NDS32_DWARF2_LEB_RELA)
-          || r_type >= R_NDS32_RELAX_ENTRY) && !info->relocatable)
+          || r_type >= R_NDS32_RELAX_ENTRY) && !bfd_link_relocatable (info))
        continue;
 
       howto = bfd_elf32_bfd_reloc_type_table_lookup (r_type);
@@ -4223,7 +4506,7 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
        }
 
-      if (info->relocatable)
+      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,
@@ -4383,8 +4666,10 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
              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))
@@ -4431,14 +4716,14 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                {
                  bfd_put_32 (output_bfd, relocation, sgot->contents + off);
 
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    {
                      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");
+                     srelgot = htab->root.srelgot;
                      BFD_ASSERT (srelgot != NULL);
 
                      outrel.r_offset = (elf_gp (output_bfd)
@@ -4477,7 +4762,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))
@@ -4578,11 +4863,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;
@@ -4616,7 +4901,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                }
              else
                r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                             contents, offset, relocation, addend);
+                                             contents, offset, relocation,
+                                             addend);
            }
 
          goto check_reloc;
@@ -4637,11 +4923,12 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
 
                  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))
+                     (dyn, bfd_link_pic (info), h)
+                     || (bfd_link_pic (info)
+                         && (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
@@ -4683,14 +4970,14 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
                    {
                      bfd_put_32 (output_bfd, relocation, sgot->contents + off);
 
-                     if (info->shared)
+                     if (bfd_link_pic (info))
                        {
                          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");
+                         srelgot = htab->root.srelgot;
                          BFD_ASSERT (srelgot != NULL);
 
                          outrel.r_offset = (elf_gp (output_bfd)
@@ -4712,8 +4999,8 @@ nds32_elf_relocate_section (bfd *                  output_bfd ATTRIBUTE_UNUSED,
          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;
@@ -4754,8 +5041,8 @@ handle_sda:
              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);
+                 _bfd_error_handler
+                   (_("%pB: warning: relocate SDA_BASE failed"), input_bfd);
                  ret = FALSE;
                  goto check_reloc;
                }
@@ -4775,8 +5062,10 @@ handle_sda:
              if (relocation & align)
                {
                  /* Incorrect alignment.  */
-                 (*_bfd_error_handler)
-                   (_("%B(%A): warning: unaligned small data access of type %d."),
+                 _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;
@@ -4789,6 +5078,101 @@ handle_sda:
          /* do nothing */
          break;
 
+       case R_NDS32_TLS_LE_HI20:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_LE_20:
+       case R_NDS32_TLS_LE_15S0:
+       case R_NDS32_TLS_LE_15S1:
+       case R_NDS32_TLS_LE_15S2:
+         if (elf_hash_table (info)->tls_sec != NULL)
+           relocation -= (elf_hash_table (info)->tls_sec->vma + TP_OFFSET);
+         break;
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+         {
+           /* Relocation is to the entry for this symbol in the global
+              offset table.  */
+           unsigned int tls_type;
+           asection *srelgot;
+           Elf_Internal_Rela outrel;
+           bfd_vma off;
+           bfd_byte *loc;
+           int indx = 0;
+
+           BFD_ASSERT (sgot != NULL);
+           if (h != NULL)
+             {
+               bfd_boolean dyn;
+
+               off = h->got.offset;
+               BFD_ASSERT (off != (bfd_vma) - 1);
+               dyn = htab->root.dynamic_sections_created;
+               tls_type = ((struct elf_nds32_link_hash_entry *) h)->tls_type;
+               if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+                   && (!bfd_link_pic (info)
+                       || !SYMBOL_REFERENCES_LOCAL (info, h)))
+                 indx = h->dynindx;
+             }
+           else
+             {
+               /* Never happen currently.  */
+               BFD_ASSERT (local_got_offsets != NULL
+                           && local_got_offsets[r_symndx] != (bfd_vma) - 1);
+
+               off = local_got_offsets[r_symndx];
+
+               tls_type = elf32_nds32_local_got_tls_type (input_bfd)[r_symndx];
+             }
+           relocation = sgot->output_section->vma + sgot->output_offset + off;
+
+           if (r_type == R_NDS32_TLS_IE_LO12S2)
+             break;
+
+           /* The offset must always be a multiple of 4.  We use
+              the least significant bit to record whether we have
+              already processed this entry.  */
+           if ((off & 1) != 0)
+             off &= ~1;
+           else
+             {
+               bfd_boolean need_relocs = FALSE;
+               srelgot = htab->root.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 (tls_type & GOT_TLS_IE)
+                 {
+                   if (need_relocs)
+                     {
+                       if (h->dynindx == 0)
+                         outrel.r_addend = relocation - dtpoff_base (info);
+                       else
+                         outrel.r_addend = 0;
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset
+                                          + off);
+                       outrel.r_info =
+                         ELF32_R_INFO (h->dynindx, R_NDS32_TLS_TPOFF);
+
+                       loc = srelgot->contents;
+                       loc +=
+                         srelgot->reloc_count * sizeof (Elf32_External_Rela);
+                       bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                       ++srelgot->reloc_count;
+                     }
+                   else
+                     bfd_put_32 (output_bfd, h->root.u.def.value - TP_OFFSET,
+                                 sgot->contents + off);
+                 }
+             }
+         }
+       break;
+
          /* DON'T   fall through.  */
 
        default:
@@ -4855,8 +5239,16 @@ handle_sda:
        case R_NDS32_PLT_GOTREL_LO20:
        case R_NDS32_17IFC_PCREL_RELA:
        case R_NDS32_10IFCU_PCREL_RELA:
+       case R_NDS32_TLS_LE_HI20:
+       case R_NDS32_TLS_LE_LO12:
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+       case R_NDS32_TLS_LE_20:
+       case R_NDS32_TLS_LE_15S0:
+       case R_NDS32_TLS_LE_15S1:
+       case R_NDS32_TLS_LE_15S2:
          /* Instruction related relocs must handle endian properly.  */
-         /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER */
+         /* NOTE: PIC IS NOT HANDLE YET; DO IT LATER */
          r = nds32_elf_final_link_relocate (howto, input_bfd,
                                             input_section, contents,
                                             rel->r_offset, relocation,
@@ -4894,16 +5286,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,10 +5312,9 @@ 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;
            }
        }
@@ -4962,9 +5351,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 = htab->root.splt;
+      sgot = htab->root.sgotplt;
+      srela = htab->root.srelplt;
       BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
 
       /* Get the index in the procedure linkage table which
@@ -4979,7 +5368,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;
 
@@ -5071,8 +5460,8 @@ nds32_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
       /* This symbol has an entry in the global offset table.
         Set it up.  */
 
-      sgot = htab->sgot;
-      srela = htab->srelgot;
+      sgot = htab->root.sgot;
+      srela = htab->root.srelgot;
       BFD_ASSERT (sgot != NULL && srela != NULL);
 
       rela.r_offset = (sgot->output_section->vma
@@ -5083,7 +5472,7 @@ 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
+      if (bfd_link_pic (info)
          && (info->symbolic
              || h->dynindx == -1 || h->forced_local) && h->def_regular)
        {
@@ -5154,7 +5543,7 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
   htab = nds32_elf_hash_table (info);
   dynobj = htab->root.dynobj;
 
-  sgot = htab->sgotplt;
+  sgot = htab->root.sgotplt;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (htab->root.dynamic_sections_created)
@@ -5180,49 +5569,28 @@ nds32_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
              break;
 
            case DT_PLTGOT:
-             /* name = ".got"; */
-             s = htab->sgot->output_section;
+             s = htab->root.sgotplt;
              goto get_vma;
            case DT_JMPREL:
-             s = htab->srelplt->output_section;
+             s = htab->root.srelplt;
            get_vma:
-             BFD_ASSERT (s != NULL);
-             dyn.d_un.d_ptr = s->vma;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
 
            case DT_PLTRELSZ:
-             s = htab->srelplt->output_section;
-             BFD_ASSERT (s != NULL);
+             s = htab->root.srelplt;
              dyn.d_un.d_val = s->size;
              bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
              break;
-
-           case DT_RELASZ:
-             /* My reading of the SVR4 ABI indicates that the
-                procedure linkage table relocs (DT_JMPREL) should be
-                included in the overall relocs (DT_RELA).  This is
-                what Solaris does.  However, UnixWare can not handle
-                that case.  Therefore, we override the DT_RELASZ entry
-                here to make it not include the JMPREL relocs.  Since
-                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)
-               {
-                 s = htab->srelplt->output_section;
-                 dyn.d_un.d_val -= s->size;
-               }
-             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
-             break;
            }
        }
 
       /* Fill in the first entry in the procedure linkage table.  */
-      splt = htab->splt;
+      splt = htab->root.splt;
       if (splt && splt->size > 0)
        {
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              unsigned long insn;
              long offset;
@@ -5433,7 +5801,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 +5811,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 +5832,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;
@@ -5485,8 +5856,8 @@ 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;
@@ -5495,9 +5866,9 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   in_version = elf_elfheader (ibfd)->e_flags & EF_NDS32_ELF_VERSION;
   if (in_version == E_NDS32_ELF_VER_1_2)
     {
-      (*_bfd_error_handler)
-       (_("%B: warning: Older version of object file encountered, "
-          "Please recompile with current tool chain."), ibfd);
+      _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.  */
@@ -5573,8 +5944,8 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   /* 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_error_handler
+       (_("%pB: error: ABI mismatch with previous modules"), ibfd);
 
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
@@ -5584,8 +5955,9 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
     {
       if (((in_flags & EF_NDS_ARCH) != E_N1_ARCH))
        {
-         (*_bfd_error_handler)
-           (_("%B: error: Instruction set mismatch with previous modules."), ibfd);
+         _bfd_error_handler
+           (_("%pB: error: instruction set mismatch with previous modules"),
+            ibfd);
 
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
@@ -5609,9 +5981,11 @@ nds32_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   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]);
+       _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]);
 
       elf_elfheader (obfd)->e_flags = in_flags | out_flags
        | (in_16regs & out_16regs) | (in_no_mac & out_no_mac)
@@ -5680,136 +6054,6 @@ 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)
-{
-  /* 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);
-
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    {
-      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;
-       }
-
-      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;
-
-       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;
-
-             if (!info->shared && h->plt.refcount > 0)
-               h->plt.refcount -= 1;
-
-             eh = (struct elf_nds32_link_hash_entry *) h;
-
-             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;
-
-       case R_NDS32_9_PLTREL:
-       case R_NDS32_25_PLTREL:
-         if (h != NULL)
-           {
-             if (h->plt.refcount > 0)
-               h->plt.refcount--;
-           }
-         break;
-
-       default:
-         break;
-       }
-    }
-
-  return TRUE;
-}
-
 /* Look through the relocs for a section during the first phase.
    Since we don't do .gots or .plts, we just need to consider the
    virtual table relocs for gc.  */
@@ -5826,7 +6070,16 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   bfd *dynobj;
   asection *sreloc = NULL;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
+    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;
@@ -5845,6 +6098,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       enum elf_nds32_reloc_type r_type;
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
+      int tls_type, old_tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -5858,8 +6112,10 @@ 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)
+      /* Some relocs require a global offset table.  We create
+        got section here, since these relocation need got section
+        and it is not created yet.  */
+      if (htab->root.sgot == NULL)
        {
          switch (r_type)
            {
@@ -5878,9 +6134,11 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            case R_NDS32_GOTPC_HI20:
            case R_NDS32_GOTPC_LO12:
            case R_NDS32_GOT20:
+           case R_NDS32_TLS_IE_HI20:
+           case R_NDS32_TLS_IE_LO12S2:
              if (dynobj == NULL)
                htab->root.dynobj = dynobj = abfd;
-             if (!create_got_section (dynobj, info))
+             if (!_bfd_elf_create_got_section (dynobj, info))
                return FALSE;
              break;
 
@@ -5896,8 +6154,23 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_NDS32_GOT_LO15:
        case R_NDS32_GOT_LO19:
        case R_NDS32_GOT20:
+       case R_NDS32_TLS_IE_HI20:
+       case R_NDS32_TLS_IE_LO12S2:
+         switch (r_type)
+           {
+           case R_NDS32_TLS_IE_HI20:
+           case R_NDS32_TLS_IE_LO12S2:
+             tls_type = GOT_TLS_IE;
+             break;
+           default:
+             tls_type = GOT_NORMAL;
+             break;
+           }
          if (h != NULL)
-           h->got.refcount += 1;
+           {
+             old_tls_type = elf32_nds32_hash_entry (h)->tls_type;
+             h->got.refcount += 1;
+           }
          else
            {
              bfd_signed_vma *local_got_refcounts;
@@ -5917,9 +6190,24 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
                }
              local_got_refcounts[r_symndx] += 1;
+             old_tls_type = elf32_nds32_local_got_tls_type (abfd)[r_symndx];
            }
-         break;
 
+         /* We will already have issued an error message if there
+            is a TLS/non-TLS mismatch, based on the symbol
+            type.  So just combine any TLS types needed.  */
+         if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
+             && tls_type != GOT_NORMAL)
+           tls_type |= old_tls_type;
+
+         if (old_tls_type != tls_type)
+           {
+             if (h != NULL)
+               elf32_nds32_hash_entry (h)->tls_type = tls_type;
+             else
+               elf32_nds32_local_got_tls_type (abfd)[r_symndx] = tls_type;
+           }
+         break;
        case R_NDS32_9_PLTREL:
        case R_NDS32_25_PLTREL:
        case R_NDS32_PLTREL_HI20:
@@ -5944,6 +6232,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (h->forced_local)
            break;
 
+         elf32_nds32_hash_entry (h)->tls_type = GOT_NORMAL;
          h->needs_plt = 1;
          h->plt.refcount += 1;
          break;
@@ -5975,7 +6264,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 +6286,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 +6297,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;
@@ -6064,6 +6353,7 @@ nds32_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              else
                {
                  asection *s;
+                 void *vpp;
 
                  Elf_Internal_Sym *isym;
                  isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx);
@@ -6075,15 +6365,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);
+                 p = (struct elf_dyn_relocs *) bfd_alloc (dynobj, amt);
                  if (p == NULL)
                    return FALSE;
                  p->next = *head;
@@ -6254,7 +6544,7 @@ calculate_plt_memory_address (bfd *abfd, struct bfd_link_info *link_info,
       h = elf_sym_hashes (abfd)[indx];
       BFD_ASSERT (h != NULL);
       htab = nds32_elf_hash_table (link_info);
-      splt = htab->splt;
+      splt = htab->root.splt;
 
       while (h->root.type == bfd_link_hash_indirect
             || h->root.type == bfd_link_hash_warning)
@@ -6303,7 +6593,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 +6808,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 +6892,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 +7018,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 +7033,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 +7121,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 +7156,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
              insn16 = N16_TYPE38 (BEQZ38, N32_RT5 (insn), N32_IMM16S (insn));
              insn_type = NDS32_INSN_BEQZ38;
            }
-         else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8))
+         else if (N32_RT5 (insn) == REG_R15
+                  && IS_WITHIN_S (N32_IMM16S (insn), 8))
            {
              insn16 = N16_TYPE8 (BEQZS8, N32_IMM16S (insn));
              insn_type = NDS32_INSN_BEQZS8;
@@ -6876,7 +7170,8 @@ nds32_convert_32_to_16 (bfd *abfd, uint32_t insn, uint16_t *pinsn16,
              insn16 = N16_TYPE38 (BNEZ38, N32_RT5 (insn), N32_IMM16S (insn));
              insn_type = NDS32_INSN_BNEZ38;
            }
-         else if (N32_RT5 (insn) == REG_R15 && IS_WITHIN_S (N32_IMM16S (insn), 8))
+         else if (N32_RT5 (insn) == REG_R15
+                  && IS_WITHIN_S (N32_IMM16S (insn), 8))
            {
              insn16 = N16_TYPE8 (BNEZS8, N32_IMM16S (insn));
              insn_type = NDS32_INSN_BNEZS8;
@@ -6894,7 +7189,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))
@@ -7026,71 +7321,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 +7411,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 +7425,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));
@@ -7132,30 +7444,35 @@ nds32_convert_16_to_32 (bfd *abfd, uint16_t insn16, uint32_t *pinsn)
       goto done;
 
     case 0x3f:                 /* MISC33 */
-      switch (insn & 0x7)
+      switch (insn16 & 0x7)
        {
        case 2:                 /* neg33 */
          insn = N32_TYPE2 (SUBRI, N16_RT3 (insn16), N16_RA3 (insn16), 0);
          break;
        case 3:                 /* not33 */
-         insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (NOR, N16_RT3 (insn16), N16_RA3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 4:                 /* mul33 */
-         insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU2 (MUL, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 5:                 /* xor33 */
-         insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (XOR, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 6:                 /* and33 */
-         insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (AND, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        case 7:                 /* or33 */
-         insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16), N16_RA3 (insn16));
+         insn = N32_ALU1 (OR, N16_RT3 (insn16), N16_RT3 (insn16),
+                          N16_RA3 (insn16));
          break;
        }
       goto done;
 
-    case 0xb:                  /* ... */
+    case 0xb:
       switch (insn16 & 0x7)
        {
        case 0:                 /* zeb33 */
@@ -7178,11 +7495,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 +7510,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 +7525,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));
@@ -7311,7 +7628,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 +7636,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 +7650,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;
@@ -7503,15 +7820,17 @@ calculate_got_memory_address (bfd *abfd, struct bfd_link_info *link_info,
   if (symndx >= 0)
     {
       BFD_ASSERT (h != NULL);
-      return htab->sgot->output_section->vma + htab->sgot->output_offset
-            + h->got.offset;
+      return (htab->root.sgot->output_section->vma
+             + htab->root.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)];
+      return (htab->root.sgot->output_section->vma
+             + htab->root.sgot->output_offset
+             + local_got_offsets[ELF32_R_SYM (irel->r_info)]);
     }
 
   /* The _GLOBAL_OFFSET_TABLE_ may be undefweak(or should be?).  */
@@ -7564,7 +7883,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 +7901,7 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
   /* Find the first relocation of the same relocation-type,
      so we iteratie them forward.  */
   pc_rel = reloc;
-  while ((pc_rel - 1) > internal_relocs && pc_rel[-1].r_offset == offset)
+  while ((pc_rel - 1) >= internal_relocs && pc_rel[-1].r_offset == offset)
     pc_rel--;
 
   for (; pc_rel < irelend && pc_rel->r_offset == offset; pc_rel++)
@@ -7594,19 +7913,29 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
        {
          off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr,
                                  &pic_ext_target);
-         if (off > 0xff || off < -0x100 || off == 0)
+         if (off >= ACCURATE_8BIT_S1 || off < -ACCURATE_8BIT_S1
+             || off == 0)
            return FALSE;
          break;
        }
       else if (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_20_RELA)
        {
          /* movi => movi55  */
-         mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf, symtab_hdr);
-         /* mem_addr is unsigned, but the value should be between [-16, 15].  */
+         mem_addr = calculate_memory_address (abfd, pc_rel, isymbuf,
+                                              symtab_hdr);
+         /* mem_addr is unsigned, but the value should
+            be between [-16, 15].  */
          if ((mem_addr + 0x10) >> 5)
            return FALSE;
          break;
        }
+      else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_20)
+              || (ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_TLS_LE_LO12))
+       {
+         /* It never happen movi to movi55 for R_NDS32_TLS_LE_20,
+            because it can be relaxed to addi for TLS_LE_ADD.  */
+         return FALSE;
+       }
       else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA15S2_RELA
                || ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_SDA17S2_RELA)
               && (reloc->r_addend & R_NDS32_INSN16_FP7U2_FLAG)
@@ -7624,9 +7953,18 @@ is_convert_32_to_16 (bfd *abfd, asection *sec,
               || ((ELF32_R_TYPE (pc_rel->r_info) > R_NDS32_LOADSTORE)
                   && (ELF32_R_TYPE (pc_rel->r_info) < R_NDS32_DWARF2_OP1_RELA)))
        {
-         /* Prevent unresolved addi instruction translate to addi45 or addi333.  */
+         /* Prevent unresolved addi instruction translate
+            to addi45 or addi333.  */
          return FALSE;
        }
+      else if ((ELF32_R_TYPE (pc_rel->r_info) == R_NDS32_17IFC_PCREL_RELA))
+       {
+         off = calculate_offset (abfd, sec, pc_rel, isymbuf, symtab_hdr,
+                                 &pic_ext_target);
+         if (off >= ACCURATE_U9BIT_S1 || off <= 0)
+           return FALSE;
+         break;
+       }
     }
 
   return TRUE;
@@ -7669,6 +8007,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 +8036,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 +8058,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;
@@ -7985,7 +8326,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 +8396,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 +8407,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 +8441,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 +8474,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;
 
@@ -8138,14 +8496,17 @@ done_adjust_diff:
          if (sec == sect)
            {
              raddr = irel->r_offset;
-             irel->r_offset -= get_nds32_elf_blank_total (&blank_t2, irel->r_offset, 1);
+             irel->r_offset -= get_nds32_elf_blank_total (&blank_t2,
+                                                          irel->r_offset, 1);
 
              if (ELF32_R_TYPE (irel->r_info) == R_NDS32_NONE)
                continue;
              if (blank_t2 && blank_t2->next
-                 && (blank_t2->offset > raddr || blank_t2->next->offset <= raddr))
-               (*_bfd_error_handler) (_("%B: %s\n"), abfd,
-                                      "Error: search_nds32_elf_blank reports wrong node");
+                 && (blank_t2->offset > raddr
+                     || blank_t2->next->offset <= raddr))
+               _bfd_error_handler
+                 (_("%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 +8558,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 +8591,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 +8644,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 +8654,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 +8689,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 +8715,9 @@ relax_range_measurement (bfd *abfd)
   /* For upper bound.   */
   bfd_vma maxpgsz = get_elf_backend_data (abfd)->maxpagesize;
   bfd_vma align;
-  bfd_vma init_range;
   static int decide_relax_range = 0;
   int i;
+  int range_number = sizeof (sdata_init_range) / sizeof (sdata_init_range[0]);
 
   if (decide_relax_range)
     return;
@@ -8359,7 +8726,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 +8747,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,5815 +8763,3907 @@ 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;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
   uint16_t insn16;
-  bfd_vma local_sda;
 
-  /* Target dependnet option.  */
-  struct elf_nds32_link_hash_table *table;
-  int load_store_relax;
-  int relax_round;
-
-  relax_blank_list = NULL;
-
-  *again = FALSE;
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-  /* Nothing to do for
-   * relocatable link or
-   * non-relocatable section or
-   * non-code section or
-   * empty content or
-   * no reloc entry.  */
-  if (link_info->relocatable
-      || (sec->flags & SEC_RELOC) == 0
-      || (sec->flags & SEC_EXCLUDE) == 1
-      || (sec->flags & SEC_CODE) == 0
-      || sec->size == 0)
-    return TRUE;
+  hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_HI20_RELA, laddr);
+  lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_LO12S0_ORI_RELA,
+                                          laddr + 4);
 
-  /* 09.12.11 Workaround.  */
-  /*  We have to adjust align for R_NDS32_LABEL if needed.
-     The adjust approach only can fix 2-byte align once.  */
-  if (sec->alignment_power > 2)
+  if (hi_irelfn == irelend || lo_irelfn == irelend)
     {
-      (*_bfd_error_handler)
-       (_("%B(%A): warning: relax is suppressed for sections "
-          "of alignment %d-bytes > 4-byte."),
-        abfd, sec, sec->alignment_power);
-      return TRUE;
+      _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,
+                          &pic_ext_target);
 
-  table = nds32_elf_hash_table (link_info);
-  relax_round = table->relax_round;
-  switch (relax_round)
-    {
-    case NDS32_RELAX_JUMP_IFC_ROUND:
-      /* Here is the entrance of ifc jump relaxation.  */
-      if (!nds32_elf_ifc_calc (link_info, abfd, sec))
-       return FALSE;
-      return TRUE;
+  /* This condition only happened when symbol is undefined.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-    case NDS32_RELAX_EX9_BUILD_ROUND:
-      /* Here is the entrance of ex9 relaxation.  There are two pass of
-        ex9 relaxation.  The one is to traverse all instructions and build
-        the hash table.  The other one is to compare instructions and replace
-        it by ex9.it.  */
-      if (!nds32_elf_ex9_build_hash_table (abfd, sec, link_info))
-       return FALSE;
-      return TRUE;
+  /* Relax to: jal symbol; 25_PCREL */
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
+
+  /* Replace the long call with a jal.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                              R_NDS32_25_PCREL_RELA);
+  irel->r_addend = hi_irelfn->r_addend;
+
+  /* We don't resolve this here but resolve it in relocate_section.  */
+  insn = INSN_JAL;
+  bfd_putb32 (insn, contents + irel->r_offset);
+
+  hi_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+  lo_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
+  *insn_len = 4;
+
+  if (seq_len & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16);
+      lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  return TRUE;
+}
 
-    case NDS32_RELAX_EX9_REPLACE_ROUND:
-      if (!nds32_elf_ex9_replace_instruction (link_info, abfd, sec))
-       return FALSE;
-      return TRUE;
+#define CONVERT_CONDITION_CALL(insn) (((insn) & 0xffff0000) ^ 0x90000)
+/* Relax LONGCALL2 relocation for nds32_elf_relax_section.  */
 
-    default:
-      if (sec->reloc_count == 0)
-       return TRUE;
-      break;
-    }
+static bfd_boolean
+nds32_elf_relax_longcall2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* bltz  rt, .L1   ; LONGCALL2
+     jal   symbol   ; 25_PCREL
+     .L1: */
 
-  /* The begining of general relaxation.  */
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-  if (is_SDA_BASE_set == 0)
-    {
-      bfd_vma gp;
-      is_SDA_BASE_set = 1;
-      nds32_elf_final_sda_base (sec->output_section->owner, link_info, &gp, FALSE);
-      relax_range_measurement (abfd);
-    }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *i1_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+
+  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,
+                          &pic_ext_target);
 
-  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY)
-    {
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG)
-       return TRUE;
+  if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG)
-       optimize = 1;
+  /* Relax to  bgezal   rt, label ; 17_PCREL
+     or                bltzal   rt, label ; 17_PCREL */
+
+  /* Convert to complimentary conditional call.  */
+  insn = CONVERT_CONDITION_CALL (insn);
+
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
+
+  /* Clean unnessary relocations.  */
+  i1_irelfn->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
+  cond_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_17_PCREL_RELA, laddr);
+  if (cond_irelfn != irelend)
+    cond_irelfn->r_info =
+      ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info), R_NDS32_NONE);
+
+  /* Replace the long call with a bgezal.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
+                              R_NDS32_17_PCREL_RELA);
+  irel->r_addend = i1_irelfn->r_addend;
+
+  bfd_putb32 (insn, contents + irel->r_offset);
+
+  *insn_len = 4;
+  return TRUE;
+}
 
-      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG)
-       optimize_for_space = 1;
+/* Relax LONGCALL3 relocation for nds32_elf_relax_section.  */
+
+static bfd_boolean
+nds32_elf_relax_longcall3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGCALL3
+     case 4-4-4-2; 16-bit on, optimize off or optimize for space
+     bltz  rt,  $1                ; LONGCALL3
+     sethi ta,  hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral5 ta                     ;
+     $1
+
+     case 4-4-4-4; 16-bit off, optimize don't care
+     bltz  rt,  $1                ; LONGCALL3
+     sethi ta,  hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral  ta                     ;
+     $1
+
+     case 4-4-4-4; 16-bit on, optimize for speed
+     bltz  rt,  $1                ; LONGCALL3
+     sethi ta,  hi20(symbol)      ; HI20
+     ori   ta, ta,  lo12(symbol)   ; LO12S0
+     jral  ta                     ;
+     $1 */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint16_t insn16;
+
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
+
+  hi_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_HI20_RELA, laddr + 4);
+  lo_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_LO12S0_ORI_RELA, laddr + 8);
+
+  if (hi_irelfn == irelend || lo_irelfn == irelend)
+    {
+      _bfd_error_handler (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,
+                          &pic_ext_target);
 
-  /* Get symbol table and section content.  */
-  if (!nds32_get_section_contents (abfd, sec, &contents)
-      || !nds32_get_local_syms (abfd, sec, &isymbuf))
-    goto error_return;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-  /* Do relax loop only when finalize is not done.
-     Take care of relaxable relocs except INSN16.  */
-  for (irel = internal_relocs; irel < irelend; irel++)
+  insn = bfd_getb32 (contents + laddr);
+  if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
     {
-      bfd_vma laddr;
-      unsigned long comp_insn = 0;
-      unsigned short comp_insn16 = 0;
-      unsigned long i_mask = 0xffffffff;
-      int seq_len;             /* Original length of instruction sequence.  */
-      int insn_len = 0;                /* Final length of instruction sequence.  */
-      int convertible;         /* 1st insn convertible.  */
-      int insn16_on;           /* 16-bit on/off.  */
-      Elf_Internal_Rela *hi_irelfn = NULL;
-      Elf_Internal_Rela *lo_irelfn = NULL;
-      Elf_Internal_Rela *i1_irelfn = NULL;
-      Elf_Internal_Rela *i2_irelfn = NULL;
-      Elf_Internal_Rela *cond_irelfn = NULL;
-      int i1_offset = 0;
-      int i2_offset = 0;
-      bfd_signed_vma foff;
-      unsigned long reloc = R_NDS32_NONE;
-      int hi_off;
-      int insn_off;
-      int pic_ext_target = 0;
-      bfd_vma access_addr = 0;
-      bfd_vma range_l = 0, range_h = 0;        /* Upper/lower bound.  */
+      /* Relax to  bgezal   rt, label ; 17_PCREL
+        or        bltzal   rt, label ; 17_PCREL */
 
-      insn = 0;
-      insn16 = 0;
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
-         && (irel->r_addend & 0x1f) >= 2)
-       optimize = 1;
+      /* Convert to complimentary conditional call.  */
+      insn = CONVERT_CONDITION_CALL (insn);
+      bfd_putb32 (insn, contents + irel->r_offset);
 
-      /* Relocation Types
-        R_NDS32_LONGCALL1      53
-        R_NDS32_LONGCALL2      54
-        R_NDS32_LONGCALL3      55
-        R_NDS32_LONGJUMP1      56
-        R_NDS32_LONGJUMP2      57
-        R_NDS32_LONGJUMP3      58
-        R_NDS32_LOADSTORE      59  */
-      if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
-         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE)
+      *insn_len = 4;
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+      hi_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
+
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_17_PCREL_RELA, laddr);
+      if (cond_irelfn != irelend)
        {
-         seq_len = GET_SEQ_LEN (irel->r_addend);
-         insn_opt = IS_OPTIMIZE (irel->r_addend);
-         convertible = IS_1ST_CONVERT (irel->r_addend);
-         insn16_on = IS_16BIT_ON (irel->r_addend);
-         laddr = irel->r_offset;
+         cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                             R_NDS32_17_PCREL_RELA);
+         cond_irelfn->r_addend = hi_irelfn->r_addend;
        }
-      /* Relocation Types
-        R_NDS32_LO12S0_RELA            30
-        R_NDS32_LO12S1_RELA            29
-        R_NDS32_LO12S2_RELA            28
-        R_NDS32_LO12S2_SP_RELA         71
-        R_NDS32_LO12S2_DP_RELA         70
-        R_NDS32_GOT_LO12               46
-        R_NDS32_GOTOFF_LO12            50
-        R_NDS32_PLTREL_LO12            65
-        R_NDS32_PLT_GOTREL_LO12        67
-        R_NDS32_GOT_SUFF               193
-        R_NDS32_GOTOFF_SUFF            194
-        R_NDS32_PLT_GOT_SUFF           195
-        R_NDS32_MULCALL_SUFF           196
-        R_NDS32_PTR                    197  */
-      else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA
-               && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA)
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12
-              || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF
-                  && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR)
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTBLOCK
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA)
+
+      if (seq_len & 0x2)
        {
-         seq_len = 0;
-         insn_opt = IS_OPTIMIZE (irel->r_addend) > 0;
-         convertible = 0;
-         insn16_on = 0;
-         laddr = irel->r_offset;
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+         hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                           R_NDS32_INSN16);
+         hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+         insn_len += 2;
        }
-      else
-       continue;
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 && foff < CONSERVATIVE_24BIT_S1)
+    {
+      /* Relax to the following instruction sequence
+        bltz  rt,   $1 ; LONGCALL2
+        jal   symbol   ; 25_PCREL
+        $1     */
+      *insn_len = 8;
+      insn = INSN_JAL;
+      bfd_putb32 (insn, contents + hi_irelfn->r_offset);
 
-      insn_len = seq_len;
+      hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                       R_NDS32_25_PCREL_RELA);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2);
+
+      lo_irelfn->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
 
-      if (laddr + seq_len > (bfd_vma) sec->size)
+      if (seq_len & 0x2)
        {
-         char *s = NULL;
-         int pass_check = 0;
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+         lo_irelfn->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_INSN16);
+         lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+         insn_len += 2;
+       }
+    }
+  return TRUE;
+}
 
-         if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
-             && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP3)
-           {
-             for (i1_irelfn = irel;
-                  i1_irelfn < irelend && i1_irelfn->r_offset < (laddr + seq_len - 4);
-                  i1_irelfn++)
-               ;
-
-             for (;
-                  i1_irelfn < irelend && i1_irelfn->r_offset == (laddr + seq_len - 4);
-                  i1_irelfn++)
-               if (ELF32_R_TYPE (i1_irelfn->r_info) == R_NDS32_INSN16)
-                 {
-                   pass_check = 1;
-                   break;
-                 }
-             i1_irelfn = NULL;
-           }
+/* Relax LONGJUMP1 relocation for nds32_elf_relax_section.  */
 
-         if (pass_check == 0)
-           {
-             reloc_howto_type *howto =
-               bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE
-                                                      (irel->r_info));
-             s = howto->name;
+static bfd_boolean
+nds32_elf_relax_longjump1 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGJUMP1
+     case 4-4-2; 16-bit bit on, optimize off or optimize for space
+     sethi ta, hi20(symbol)     ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)         ; LO12S0
+     jr5   ta                   ;
+
+     case 4-4-4; 16-bit off, optimize don't care
+     sethi ta, hi20(symbol)     ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)         ; LO12S0
+     jr           ta                    ;
+
+     case 4-4-4; 16-bit on, optimize for speed
+     sethi ta, hi20(symbol)     ; LONGJUMP1/HI20
+     ori   ta, ta, lo12(symbol)         ; LO12S0
+     jr           ta                    ;      */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  int insn16_on;       /* 16-bit on/off.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint16_t insn16;
+  unsigned long reloc;
+
+  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;
+    }
 
-             (*_bfd_error_handler)
-              ("%B: warning: %s points to unrecognized insns at 0x%lx.",
-               abfd, s, (long) irel->r_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);
 
-             continue;
-           }
-       }
+  if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-      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 (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;
+    }
 
-         i1_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_INSN16,
-                                                  laddr + i1_offset);
+  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;
+}
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+/* Revert condition branch.  This function does not check if the input
+   instruction is condition branch or not.  */
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
+static void
+nds32_elf_convert_branch (uint16_t insn16, uint32_t insn,
+                          uint16_t *re_insn16, uint32_t *re_insn)
+{
+  uint32_t comp_insn = 0;
+  uint16_t comp_insn16 = 0;
+
+  if (insn)
+    {
+      if (N32_OP6 (insn) == N32_OP6_BR1)
+       {
+         /* beqs label.  */
+         comp_insn = (insn ^ 0x4000) & 0xffffc000;
+         if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5)
            {
-             continue;
+             /* Insn can be contracted to 16-bit implied r5.  */
+             comp_insn16 =
+               (comp_insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38;
+             comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
            }
-
-         /* Relax to
-            jal   symbol   ; 25_PCREL */
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
-
-         /* Replace the long call with a jal.  */
-         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                      R_NDS32_25_PCREL_RELA);
-         irel->r_addend = hi_irelfn->r_addend;
-
-         /* We don't resolve this here but resolve it in relocate_section.  */
-         insn = INSN_JAL;
-
-         bfd_putb32 (insn, contents + irel->r_offset);
-         hi_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-         lo_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-         insn_len = 4;
-         if (i1_irelfn != irelend)
+       }
+      else if (N32_OP6 (insn) == N32_OP6_BR3)
+       {
+         /* bnec $ta, imm11, label.  */
+         comp_insn = (insn ^ 0x80000) & 0xffffff00;
+       }
+      else
+       {
+         comp_insn = (insn ^ 0x10000) & 0xffffc000;
+         if (N32_BR2_SUB (insn) == N32_BR2_BEQZ
+             || N32_BR2_SUB (insn) == N32_BR2_BNEZ)
            {
-             if (!insn_opt
-                 && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
+             if (N32_IS_RT3 (insn))
                {
-                 /* The instruction pointed by R_NDS32_INSN16 is already
-                    turned into 16-bit instruction, so the total length of
-                    this sequence is decreased by 2.  */
-                 seq_len = seq_len - 2;
+                 /* Insn can be contracted to 16-bit.  */
+                 comp_insn16 =
+                   (comp_insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38;
+                 comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
+               }
+             else if (N32_RT5 (insn) == REG_R15)
+               {
+                 /* Insn can be contracted to 16-bit.  */
+                 comp_insn16 =
+                   (comp_insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38;
                }
-             i1_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-           }
-         if (seq_len & 0x2)
-           {
-             insn16 = NDS32_NOP16;
-             bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                             R_NDS32_INSN16);
-             lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-             insn_len += 2;
            }
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL2)
+    }
+  else
+    {
+      switch ((insn16 & 0xf000) >> 12)
        {
-         /* bltz  rt, $1   ; LONGCALL2
-            jal   symbol   ; 25_FIXED
-            $1: */
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_25_PCREL_RELA, laddr + 4);
+       case 0xc:
+         /* beqz38 or bnez38 */
+         comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ;
+         comp_insn |= ((comp_insn16 & 0x0700) >> 8) << 20;
+         break;
 
-         if (i1_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_LONGCALL2 points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
+       case 0xd:
+         /* beqs38 or bnes38 */
+         comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0800) ? INSN_BNE : INSN_BEQ;
+         comp_insn |= (((comp_insn16 & 0x0700) >> 8) << 20)
+           | (REG_R5 << 15);
+         break;
 
-             continue;
-           }
+       case 0xe:
+         /* beqzS8 or bnezS8 */
+         comp_insn16 = (insn16 ^ 0x0100) & 0xff00;
+         comp_insn = (comp_insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ;
+         comp_insn |= REG_R15 << 20;
+         break;
 
-         insn = bfd_getb32 (contents + laddr);
+       default:
+         break;
+       }
+    }
+  if (comp_insn && re_insn)
+    *re_insn = comp_insn;
+  if (comp_insn16 && re_insn16)
+    *re_insn16 = comp_insn16;
+}
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, i1_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (foff == 0)
-           continue;
-         if (foff < -0x10000 - 4 || foff >= 0x10000 - 4)
-           /* After all that work, we can't shorten this function call.  */
-           continue;
+/* Relax LONGJUMP2 relocation for nds32_elf_relax_section.  */
 
-         /* Relax to   bgezal   rt, label ; 17_PCREL
-            or         bltzal   rt, label ; 17_PCREL */
+static bfd_boolean
+nds32_elf_relax_longjump2 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 3 variations for LONGJUMP2
+     case 2-4;  1st insn convertible, 16-bit on,
+     optimize off or optimize for space
+     bnes38  rt, ra, $1 ; LONGJUMP2
+     j       label      ; 25_PCREL
+     $1:
+
+     case 4-4; 1st insn not convertible
+     bne  rt, ra, $1 ; LONGJUMP2
+     j    label      ; 25_PCREL
+     $1:
+
+     case 4-4; 1st insn convertible, 16-bit on, optimize for speed
+     bne  rt, ra, $1 ; LONGJUMP2
+     j    label      ; 25_PCREL
+     $1: */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  Elf_Internal_Rela *i2_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0, first_size;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc, cond_reloc;
 
-         /* Convert to complimentary conditional call.  */
-         insn &= 0xffff0000;
-         insn ^= 0x90000;
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
 
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
+  first_size = (seq_len == 6) ? 2 : 4;
+
+  i2_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs,
+                                irelend, R_NDS32_25_PCREL_RELA,
+                                laddr + first_size);
+
+  for (i = 0; i < sizeof (checked_types) / sizeof(checked_types[0]); i++)
+    {
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    checked_types[i], laddr);
+      if (cond_irelfn != irelend)
+       break;
+    }
 
-         /* Replace the long call with a bgezal.  */
-         irel->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                         R_NDS32_17_PCREL_RELA);
+  if (i2_irelfn == irelend || cond_irelfn == irelend)
+    {
+      _bfd_error_handler (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,
+                     &pic_ext_target);
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         i1_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-         cond_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_17_PCREL_RELA, laddr);
-         if (cond_irelfn != irelend)
-           {
-             cond_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                             R_NDS32_17_PCREL_RELA);
-             cond_irelfn->r_addend = i1_irelfn->r_addend;
-           }
-         insn_len = 4;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGCALL3)
-       {
-         /* There are 3 variations for LONGCALL3
-            case 4-4-4-2; 16-bit on, optimize off or optimize for space
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral5 ta                      ;
-            $1
-
-            case 4-4-4-4; 16-bit off, optimize don't care
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral  ta                      ;
-            $1
-
-            case 4-4-4-4; 16-bit on, optimize for speed
-            bltz  rt,   $1                ; LONGCALL3
-            sethi ta,   hi20(symbol)      ; HI20
-            ori   ta, ta,  lo12(symbol)   ; LO12S0
-            jral  ta                      ; (INSN16)
-            $1 */
-
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         hi_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_HI20_RELA, laddr + 4);
-         lo_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_LO12S0_ORI_RELA, laddr + 8);
-         i2_offset = 12;
+  /* Get the all corresponding instructions.  */
+  if (first_size == 4)
+    {
+      insn = bfd_getb32 (contents + laddr);
+      nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
+    }
+  else
+    {
+      insn16 = bfd_getb16 (contents + laddr);
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             i2_offset = 8;
-             hi_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_20_RELA, laddr + 4);
+  if (re_insn16 && foff >= -(ACCURATE_8BIT_S1 - first_size)
+      && foff < ACCURATE_8BIT_S1 - first_size)
+    {
+      if (first_size == 4)
+       {
+         /* Don't convert it to 16-bit now, keep this as relaxable for
+            ``label reloc; INSN16''.  */
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGCALL3 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
-                 continue;
-               }
-           }
+         /* Save comp_insn32 to buffer.  */
+         bfd_putb32 (re_insn, contents + irel->r_offset);
+         *insn_len = 4;
+         reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ?
+           R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+         cond_reloc = R_NDS32_INSN16;
+       }
+      else
+       {
+         bfd_putb16 (re_insn16, contents + irel->r_offset);
+         *insn_len = 2;
+         reloc = R_NDS32_9_PCREL_RELA;
+         cond_reloc = R_NDS32_NONE;
+       }
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR1
+          && (foff >= -(ACCURATE_14BIT_S1 - first_size)
+              && foff < ACCURATE_14BIT_S1 - first_size))
+    {
+      /* beqs     label    ; 15_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_15_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1
+          && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz     label ; 17_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_17_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+    }
+  else
+    return FALSE;
 
-         i2_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr + i2_offset);
+  /* Set all relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc);
+  irel->r_addend = i2_irelfn->r_addend;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           continue;
+  cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
+                                     cond_reloc);
+  cond_irelfn->r_addend = 0;
 
-         insn = bfd_getb32 (contents + laddr);
-         if (foff >= -0x10000 - 4 && foff < 0x10000 - 4)
-           {
-             /* Relax to  bgezal   rt, label ; 17_PCREL
-                or        bltzal   rt, label ; 17_PCREL */
+  if ((seq_len ^ *insn_len ) & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + 4);
+      i2_irelfn->r_offset = 4;
+      i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
+                                       R_NDS32_INSN16);
+      i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  else
+    i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
+                                     R_NDS32_NONE);
+  return TRUE;
+}
 
-             /* Convert to complimentary conditional call.  */
-             insn &= 0xffff0000;
-             insn ^= 0x90000;
-             bfd_putb32 (insn, contents + irel->r_offset);
+/* Relax LONGJUMP3 relocation for nds32_elf_relax_section.  */
 
-             insn_len = 4;
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                             R_NDS32_NONE);
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (i2_irelfn != irelend)
-               {
-                 if (!insn_opt
-                     && (i2_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-                   {
-                     /* The instruction pointed by R_NDS32_INSN16 is already
-                        turned into 16-bit instruction, so the total length
-                        of this sequence is decreased by 2.  */
-                     seq_len = seq_len - 2;
-                   }
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_NONE);
-               }
-             cond_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_17_PCREL_RELA, laddr);
-             if (cond_irelfn != irelend)
-               {
-                 cond_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_17_PCREL_RELA);
-                 cond_irelfn->r_addend = hi_irelfn->r_addend;
-               }
+static bfd_boolean
+nds32_elf_relax_longjump3 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 5 variations for LONGJUMP3
+     case 1: 2-4-4-2; 1st insn convertible, 16-bit on,
+     optimize off or optimize for space
+     bnes38   rt, ra, $1           ; LONGJUMP3
+     sethi    ta, hi20(symbol)     ; HI20
+     ori      ta, ta, lo12(symbol)  ; LO12S0
+     jr5      ta                   ;
+     $1:                           ;
+
+     case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed
+     bnes38   rt, ra, $1          ; LONGJUMP3
+     sethi    ta, hi20(symbol)    ; HI20
+     ori      ta, ta, lo12(symbol) ; LO12S0
+     jr5      ta                  ;
+     $1:                          ; LABEL
+
+     case 3: 4-4-4-2; 1st insn not convertible, 16-bit on,
+     optimize off or optimize for space
+     bne   rt, ra, $1          ; LONGJUMP3
+     sethi ta, hi20(symbol)    ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr5   ta                  ;
+     $1:                       ;
+
+     case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care
+     16-bit off if no INSN16
+     bne   rt, ra, $1          ; LONGJUMP3
+     sethi ta, hi20(symbol)    ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr           ta                   ;
+     $1:                       ;
+
+     case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed
+     16-bit off if no INSN16
+     bne   rt, ra, $1          ; LONGJUMP3
+     sethi ta, hi20(symbol)    ; HI20
+     ori   ta, ta, lo12(symbol) ; LO12S0
+     jr           ta                   ;
+     $1:                       ; LABEL */
+
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
+
+  int reloc_off = 0, cond_removed = 0, convertible;
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  Elf_Internal_Rela *hi_irelfn, *lo_irelfn, *cond_irelfn, *irelend;
+  int pic_ext_target = 0, first_size;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc, cond_reloc;
 
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 hi_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 hi_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else
-           {
-             /* Relax to the following instruction sequence
-                 bltz  rt,   $1 ; LONGCALL2
-                 jal   symbol   ; 25_PCREL
-                 $1
-              */
-             insn = (insn & 0xffff0000) | 4;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             /* This relax is incorrect.  Review, fix and test it.
-                Check 6a726f0f for the oringnal code.  */
-             BFD_ASSERT (0);
-
-             bfd_putb32 (insn, contents + irel->r_offset + 4);
-             insn_len = 8;
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                             R_NDS32_25_PCREL_RELA);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGCALL2);
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (i2_irelfn != irelend)
-               {
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_NONE);
-               }
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP1)
-       {
-         /* There are 3 variations for LONGJUMP1
-            case 4-4-2; 16-bit bit on, optimize off or optimize for space
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr5   ta                    ;
+  convertible = IS_1ST_CONVERT (irel->r_addend);
 
-            case 4-4-4; 16-bit off, optimize don't care
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr    ta                    ;
+  if (convertible)
+    first_size = 2;
+  else
+    first_size = 4;
+
+  /* Get all needed relocations.  */
+  hi_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_HI20_RELA, laddr + first_size);
+  lo_irelfn =
+    find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                R_NDS32_LO12S0_ORI_RELA,
+                                laddr + first_size + 4);
+
+  for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+    {
+      cond_irelfn =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    checked_types[i], laddr);
+      if (cond_irelfn != irelend)
+       break;
+    }
 
-            case 4-4-4; 16-bit on, optimize for speed
-            sethi ta, hi20(symbol)      ; LONGJUMP1/HI20
-            ori   ta, ta, lo12(symbol)  ; LO12S0
-            jr    ta                    ; INSN16 */
+  if (hi_irelfn == irelend || lo_irelfn == irelend || cond_irelfn == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP3",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         hi_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_HI20_RELA, laddr);
-         lo_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_LO12S0_ORI_RELA, laddr + 4);
-         i1_offset = 8;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             hi_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            R_NDS32_20_RELA, laddr);
-             i1_offset = 4;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-             if (hi_irelfn == irelend)
-               {
-                 (*_bfd_error_handler)
-                  ("%B: warning: R_NDS32_LONGJUMP1 points to unrecognized reloc at 0x%lx.",
-                   abfd, (long) irel->r_offset);
+  /* Get the all corresponding instructions.  */
+  if (first_size == 4)
+    {
+      insn = bfd_getb32 (contents + laddr);
+      nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
+    }
+  else
+    {
+      insn16 = bfd_getb16 (contents + laddr);
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
 
-                 continue;
-               }
-           }
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr + i1_offset);
+  if (re_insn16 && foff >= -ACCURATE_8BIT_S1 - first_size
+      && foff < ACCURATE_8BIT_S1 - first_size)
+    {
+      if (!(seq_len & 0x2))
+       {
+         /* Don't convert it to 16-bit now, keep this as relaxable
+            for ``label reloc; INSN1a''6.  */
+         /* Save comp_insn32 to buffer.  */
+         bfd_putb32 (re_insn, contents + irel->r_offset);
+         *insn_len = 4;
+         reloc = (N32_OP6 (re_insn) == N32_OP6_BR1) ?
+           R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+         cond_reloc = R_NDS32_INSN16;
+       }
+      else
+       {
+         /* Not optimize for speed; convert sequence to 16-bit.  */
+         /* Save comp_insn16 to buffer.  */
+         bfd_putb16 (re_insn16, contents + irel->r_offset);
+         *insn_len = 2;
+         reloc = R_NDS32_9_PCREL_RELA;
+         cond_reloc = R_NDS32_NONE;
+       }
+      cond_removed = 1;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR1
+          && (foff >= -(ACCURATE_14BIT_S1 - first_size)
+              && foff < ACCURATE_14BIT_S1 - first_size))
+    {
+      /* beqs     label    ; 15_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_15_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+      cond_removed = 1;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1
+          && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz     label ; 17_PCREL */
+      bfd_putb32 (re_insn, contents + irel->r_offset);
+      *insn_len = 4;
+      reloc = R_NDS32_17_PCREL_RELA;
+      cond_reloc = R_NDS32_NONE;
+      cond_removed = 1;
+    }
+  else if (foff >= -CONSERVATIVE_24BIT_S1 - reloc_off
+          && foff < CONSERVATIVE_24BIT_S1 - reloc_off)
+    {
+      /* Relax to one of the following 3 variations
+
+        case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize
+        for space
+        bnes38  rt, $1 ; LONGJUMP2
+        j       label  ; 25_PCREL
+        $1
+
+        case 4-4; 1st insn not convertible, others don't care
+        bne   rt, ra, $1 ; LONGJUMP2
+        j     label      ; 25_PCREL
+        $1
+
+        case 4-4; 1st insn convertible, 16-bit on, optimize for speed
+        bne   rt, ra, $1 ; LONGJUMP2
+        j     label      ; 25_PCREL
+        $1 */
+
+      /* Offset for first instruction.  */
+
+      /* Use j label as second instruction.  */
+      *insn_len = 4 + first_size;
+      insn = INSN_J;
+      bfd_putb32 (insn, contents + hi_irelfn->r_offset);
+      reloc = R_NDS32_LONGJUMP2;
+      cond_reloc = R_NDS32_25_PLTREL;
+    }
+    else
+      return FALSE;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, hi_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
+    if (cond_removed == 1)
+      {
+       /* Set all relocations.  */
+       irel->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
+       irel->r_addend = hi_irelfn->r_addend;
+
+       cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
+                                           cond_reloc);
+       cond_irelfn->r_addend = 0;
+       hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                         R_NDS32_NONE);
+      }
+    else
+      {
+       irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+       hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
+                                         cond_reloc);
+      }
 
-         if (foff >= -0x1000000 && foff < 0x1000000)
-           {
-             /* j     label */
-             if (!insn_opt && insn16_on && foff >= -0x100 && foff < 0x100
-                 && (seq_len & 0x2))
-               {
-                 /* 16-bit on, but not optimized for speed.  */
-                 reloc = R_NDS32_9_PCREL_RELA;
-                 insn16 = INSN_J8;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-               }
-             else
-               {
-                 reloc = R_NDS32_25_PCREL_RELA;
-                 insn = INSN_J;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 4;
-               }
-           }
-         else
-           {
-             continue;
-           }
+  if ((seq_len ^ *insn_len ) & 0x2)
+    {
+      insn16 = NDS32_NOP16;
+      bfd_putb16 (insn16, contents + irel->r_offset + *insn_len);
+      lo_irelfn->r_offset = *insn_len;
+      lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
+                                       R_NDS32_INSN16);
+      lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+      *insn_len += 2;
+    }
+  else
+    lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
+                                     R_NDS32_NONE);
+  return TRUE;
+}
 
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
+/* Relax LONGCALL4 relocation for nds32_elf_relax_section.  */
 
-         if (insn == 4)
-           {
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_INSN16);
-             irel->r_addend = 0;
-           }
-         else
-           irel->r_info =
-             ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+static bfd_boolean
+nds32_elf_relax_longcall4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL4.  Support for function cse.
+     sethi ta, hi20(symbol)    ; LONGCALL4/HI20
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jral  ta                  ; PTR_RES/EMPTY/INSN16  */
 
-         hi_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), reloc);
-         lo_irelfn->r_info =
-           ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-         if (i1_irelfn != irelend)
-           {
-             if (!insn_opt
-                 && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-               {
-                 /* The instruction pointed by R_NDS32_INSN16 is already
-                    turned into 16-bit instruction, so the total length
-                    of this sequence is decreased by 2.  */
-                 seq_len = seq_len - 2;
-                 i1_irelfn->r_addend = 0;
-               }
-             i1_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info), R_NDS32_NONE);
-           }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irel, *ptr_irel, *insn_irel, *em_irel, *call_irel;
+  Elf_Internal_Rela *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-         if ((seq_len & 0x2) && ((insn_len & 2) == 0))
-           {
-             insn16 = NDS32_NOP16;
-             bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                             R_NDS32_INSN16);
-             lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-             insn_len += 2;
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP2)
-       {
-         /* There are 3 variations for LONGJUMP2
-            case 2-4;  1st insn convertible, 16-bit on, optimize off or optimize for space
-            bnes38  rt, ra, $1 ; LONGJUMP2
-            j       label      ; 25_PCREL
-            $1:
-
-            case 4-4; 1st insn not convertible
-            bne  rt, ra, $1 ; LONGJUMP2
-            j    label      ; 25_PCREL
-            $1:
-
-            case 4-4; 1st insn convertible, 16-bit on, optimize for speed
-            bne  rt, ra, $1 ; LONGJUMP2/INSN16
-            j    label      ; 25_PCREL
-            $1: */
-
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
-         hi_off = (seq_len == 6) ? 2 : 4;
-         i2_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_25_PCREL_RELA,
-                                        laddr + hi_off);
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         for (i = 0; i < 2; i++)
-           {
-             cond_irelfn =
-               find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                            checked_types[i], laddr);
-             if (cond_irelfn != irelend)
-               break;
-           }
-         if (i2_irelfn == irelend)
-           {
-             (*_bfd_error_handler)
-              ("%B: warning: R_NDS32_LONGJUMP2 points to unrecognized reloc at 0x%lx.",
-               abfd, (long) irel->r_offset);
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
+  hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_HI20_RELA, laddr);
 
-             continue;
-           }
+  if (hi_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL4",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_INSN16, laddr);
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (i1_irelfn != irelend && !insn_opt
-             && (i1_irelfn->r_addend & R_NDS32_INSN16_CONVERT_FLAG))
-           {
-             /* The instruction pointed by R_NDS32_INSN16 is already turned
-                into 16-bit instruction, so the total length of this sequence
-                is decreased by 2.  */
-             seq_len = seq_len - 2;
-           }
+  /* This condition only happened when symbol is undefined.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         if (seq_len == 8)
-           {
-             /* possible cases
-                1. range is outside of +/-256 bytes
-                2. optimize is on with INSN16
-                3. optimize is off  */
-             insn_off = 4;
-             insn = bfd_getb32 (contents + laddr);
-             if (!insn16_on)
-               {
-                 /* 16-bit is off, can't convert to 16-bit.  */
-                 comp_insn16 = 0;
-               }
-             else if (N32_OP6 (insn) == N32_OP6_BR1)
-               {
-                 /* beqs     label    ; 15_PCREL (INSN16) */
-                 comp_insn = (insn ^ 0x4000) & 0xffffc000;
-                 i_mask = 0xffffc000;
-                 if (N32_IS_RT3 (insn) && N32_RA5 (insn) == REG_R5)
-                   {
-                     /* Insn can be contracted to 16-bit.  */
-                     comp_insn16 =
-                       (insn & 0x4000) ? INSN_BNES38 : INSN_BEQS38;
-                     comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                   }
-                 else
-                   {
-                     /* No conversion.  */
-                     comp_insn16 = 0;
-                   }
-               }
-             else
-               {
-                 comp_insn = (insn ^ 0x10000) & 0xffffc000;
-                 i_mask = 0xffff0000;
-                 if (N32_BR2_SUB (insn) == N32_BR2_BEQZ
-                     || N32_BR2_SUB (insn) == N32_BR2_BNEZ)
-                   {
-                     if (N32_IS_RT3 (insn))
-                       {
-                         /* Insn can be contracted to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNEZ38 : INSN_BEQZ38;
-                         comp_insn16 |= (N32_RT5 (insn) & 0x7) << 8;
-                       }
-                     else if (N32_RT5 (insn) == REG_R15)
-                       {
-                         /* Insn can be contracted to 16-bit.  */
-                         comp_insn16 =
-                           (insn & 0x10000) ? INSN_BNES38 : INSN_BEQS38;
-                       }
-                     else
-                       {
-                         /* No conversion.  */
-                         comp_insn16 = 0;
-                       }
-                   }
-                 else
-                   {
-                     /* No conversion.  */
-                     comp_insn16 = 0;
-                   }
-               }
-           }
-         else
-           {
-             /* First instruction is 16-bit.  */
-             insn_off = 2;
-             insn16 = bfd_getb16 (contents + laddr);
-             switch ((insn16 & 0xf000) >> 12)
-               {
-               case 0xc:
-                 /* beqz38 or bnez38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= ((insn16 & 0x0700) >> 8) << 20;
-                 i_mask = 0xffff0000;
-                 break;
+  /* Relax to: jal symbol; 25_PCREL */
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-               case 0xd:
-                 /* beqs38 or bnes38 */
-                 comp_insn = (insn16 & 0x0800) ? INSN_BNE : INSN_BEQ;
-                 comp_insn |= (((insn16 & 0x0700) >> 8) << 20)
-                   | (REG_R5 << 15);
-                 comp_insn16 = (insn16 ^ 0x0800) & 0xff00;
-                 insn = (insn16 & 0x0800) ? INSN_BEQ : INSN_BNE;
-                 insn |= (((insn16 & 0x0700) >> 8) << 20) | (REG_R5 << 15);
-                 i_mask = 0xffffc000;
-                 break;
+  ptr_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_PTR_RESOLVED, irel->r_addend);
+  em_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_EMPTY, irel->r_addend);
 
-               case 0xe:
-                 /* beqzS8 or bnezS8 */
-                 comp_insn = (insn16 & 0x0100) ? INSN_BNEZ : INSN_BEQZ;
-                 comp_insn |= REG_R15 << 20;
-                 comp_insn16 = (insn16 ^ 0x0100) & 0xff00;
-                 insn = (insn16 & 0x0100) ? INSN_BEQZ : INSN_BNEZ;
-                 insn |= REG_R15 << 20;
-                 i_mask = 0xffff0000;
-                 break;
+  if (ptr_irel == irelend || em_irel == irelend)
+    {
+      _bfd_error_handler (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;
 
-               default:
-                 comp_insn16 = 0;
-                 insn = 0;
-                 break;
-               }
-           }
+  /* Replace the long call with a jal.  */
+  em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info),
+                                 R_NDS32_25_PCREL_RELA);
+  ptr_irel->r_addend = 1;
 
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff =
-           calculate_offset (abfd, sec, i2_irelfn, isymbuf, symtab_hdr,
-                             &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
+  /* We don't resolve this here but resolve it in relocate_section.  */
+  insn = INSN_JAL;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-         if (comp_insn16
-             && foff >= -0x100 - insn_off && foff < 0x100 - insn_off)
-           {
-             if (insn_opt || seq_len == 8)
-               {
-                 /* Don't convert it to 16-bit now, keep this as relaxable for
-                    ``label reloc; INSN16''.  */
+  irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-                 /* Save comp_insn32 to buffer.  */
-                 insn = comp_insn;
-                 bfd_putb32 (insn, contents + irel->r_offset);
-                 insn_len = 4;
-                 reloc = (N32_OP6 (comp_insn) == N32_OP6_BR1) ?
-                   R_NDS32_15_PCREL_RELA : R_NDS32_17_PCREL_RELA;
+  /* If there is function cse, HI20 can not remove now.  */
+  call_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                          R_NDS32_LONGCALL4, laddr);
+  if (call_irel == irelend)
+    {
+      *insn_len = 0;
+      hi_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (hi_irel->r_info), R_NDS32_NONE);
+    }
 
-                 if (cond_irelfn != irelend)
-                   {
-                     cond_irelfn->r_info =
-                       ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
-                                     R_NDS32_INSN16);
-                     cond_irelfn->r_addend = 0;
-                   }
-               }
-             else
-               {
-                 /* Not optimize for speed; convert sequence to 16-bit.  */
+  insn_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                         R_NDS32_INSN16, irel->r_addend);
+  if (insn_irel != irelend)
+    insn_irel->r_info =
+      ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-                 /* Save comp_insn16 to buffer.  */
-                 insn16 = comp_insn16;
-                 bfd_putb16 (insn16, contents + irel->r_offset);
-                 insn_len = 2;
-                 reloc = R_NDS32_9_PCREL_RELA;
-               }
+  return TRUE;
+}
 
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info), reloc);
-             irel->r_addend = i2_irelfn->r_addend;
+/* Relax LONGCALL5 relocation for nds32_elf_relax_section.  */
 
-             i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                               R_NDS32_NONE);
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR1
-                  && (foff >= -0x4000 - insn_off && foff < 0x4000 - insn_off))
-           {
-             /* beqs     label    ; 15_PCREL */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                          R_NDS32_15_PCREL_RELA);
-             irel->r_addend = i2_irelfn->r_addend;
-             if (i1_irelfn != irelend)
-               i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                                 R_NDS32_NONE);
-
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 i2_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else if (N32_OP6 (insn) == N32_OP6_BR2 && foff >= -0x10000 && foff < 0x10000)
-           {
-             /* beqz     label ; 17_PCREL */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                          R_NDS32_17_PCREL_RELA);
-             irel->r_addend = i2_irelfn->r_addend;
-             if (i1_irelfn != irelend)
-               i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i1_irelfn->r_info),
-                                                 R_NDS32_NONE);
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (i2_irelfn->r_info),
-                                                   R_NDS32_INSN16);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 insn_len += 2;
-               }
-           }
-         else
-           continue;
+static bfd_boolean
+nds32_elf_relax_longcall5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL5.
+     bltz  rt, .L1     ; LONGCALL5/17_PCREL
+     jal   symbol      ; 25_PCREL
+     .L1:  */
 
-         if (cond_irelfn != irelend)
-           cond_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irelfn->r_info),
-                                               R_NDS32_NONE);
-
-
-         /* For simplicity of coding, we are going to modify the section
-            contents, the section relocs, and the BFD symbol table.  We
-            must tell the rest of the code not to free up this
-            information.  It would be possible to instead create a table
-            of changes which have to be made, as is done in coff-mips.c;
-            that would be more work, but would require less memory when
-            the linker is run.  */
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LONGJUMP3)
-       {
-         int reloc_off = 0, cond_removed = 0;
-         /* Get the reloc for the address from which the register is
-            being loaded.  This reloc will tell us which function is
-            actually being called.  */
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_15_PCREL_RELA, R_NDS32_9_PCREL_RELA };
-
-         /* There are 5 variations for LONGJUMP3
-            case 1: 2-4-4-2; 1st insn convertible, 16-bit on,
-                             optimize off or optimize for space
-            bnes38   rt, ra, $1            ; LONGJUMP3
-            sethi    ta, hi20(symbol)      ; HI20
-            ori      ta, ta, lo12(symbol)  ; LO12S0
-            jr5      ta                    ;
-            $1:                            ;
-
-            case 2: 2-4-4-2; 1st insn convertible, 16-bit on, optimize for speed
-            bnes38   rt, ra, $1           ; LONGJUMP3
-            sethi    ta, hi20(symbol)     ; HI20
-            ori      ta, ta, lo12(symbol) ; LO12S0
-            jr5      ta                   ;
-            $1:                           ; LABEL
-
-            case 3: 4-4-4-2; 1st insn not convertible, 16-bit on,
-                             optimize off or optimize for space
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr5   ta                   ;
-            $1:                        ;
-
-            case 4: 4-4-4-4; 1st insn don't care, 16-bit off, optimize don't care
-            16-bit off if no INSN16
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr    ta                   ;
-            $1:                        ;
-
-            case 5: 4-4-4-4; 1st insn not convertible, 16-bit on, optimize for speed
-            16-bit off if no INSN16
-            bne   rt, ra, $1           ; LONGJUMP3
-            sethi ta, hi20(symbol)     ; HI20
-            ori   ta, ta, lo12(symbol) ; LO12S0
-            jr    ta                   ; INSN16
-            $1:                        ; LABEL
-          */
-
-         if (convertible)
-           {
-             hi_off = 2;
-             if (insn_opt)
-               reloc_off = 2;
-           }
-         else
-           {
-             hi_off = 4;
-           }
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *cond_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-         hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_HI20_RELA,
-                                                  laddr + hi_off);
-         lo_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                  R_NDS32_LO12S0_ORI_RELA,
-                                                  laddr + hi_off + 4);
-         i2_offset = 8;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+
+  /* 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;
+    }
 
-         if (hi_irelfn == irelend || lo_irelfn == irelend)
-           {
-             hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                                      R_NDS32_20_RELA,
-                                                      laddr + hi_off);
-             i2_offset = 4;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             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;
-               }
-           }
+  if (foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         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;
+  /* Relax to  bgezal   rt, label ; 17_PCREL
+     or                bltzal   rt, label ; 17_PCREL */
 
-         /* 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;
+  /* Convert to complimentary conditional call.  */
+  insn = CONVERT_CONDITION_CALL (insn);
 
-               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;
+  /* For simplicity of coding, we are going to modify the section
+     contents, the section relocs, and the BFD symbol table.  We
+     must tell the rest of the code not to free up this
+     information.  It would be possible to instead create a table
+     of changes which have to be made, as is done in coff-mips.c;
+     that would be more work, but would require less memory when
+     the linker is run.  */
 
-               case 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;
-                   }
-               }
-           }
+  /* Modify relocation and contents.  */
+  cond_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_17_PCREL_RELA);
 
-         if (foff < -0x1000000 && foff >= 0x1000000)
-           continue;
+  /* Replace the long call with a bgezal.  */
+  bfd_putb32 (insn, contents + cond_irel->r_offset);
+  *insn_len = 0;
 
-         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;
-               }
-           }
+  /* Clean unnessary relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->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.  */
+  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);
 
-         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);
-               }
+  return TRUE;
+}
 
-             /* Change relocs.  */
-             for (i = 0; i < 2; i++)
-               {
-                 cond_irelfn =
-                   find_relocs_at_address_addr (irel, internal_relocs,
-                                                irelend, checked_types[i],
-                                                laddr);
+/* Relax LONGCALL6 relocation for nds32_elf_relax_section.  */
 
-                 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'.  */
+static bfd_boolean
+nds32_elf_relax_longcall6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGCALL6.
+     bltz  rt,   .L1                   ; LONGCALL6/17_PCREL
+     sethi ta,   hi20(symbol)          ; HI20/PTR
+     ori   ta, ta,  lo12(symbol)       ; LO12S0_ORI/PTR
+     jral  ta                          ; PTR_RES/EMPTY/INSN16
+     .L1  */
+
+  bfd_vma laddr;
+  uint32_t insn;
+  Elf_Internal_Rela *em_irel, *cond_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = R_NDS32_15_PCREL_RELA;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = 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'.  */
+  /* 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);
 
-             /* Save comp_insn to buffer.  */
-             insn = comp_insn;
-             bfd_putb32 (insn, contents + irel->r_offset);
-             insn_len = 4;
-             reloc = R_NDS32_17_PCREL_RELA;
+  if (em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGCALL6",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-             /* Change relocs.  */
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (seq_len & 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                 R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 if (hi_off == 2)
-                   hi_irelfn->r_offset += 2;
-                 insn_len += 2;
-               }
-             cond_removed = 1;
-           }
-         else if (foff >= -0x1000000 - reloc_off
-                  && foff < 0x1000000 - reloc_off)
-           {
-             /* Relax to one of the following 3 variations
-
-                case 2-4; 1st insn convertible, 16-bit on, optimize off or optimize for space
-                bnes38  rt, $1 ; LONGJUMP2
-                j       label  ; 25_PCREL
-                $1
-
-                case 4-4; 1st insn not convertible, others don't care
-                bne   rt, ra, $1 ; LONGJUMP2
-                j     label      ; 25_PCREL
-                $1
-
-                case 4-4; 1st insn convertible, 16-bit on, optimize for speed
-                bne   rt, ra, $1 ; LONGJUMP2/INSN16
-                j     label      ; 25_PCREL
-                $1
-              */
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, em_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             /* Offset for first instruction.  */
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-             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;
-               }
+  /* Check these is enough space to insert jal in R_NDS32_EMPTY.  */
+  insn = bfd_getb32 (contents + irel->r_addend);
+  if (insn & 0x80000000)
+    return FALSE;
 
-             /* Use j label as second instruction.  */
-             insn = INSN_J;
-             bfd_putb32 (insn, contents + irel->r_offset);
-
-             /* Change relocs.  */
-             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_LONGJUMP2);
-             hi_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                               R_NDS32_25_PCREL_RELA);
-             lo_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info), R_NDS32_NONE);
-             if (((seq_len ^ insn_len) & 0x2) != 0x2)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + insn_len);
-                 lo_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (lo_irelfn->r_info),
-                                                   R_NDS32_INSN16);
-                 lo_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 lo_irelfn->r_offset = hi_irelfn->r_offset + 4;
-                 insn_len += 2;
-               }
-           }
+  insn = bfd_getb32 (contents + laddr);
+  if (foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* Relax to  bgezal   rt, label ; 17_PCREL
+        or        bltzal   rt, label ; 17_PCREL */
 
-         if (cond_removed)
-           {
-             for (i = 0; i < 2; i++)
-               {
-                 cond_irelfn =
-                   find_relocs_at_address_addr (irel, internal_relocs,
-                                                irelend, checked_types[i],
-                                                laddr);
+      /* Convert to complimentary conditional call.  */
+      *insn_len = 0;
+      insn = CONVERT_CONDITION_CALL (insn);
+      bfd_putb32 (insn, contents + em_irel->r_offset);
 
-                 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)
+      em_irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_17_PCREL_RELA);
+
+      /* Set resolved relocation.  */
+      cond_irel =
+       find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                    R_NDS32_PTR_RESOLVED, irel->r_addend);
+      if (cond_irel == irelend)
        {
-         int eliminate_sethi = 0, ls_range_type;
-         enum elf_nds32_reloc_type checked_types[] =
-           { R_NDS32_HI20_RELA, R_NDS32_GOT_HI20,
-             R_NDS32_GOTPC_HI20, R_NDS32_GOTOFF_HI20,
-             R_NDS32_PLTREL_HI20, R_NDS32_PLT_GOTREL_HI20
-           };
+         _bfd_error_handler (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;
 
-         insn_len = seq_len;
+      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;
+}
 
-         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;
-           }
+/* Relax LONGJUMP4 relocation for nds32_elf_relax_section.  */
 
-         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;
-           }
+static bfd_boolean
+nds32_elf_relax_longjump4 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* The pattern for LONGJUMP4.
+     sethi ta, hi20(symbol)    ; LONGJUMP4/HI20
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jr    ta                  ; PTR_RES/INSN16/EMPTY  */
+
+  bfd_vma laddr;
+  int seq_len; /* Original length of instruction sequence.  */
+  uint32_t insn;
+  Elf_Internal_Rela *hi_irel, *ptr_irel, *em_irel, *call_irel, *irelend;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
 
-         ls_range_type = (irel->r_addend >> 8) & 0x3f;
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
-         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);
+  /* 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 ((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;
-                       }
-                   }
-               }
+  hi_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        R_NDS32_HI20_RELA, laddr);
 
-             if (!load_store_relax)
-               continue;
+  if (hi_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP4",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
+    }
 
-             if (((insn >> 20) & 0x1f) == REG_GP)
-               break;
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, hi_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             if (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;
+  if (pic_ext_target || foff == 0 || foff >= CONSERVATIVE_24BIT_S1
+      || foff < -CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-           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;
+  /* 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);
 
-           case R_NDS32_PLT_GOTREL_HI20:
-             access_addr =
-               calculate_plt_memory_address (abfd, link_info, isymbuf,
-                                             hi_irelfn, symtab_hdr);
+  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 ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+  em_irel->r_info =
+    ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), R_NDS32_25_PCREL_RELA);
+  ptr_irel->r_addend = 1;
 
-           case R_NDS32_GOTOFF_HI20:
-             access_addr =
-               calculate_memory_address (abfd, hi_irelfn, isymbuf,
-                                         symtab_hdr);
+  /* Write instruction.  */
+  insn = INSN_J;
+  bfd_putb32 (insn, contents + em_irel->r_offset);
 
-             if ((bfd_signed_vma) (access_addr - local_sda) < 0x7f000
-                 && (bfd_signed_vma) (access_addr - local_sda) >= -0x7f000)
-               eliminate_sethi = 1;
-             break;
+  /* Clear relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
 
-           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 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);
+    }
 
-             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;
+  return TRUE;
+}
 
-           default:
-             continue;
-           }
-         if (eliminate_sethi == 1
-             || (local_sda <= access_addr && (access_addr - local_sda) < range_h)
-             || (local_sda > access_addr && (local_sda - access_addr) <= range_l))
-           {
-             hi_irelfn->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info), R_NDS32_NONE);
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-             insn_len = 0;
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA)
-       {
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < 1022 && foff >= 0)
-           {
-             reloc = R_NDS32_10IFCU_PCREL_RELA;
-             insn16 = INSN_IFCALL9;
-             bfd_putb16 (insn16, contents + irel->r_offset);
-             insn_len = 2;
-             irel->r_info =
-               ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_10IFCU_PCREL_RELA);
-             *again = TRUE;
+/* Relax LONGJUMP5 relocation for nds32_elf_relax_section.  */
 
-             i2_irelfn = find_relocs_at_address (irel, internal_relocs,
-                                                 irelend, R_NDS32_INSN16);
-             if (i2_irelfn < irelend)
-               {
-                 insn16 = NDS32_NOP16;
-                 bfd_putb16 (insn16, contents + irel->r_offset + 2);
-                 i2_irelfn->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
-                 i2_irelfn->r_offset += 2;
-                 insn_len += 2;
-               }
-             else
-               {
-                 ((*_bfd_error_handler)
-                  ("%s: 0x%lx: warning: R_NDS32_17IFC points to unrecognized reloc at 0x%lx",
-                   bfd_get_filename (abfd), (long) irel->r_offset));
-               }
-           }
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S0_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S1_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
-              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_RELA)
-       {
-         nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                   &local_sda, FALSE);
+static bfd_boolean
+nds32_elf_relax_longjump5 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 2 variations for LONGJUMP5
+     case 2-4;  1st insn convertible, 16-bit on.
+     bnes38  rt, ra, .L1       ; LONGJUMP5/9_PCREL/INSN16
+     j       label             ; 25_PCREL/INSN16
+     $1:
+
+     case 4-4; 1st insn not convertible
+     bne  rt, ra, .L1  ; LONGJUMP5/15_PCREL/INSN16
+     j    label                ; 25_PCREL/INSN16
+     .L1:  */
+
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel,  *irelend;
+  int pic_ext_target = 0;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-         insn = bfd_getb32 (contents + laddr);
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA,
+      R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 };
 
-         if (!is_sda_access_insn (insn)
-             && N32_OP6 (insn) != N32_OP6_ORI)
-           continue;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         access_addr =
-           calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         insn_len = seq_len = 4;
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-         /* 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;
-               }
-           }
+  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 (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;
-               }
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-             /* 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);
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_16BIT_S1
+      || foff >= CONSERVATIVE_16BIT_S1)
+    return FALSE;
 
-         insn = bfd_getb32 (contents + laddr);
+  /* Get the all corresponding instructions.  */
+  insn = bfd_getb32 (contents + laddr);
+  /* Check instruction size.  */
+  if (insn & 0x80000000)
+    {
+      *seq_len = 0;
+      insn16 = insn >> 16;
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
+  else
+    nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
 
-         if (N32_OP6 (insn) != N32_OP6_ORI)
-           continue;
+  if (N32_OP6 (re_insn) == N32_OP6_BR1
+      && (foff >= -CONSERVATIVE_14BIT_S1 && foff < CONSERVATIVE_14BIT_S1))
+    {
+      /* beqs label ; 15_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_15_PCREL_RELA;
+    }
+  else if (N32_OP6 (re_insn) == N32_OP6_BR2
+          && foff >= -CONSERVATIVE_16BIT_S1 && foff < CONSERVATIVE_16BIT_S1)
+    {
+      /* beqz label ; 17_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_17_PCREL_RELA;
+    }
+  else if ( N32_OP6 (re_insn) == N32_OP6_BR3
+          && foff >= -CONSERVATIVE_8BIT_S1 && foff < CONSERVATIVE_8BIT_S1)
+    {
+      /* beqc label ; 9_PCREL.  */
+      bfd_putb32 (re_insn, contents + cond_irel->r_offset);
+      reloc = R_NDS32_WORD_9_PCREL_RELA;
+    }
+  else
+    return FALSE;
 
-         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;
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), reloc);
 
-         if ((foff < 0x7f000) && (foff >= -0x7f000))
+  /* Clean relocations.  */
+  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
+  for (i = 0; i < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+    {
+      cond_irel = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (cond_irel != irelend)
+       {
+         if (*seq_len == 0
+             && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16))
            {
-             /* 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);
+             /* 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_PTR)
-       {
-         i1_irelfn =
-           find_relocs_at_address_addr (irel, internal_relocs, irelend,
-                                        R_NDS32_PTR_RESOLVED, irel->r_addend);
+    }
+  *insn_len = 0;
 
-         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;
-           }
+  return TRUE;
+}
 
-         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);
+/* Relax LONGJUMP6 relocation for nds32_elf_relax_section.  */
 
-             i1_irelfn =
-               find_relocs_at_address (irel, internal_relocs, irelend,
-                                       R_NDS32_PTR_COUNT);
+static bfd_boolean
+nds32_elf_relax_longjump6 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 5 variations for LONGJUMP6
+     case : 2-4-4-4; 1st insn convertible, 16-bit on.
+     bnes38   rt, ra, .L1              ; LONGJUMP6/15_PCREL/INSN16
+     sethi    ta, hi20(symbol)         ; HI20/PTR
+     ori      ta, ta, lo12(symbol)     ; LO12S0_ORI/PTR
+     jr       ta                       ; PTR_RES/INSN16/EMPTY
+     .L1:
+
+     case : 4-4-4-4; 1st insn not convertible, 16-bit on.
+     bne   rt, ra, .L1         ; LONGJUMP6/15_PCREL/INSN16
+     sethi ta, hi20(symbol)    ; HI20/PTR
+     ori   ta, ta, lo12(symbol)        ; LO12S0_ORI/PTR
+     jr    ta                  ; PTR_RES/INSN16/EMPTY
+     .L1:  */
+
+  enum elf_nds32_reloc_type checked_types[] =
+    { R_NDS32_17_PCREL_RELA, R_NDS32_15_PCREL_RELA,
+      R_NDS32_9_PCREL_RELA, R_NDS32_INSN16 };
+
+  int reloc_off = 0, cond_removed = 0;
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel, *em_irel, *irelend, *insn_irel;
+  int pic_ext_target = 0;
+  unsigned int i;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16, re_insn16 = 0;
+  unsigned long reloc;
 
-             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;
-               }
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-             if (--i1_irelfn->r_addend > 0)
-               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 the PTR_COUNT is already 0, remove current instruction.  */
-             seq_len = nds32_elf_insn_size (abfd, contents, irel->r_offset);
-             insn_len = 0;
-           }
-         else
-           continue;
-       }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOT_SUFF)
-       {
-         /* FIXME: It's a little trouble to turn JRAL5 to JAL since
-            we need additional space.  It might be help if we could
-            borrow some space from instructions to be eliminated
-            such as sethi, ori, add.  */
+  if (em_irel == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LONGJUMP6",
+                         (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, em_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF))
-           continue;
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_24BIT_S1
+      || foff >= CONSERVATIVE_24BIT_S1)
+    return FALSE;
 
-         seq_len = insn_len = 4;
-         i1_irelfn =
-           find_relocs_at_address (irel, internal_relocs, irelend,
-                                   R_NDS32_PTR_RESOLVED);
-
-         /* FIXIT 090606
-            The boundary should be reduced since the .plt section hasn't
-            been created and the address of specific entry is still unknown
-            Maybe the range between the function call and the begin of the
-            .text section can be used to decide if the .plt is in the range
-            of function call.  */
-
-         if (N32_OP6 (insn) == N32_OP6_ALU1
-             && N32_SUB5 (insn) == N32_ALU1_ADD_SLLI
-             && N32_SH5 (insn) == 0)
-           {
-             /* Get the value of the symbol referred to by the reloc.  */
-             nds32_elf_final_sda_base (sec->output_section->owner, link_info,
-                                       &local_sda, FALSE);
-             foff = (bfd_signed_vma) (calculate_plt_memory_address
-                                      (abfd, link_info, isymbuf, irel,
-                                       symtab_hdr) - local_sda);
-             /* This condition only happened when symbol is undefined.  */
-             if (foff == 0)
-               continue;
+  insn = bfd_getb32 (contents + laddr);
+  /* Check instruction size.  */
+  if (insn & 0x80000000)
+    {
+      *seq_len = 0;
+      insn16 = insn >> 16;
+      nds32_elf_convert_branch (insn16, 0, &re_insn16, &re_insn);
+    }
+  else
+    nds32_elf_convert_branch (0, insn, &re_insn16, &re_insn);
 
-             if (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;
+  /* 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.  */
 
-         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_GOT_SUFF)
-       {
+  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
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           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 (nds32_elf_check_dup_relocs
-               (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF))
-           continue;
+        case 4-4; 1st insn not convertible
+        bne  rt, ra, .L1       ; LONGJUMP5/15_PCREL/INSN16
+        j    label             ; 25_PCREL/INSN16
+        .L1:  */
 
-         seq_len = insn_len = 4;
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PTR_RESOLVED);
+      /* 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;
 
-         foff = calculate_got_memory_address (abfd, link_info, irel,
-                                              symtab_hdr) - local_sda;
+  /* Set all relocations.  */
+  em_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (em_irel->r_info), reloc);
 
-         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;
-
-         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_PTR_RESOLVED, em_irel->r_offset);
+  cond_irel->r_addend = 1;
 
-         insn = bfd_getb32 (contents + laddr);
-         if (insn & 0x80000000)
-           continue;
-
-         if (nds32_elf_check_dup_relocs
-             (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF))
-           continue;
-
-         seq_len = insn_len = 4;
-
-         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;
+  /* 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 (foff >= 0x3f000 || foff < -0x3f000)
-           continue;
+  if (cond_removed == 1)
+    {
+      *insn_len = 0;
 
-         /* 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;
-           }
+      /* 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 < sizeof (checked_types) / sizeof (checked_types[0]); i++)
+       {
+         cond_irel =
+           find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                        checked_types[i], laddr);
+         if (cond_irel != irelend)
            {
-             i1_irelfn->r_addend |= 1;
-             *again = TRUE;
+             if (*seq_len == 0
+                 && (ELF32_R_TYPE (cond_irel->r_info) == R_NDS32_INSN16))
+               {
+                 /* If the branch instruction is 2 byte, it cannot remove
+                    directly.  Only convert it to nop16 and remove it after
+                    checking alignment issue.  */
+                 insn16 = NDS32_NOP16;
+                 bfd_putb16 (insn16, contents + laddr);
+                 cond_irel->r_addend = R_NDS32_INSN16_CONVERT_FLAG;
+               }
+             else
+               cond_irel->r_info =
+                 ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info), R_NDS32_NONE);
            }
-         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;
-
-         /* Get the value of the symbol referred to by the reloc.  */
-         foff = calculate_offset (abfd, sec, irel, isymbuf, symtab_hdr,
-                                  &pic_ext_target);
+       }
+    }
+  else
+    {
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                  R_NDS32_LONGJUMP5);
+    }
 
-         /* This condition only happened when symbol is undefined.  */
-         if (pic_ext_target || foff == 0)
-           continue;
-         if (foff < -0x1000000 || foff >= 0x1000000)
-           continue;
+  return TRUE;
+}
 
-         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;
+/* Relax LONGJUMP7 relocation for nds32_elf_relax_section.  */
 
-         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);
+static bfd_boolean
+nds32_elf_relax_longjump7 (bfd *abfd, asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          int *seq_len, bfd_byte *contents,
+                          Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
+{
+  /* There are 2 variations for LONGJUMP5
+     case 2-4;  1st insn convertible, 16-bit on.
+     movi55  ta, imm11         ; LONGJUMP7/INSN16
+     beq     rt, ta, label     ; 15_PCREL
+
+     case 4-4; 1st insn not convertible
+     movi55  ta, imm11         ; LONGJUMP7/INSN16
+     beq     rt, ta, label     ; 15_PCREL  */
+
+  bfd_vma laddr;
+  Elf_Internal_Rela *cond_irel,  *irelend, *insn_irel;
+  int pic_ext_target = 0;
+  bfd_signed_vma foff;
+  uint32_t insn, re_insn = 0;
+  uint16_t insn16;
+  uint32_t imm11;
 
-         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)
-       {
-         i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
-                                             R_NDS32_PLT_GOTREL_HI20);
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
 
-         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;
-           }
+  /* Get the reloc for the address from which the register is
+     being loaded.  This reloc will tell us which function is
+     actually being called.  */
 
-         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);
+  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;
+    }
 
-         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 */
+  /* Get the value of the symbol referred to by the reloc.  */
+  foff = calculate_offset (abfd, sec, cond_irel, isymbuf, symtab_hdr,
+                          &pic_ext_target);
 
-                 /* 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);
+  if (pic_ext_target || foff == 0 || foff < -CONSERVATIVE_8BIT_S1
+      || foff >= CONSERVATIVE_8BIT_S1)
+    return FALSE;
 
-                 i1_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                                   R_NDS32_PLT_GOTREL_LO15);
-                 i1_irelfn->r_addend = hi_irelfn->r_addend;
+  /* Get the 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);
+    }
 
-                 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;
+  /* 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);
 
-           }
-         else
-           {
-             /* jal Sym INSN16/25_PLTREL */
-             for (i1_irelfn = irel;
-                  i1_irelfn->r_offset < irel->r_offset + 12; i1_irelfn++)
-               ;
-
-             i2_irelfn = i1_irelfn - 1;
-             i2_irelfn->r_offset = i1_irelfn->r_offset;
-             i2_irelfn->r_info = ELF32_R_INFO (ELF32_R_SYM (hi_irelfn->r_info),
-                                               R_NDS32_25_PLTREL);
-             i2_irelfn->r_addend = hi_irelfn->r_addend;
-             insn = INSN_JAL;
-             bfd_putb32 (insn, contents + irel->r_offset + 12);
-             seq_len = 12;
-           }
+  bfd_putb32 (re_insn, contents + cond_irel->r_offset);
 
-         insn_len = 0;
-       }
-      else
-       continue;
+  /* Set all relocations.  */
+  cond_irel->r_info = ELF32_R_INFO (ELF32_R_SYM (cond_irel->r_info),
+                                   R_NDS32_WORD_9_PCREL_RELA);
 
-      if (seq_len - insn_len > 0)
+  /* 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 (!insert_nds32_elf_blank
-             (&relax_blank_list, irel->r_offset + insn_len,
-              seq_len - insn_len))
-           goto error_return;
-         *again = TRUE;
+         /* 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;
 
-  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.  */
 
-  if (*again == FALSE)
-    {
-      /* This code block is used to adjust 4-byte alignment by relax a pair
-        of instruction a time.
+static bfd_boolean
+nds32_elf_relax_loadstore (struct bfd_link_info *link_info, bfd *abfd,
+                          asection *sec, Elf_Internal_Rela *irel,
+                          Elf_Internal_Rela *internal_relocs, int *insn_len,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr, int load_store_relax)
+{
+  int eliminate_sethi = 0, range_type;
+  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.  */
+  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
+    };
 
-        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.
+  irelend = internal_relocs + sec->reloc_count;
+  seq_len = GET_SEQ_LEN (irel->r_addend);
+  laddr = irel->r_offset;
+  *insn_len = seq_len;
 
-        FIXME: It seems currently implementation only support 4-byte aligment.
-        We should handle any-aligment.  */
+  /* Get the high part relocation.  */
+  for (i = 0; i < ARRAY_SIZE (checked_types); i++)
+    {
+      hi_irelfn = find_relocs_at_address_addr (irel, internal_relocs, irelend,
+                                              checked_types[i], laddr);
+      if (hi_irelfn != irelend)
+       break;
+    }
 
-      Elf_Internal_Rela *insn_rel = NULL;
-      Elf_Internal_Rela *label_rel = NULL;
-      Elf_Internal_Rela *tmp_rel, tmp2_rel, *tmp3_rel = NULL;
+  if (hi_irelfn == irelend)
+    {
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_LOADSTORE",
+                         (uint64_t) irel->r_offset);
+       return FALSE;
+    }
 
-      /* 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);
+  range_type = GET_LOADSTORE_RANGE (irel->r_addend);
+  nds32_elf_final_sda_base (sec->output_section->owner,
+                           link_info, &local_sda, FALSE);
 
-      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);
 
-      /* 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 (range_type == NDS32_LOADSTORE_IMM)
        {
-         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;
+         struct elf_link_hash_entry *h = NULL;
+         int indx;
 
-         if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset
-             && insn_rel < label_rel)
+         if (ELF32_R_SYM (hi_irelfn->r_info) >= symtab_hdr->sh_info)
            {
-             /* Swap the two reloc if the R_NDS32_INSN16 is before R_NDS32_LABEL.  */
-             memcpy (&tmp2_rel, insn_rel, sizeof (Elf_Internal_Rela));
-             memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela));
-             memcpy (label_rel, &tmp2_rel, sizeof (Elf_Internal_Rela));
+             indx = ELF32_R_SYM (hi_irelfn->r_info) - symtab_hdr->sh_info;
+             h = elf_sym_hashes (abfd)[indx];
            }
-       }
-      label_rel = NULL;
-      insn_rel = NULL;
 
-      /* If there were a sequence of R_NDS32_LABEL end up with .align 2 or higher,
-        remove other R_NDS32_LABEL with lower alignment.
-        If an R_NDS32_INSN16 in between R_NDS32_LABELs must be converted,
-        then the R_NDS32_LABEL sequence is broke.  */
-      for (tmp_rel = internal_relocs; tmp_rel < irelend; tmp_rel++)
-       {
-         if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_LABEL)
-           {
-             if (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)
+         if ((access_addr < CONSERVATIVE_20BIT)
+             && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0)))
            {
-             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;
-               }
+             eliminate_sethi = 1;
+             break;
            }
+
+         /* This is avoid to relax symbol address which is fixed
+            relocations.  Ex: _stack.  */
+         if (h && bfd_is_abs_section (h->root.u.def.section))
+           return FALSE;
        }
-      label_rel = NULL;
-      insn_rel = NULL;
 
-      /* Optimized for speed and nothing has not been relaxed.
-        It's time to align labels.
-        We may convert a 16-bit instruction right before a label to
-        32-bit, in order to align the label if necessary
-        all reloc entries has been sorted by r_offset.  */
-      for (irel = internal_relocs; irel < irelend; irel++)
-       {
-         if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16
-             && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL)
-           continue;
+      if (!load_store_relax)
+       return FALSE;
 
-         /* Search for INSN16 reloc.  */
-         if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16)
-           {
-             if (label_rel)
-               {
-                 /* Previous LABEL reloc exists.  Try to resolve it.  */
-                 if (label_rel->r_offset == irel->r_offset)
-                   {
-                     /* LABEL and INSN are at the same addr.  */
-                     if ((irel->r_offset
-                          - get_nds32_elf_blank_total (&relax_blank_list,
-                                                       irel->r_offset,
-                                                       1)) & 0x02)
-                       {
-                         if (irel->r_addend > 1)
-                           {
-                             /* Force to relax.  */
-                             irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                                          R_NDS32_NONE);
-                             if (is_convert_32_to_16
-                                 (abfd, sec, irel, internal_relocs, irelend,
-                                  &insn16))
-                               {
-                                 nds32_elf_write_16 (abfd, contents, irel,
-                                                     internal_relocs, irelend,
-                                                     insn16);
-
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list, irel->r_offset + 2,
-                                      2))
-                                   goto error_return;
-                               }
-                             else if (is_16bit_NOP (abfd, sec, irel))
-                               {
-                                 if (!insert_nds32_elf_blank_recalc_total
-                                     (&relax_blank_list, irel->r_offset, 2))
-                                   goto error_return;
-                               }
-                           }
-                         else
-                           {
-                             if (is_convert_32_to_16
-                                 (abfd, sec, irel, internal_relocs, irelend,
-                                  &insn16)
-                                 || is_16bit_NOP (abfd, sec, irel))
-                               insn_rel = irel;
-                           }
-                         label_rel = NULL;
-                         continue;
-                       }
-                     else
-                       {
-                         /* Already aligned, reset LABEL and keep INSN16.  */
-                       }
-                   }
-                 else
-                   {
-                     /* No INSN16 to relax, we don't want to insert 16-bit.  */
-                     /* Nop here, just signal the algorithm is wrong.  */
-                   }
-                 label_rel = NULL;
-               }
-             /* A new INSN16 found, resize the old one.  */
-             else if (insn_rel)
-               {
-                 if (!is_convert_32_to_16
-                     (abfd, sec, irel, internal_relocs, irelend,
-                      &insn16)
-                     && !is_16bit_NOP (abfd, sec, irel))
-                   {
-                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                                  R_NDS32_NONE);
-                     continue;
-                   }
-                 /* Previous INSN16 reloc exists, reduce its size to 16-bit.  */
-                 if (is_convert_32_to_16
-                     (abfd, sec, insn_rel, internal_relocs, irelend,
-                      &insn16))
-                   {
-                     nds32_elf_write_16 (abfd, contents, insn_rel,
-                                         internal_relocs, irelend, insn16);
+      /* Case for set gp register.  */
+      if (N32_RT5 (insn) == REG_GP)
+       break;
 
-                     if (!insert_nds32_elf_blank_recalc_total
-                         (&relax_blank_list, insn_rel->r_offset + 2, 2))
-                       goto error_return;
-                   }
-                 else if (is_16bit_NOP (abfd, sec, insn_rel))
-                   {
-                     if (!insert_nds32_elf_blank_recalc_total
-                         (&relax_blank_list, insn_rel->r_offset, 2))
-                       goto error_return;
-                   }
-                 insn_rel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                 R_NDS32_NONE);
-                 insn_rel = NULL;
-               }
+      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];
+       }
+      else
+       {
+         range_l = sdata_range[1][0];
+         range_h = sdata_range[1][1];
+       }
+      break;
 
-             if (is_convert_32_to_16
-                 (abfd, sec, irel, internal_relocs, irelend, &insn16)
-                 || is_16bit_NOP (abfd, sec, irel))
-               {
-                 insn_rel = irel;
-               }
-             /* Save the new one for later use.  */
-           }
-         /* Search for label.  */
-         else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL)
-           {
-             /* Label on 16-bit instruction, just reset this reloc.  */
-             insn16 = bfd_getb16 (contents + irel->r_offset);
-             if ((irel->r_addend & 0x1f) < 2 && (insn16 & 0x8000))
-               {
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 continue;
-               }
+    case R_NDS32_GOT_HI20:
+      access_addr =
+       calculate_got_memory_address (abfd, link_info, hi_irelfn, symtab_hdr);
 
-             if (!optimize && (irel->r_addend & 0x1f) < 2)
-               {
-                 irel->r_info =
-                   ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_NONE);
-                 continue;
-               }
+      /* If this symbol is not in .got, the return value will be -1.
+        Since the gp value is set to SDA_BASE but not GLOBAL_OFFSET_TABLE,
+        a negative offset is allowed.  */
+      if ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
 
-             /* Try to align this label.  */
-             if (insn_rel)
-               {
-                 int force_relax = 0;
+    case R_NDS32_PLT_GOTREL_HI20:
+      access_addr = calculate_plt_memory_address (abfd, link_info, isymbuf,
+                                                 hi_irelfn, symtab_hdr);
 
-                 /* 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 ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
 
-                     /* 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;
-                       }
+    case R_NDS32_GOTOFF_HI20:
+      access_addr =
+       calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr);
 
-                     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 ((bfd_signed_vma) (access_addr - local_sda) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr - local_sda) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
 
-                 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
-                   {
-                     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;
-                               }
-                           }
-                       }
+    case R_NDS32_GOTPC_HI20:
+      /* The access_addr must consider r_addend of hi_irel.  */
+      access_addr = sec->output_section->vma + sec->output_offset
+       + irel->r_offset + hi_irelfn->r_addend;
 
-                     if (force_relax)
-                       {
-                         label_rel = irel;
-                       }
+      if ((bfd_signed_vma) (local_sda - access_addr) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (local_sda - access_addr) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
 
-                     /* INSN16 reloc is used.  */
-                     insn_rel = NULL;
-                   }
-               }
-           }
-       }
+    case R_NDS32_TLS_LE_HI20:
+      access_addr =
+       calculate_memory_address (abfd, hi_irelfn, isymbuf, symtab_hdr);
+      BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+      access_addr -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+      if ((range_type == NDS32_LOADSTORE_IMM)
+         && (bfd_signed_vma) (access_addr) < CONSERVATIVE_20BIT
+         && (bfd_signed_vma) (access_addr) >= -CONSERVATIVE_20BIT)
+       eliminate_sethi = 1;
+      break;
 
-      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 (is_convert_32_to_16
-                 (abfd, sec, insn_rel, internal_relocs, irelend,
-                  &insn16))
-               {
-                 nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs,
-                                     irelend, insn16);
-                 if (!insert_nds32_elf_blank_recalc_total
-                     (&relax_blank_list, insn_rel->r_offset + 2, 2))
-                   goto error_return;
-                 insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                                  R_NDS32_NONE);
-               }
-             else if (is_16bit_NOP (abfd, sec, insn_rel))
-               {
-                 if (!insert_nds32_elf_blank_recalc_total
-                     (&relax_blank_list, insn_rel->r_offset, 2))
-                   goto error_return;
-                 insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
-                                                  R_NDS32_NONE);
-               }
-           }
-         insn_rel = NULL;
-       }
+    default:
+      return FALSE;
     }
-    /* 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)
+  /* 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))
     {
-      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
-      relax_blank_list = NULL;
+      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;
+}
 
-  if (*again == FALSE)
-    {
-      /* Closing the section, so we don't relax it anymore.  */
-      bfd_vma sec_size_align;
-      Elf_Internal_Rela *tmp_rel;
+/* Relax LO12 relocation for nds32_elf_relax_section.  */
 
-      /* 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)
-       {
-         insn16 = NDS32_NOP16;
-         bfd_putb16 (insn16, contents + sec->size);
-         sec->size += 2;
-       }
+static void
+nds32_elf_relax_lo12 (struct bfd_link_info *link_info, bfd *abfd,
+                     asection *sec, Elf_Internal_Rela *irel,
+                     Elf_Internal_Rela *internal_relocs, bfd_byte *contents,
+                     Elf_Internal_Sym *isymbuf, Elf_Internal_Shdr *symtab_hdr)
+{
+  uint32_t insn;
+  bfd_vma local_sda, laddr;
+  unsigned long reloc;
+  bfd_vma access_addr;
+  bfd_vma range_l = 0, range_h = 0;    /* Upper/lower bound.  */
+  Elf_Internal_Rela *irelfn = NULL, *irelend;
+  struct elf_link_hash_entry *h = NULL;
+  int indx;
+
+  /* For SDA base relative relaxation.  */
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
 
-      while (sec_size_align != sec->size)
-       {
-         insn = NDS32_NOP32;
-         bfd_putb32 (insn, contents + sec->size);
-         sec->size += 4;
-       }
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
 
-      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 (!is_sda_access_insn (insn) && N32_OP6 (insn) != N32_OP6_ORI)
+    return;
 
-      clean_nds32_elf_blank ();
-    }
+  access_addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
 
-finish:
-  if (internal_relocs != NULL
-      && elf_section_data (sec)->relocs != internal_relocs)
-    free (internal_relocs);
+  if (ELF32_R_SYM (irel->r_info) >= symtab_hdr->sh_info)
+    {
+      indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+      h = elf_sym_hashes (abfd)[indx];
+    }
 
-  if (contents != NULL
-      && elf_section_data (sec)->this_hdr.contents != contents)
-    free (contents);
+  if (N32_OP6 (insn) == N32_OP6_ORI && access_addr < CONSERVATIVE_20BIT
+      && (!h || (h && strcmp (h->root.root.string, FP_BASE_NAME) != 0)))
+    {
+      reloc = R_NDS32_20_RELA;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
+      bfd_putb32 (insn, contents + laddr);
+    }
+  /* This is avoid to relax symbol address which is fixed
+     relocations.  Ex: _stack.  */
+  else if (N32_OP6 (insn) == N32_OP6_ORI
+          && h && bfd_is_abs_section (h->root.u.def.section))
+    return;
+  else
+    {
+      range_l = sdata_range[1][0];
+      range_h = sdata_range[1][1];
+      switch (ELF32_R_TYPE (irel->r_info))
+       {
+       case R_NDS32_LO12S0_RELA:
+         reloc = R_NDS32_SDA19S0_RELA;
+         break;
+       case R_NDS32_LO12S1_RELA:
+         reloc = R_NDS32_SDA18S1_RELA;
+         break;
+       case R_NDS32_LO12S2_RELA:
+         reloc = R_NDS32_SDA17S2_RELA;
+         break;
+       case R_NDS32_LO12S2_DP_RELA:
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
+         reloc = R_NDS32_SDA12S2_DP_RELA;
+         break;
+       case R_NDS32_LO12S2_SP_RELA:
+         range_l = sdata_range[0][0];
+         range_h = sdata_range[0][1];
+         reloc = R_NDS32_SDA12S2_SP_RELA;
+         break;
+       default:
+         return;
+       }
 
-  if (isymbuf != NULL && symtab_hdr->contents != (bfd_byte *) isymbuf)
-    free (isymbuf);
+      /* 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.  */
+             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);
 
-  return result;
+         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);
 
-error_return:
-  result = FALSE;
-  goto finish;
+       }
+    }
+  return;
 }
 
-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}
-};
+/* Relax low part of PIC instruction pattern.  */
 
-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)
+static void
+nds32_elf_relax_piclo12 (struct bfd_link_info *link_info, bfd *abfd,
+                        asection *sec, Elf_Internal_Rela *irel,
+                        bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                        Elf_Internal_Shdr *symtab_hdr)
 {
-  FILE *sym_ld_script = NULL;
-  struct elf_nds32_link_hash_table *table;
+  uint32_t insn;
+  bfd_vma local_sda, laddr;
+  bfd_signed_vma foff;
+  unsigned long reloc;
 
-  table = nds32_elf_hash_table (info);
-  sym_ld_script = table->sym_ld_script;
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
 
-  if (check_start_export_sym)
-    fprintf (sym_ld_script, "}\n");
+  if (N32_OP6 (insn) != N32_OP6_ORI)
+    return;
 
-  return TRUE;
-}
+  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12)
+    {
+      foff = calculate_got_memory_address (abfd, link_info, irel,
+                                          symtab_hdr) - local_sda;
+      reloc = R_NDS32_GOT20;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12)
+    {
+      foff = calculate_plt_memory_address (abfd, link_info, isymbuf, irel,
+                                          symtab_hdr) - local_sda;
+      reloc = R_NDS32_PLT_GOTREL_LO20;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12)
+    {
+      foff = calculate_memory_address (abfd, irel, isymbuf,
+                                      symtab_hdr) - local_sda;
+      reloc = R_NDS32_GOTOFF;
+    }
+  else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12)
+    {
+      foff = local_sda - sec->output_section->vma + sec->output_offset
+       + irel->r_offset + irel->r_addend;
+      reloc = R_NDS32_GOTPC20;
+    }
+  else
+    return;
 
-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))
+  if ((foff < CONSERVATIVE_20BIT) && (foff >= -CONSERVATIVE_20BIT))
     {
-    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;
+      /* 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);
     }
 }
 
-/* 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)
+/* Relax low part of LE TLS instruction pattern.  */
+
+static void
+nds32_elf_relax_letlslo12 (struct bfd_link_info *link_info, bfd *abfd,
+                          Elf_Internal_Rela *irel,
+                          bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                          Elf_Internal_Shdr *symtab_hdr)
 {
-  struct elf_nds32_link_hash_table *table;
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  unsigned long reloc;
 
-  table = nds32_elf_hash_table (link_info);
-  if (table == NULL)
-    return;
+  laddr = irel->r_offset;
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+  insn = bfd_getb32 (contents + laddr);
 
-  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;
+  if ( (bfd_signed_vma) (foff) < CONSERVATIVE_20BIT
+      && (bfd_signed_vma) (foff) >= -CONSERVATIVE_20BIT)
+    {
+      /* Pattern sethi-ori transform to movi.  */
+      reloc = R_NDS32_TLS_LE_20;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), reloc);
+      insn = N32_TYPE1 (MOVI, N32_RT5 (insn), 0);
+      bfd_putb32 (insn, contents + laddr);
+    }
 }
-\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.  */
-};
+/* Relax LE TLS calculate address instruction pattern.  */
 
 static void
-nds32_fag_init (struct nds32_fag *head)
+nds32_elf_relax_letlsadd (struct bfd_link_info *link_info, bfd *abfd,
+                         asection *sec, Elf_Internal_Rela *irel,
+                         Elf_Internal_Rela *internal_relocs,
+                         bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                         Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
 {
-  memset (head, 0, sizeof (struct nds32_fag));
-}
+  /* Local TLS non-pic
+     sethi    ta, hi20(symbol@tpoff)     ; TLS_LE_HI20
+     ori      ta, ta, lo12(symbol@tpoff)  ; TLS_LE_LO12
+     add      ra, ta, tp                 ; TLS_LE_ADD */
 
-static void
-nds32_fag_verify (struct nds32_fag *head)
-{
-  struct nds32_fag *iter;
-  struct nds32_fag *prev;
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
 
-  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;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+
+  /* The range is +/-16k.  */
+  if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT
+      && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT)
+    {
+      /* Transform add to addi.  */
+      insn = N32_TYPE2 (ADDI, N32_RT5 (insn), N32_RB5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0);
+
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
+       {
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
+       }
     }
 }
 
-/* Insert a fag in ascending order.
-   If a fag of the same address already exists,
-   they are chained by relas array.  */
+/* Relax LE TLS load store instruction pattern.  */
 
 static void
-nds32_fag_insert (struct nds32_fag *head, bfd_vma addr,
-                 Elf_Internal_Rela * rel)
+nds32_elf_relax_letlsls (struct bfd_link_info *link_info, bfd *abfd,
+                        asection *sec, Elf_Internal_Rela *irel,
+                        Elf_Internal_Rela *internal_relocs,
+                        bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                        Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
 {
-  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.  */ ;
+  uint32_t insn;
+  bfd_vma laddr;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  int success = 0;
 
-  /* `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.  */
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  BFD_ASSERT (elf_hash_table (link_info)->tls_sec != NULL);
+  foff -= (elf_hash_table (link_info)->tls_sec->vma + TP_OFFSET);
+
+  switch ((N32_OP6 (insn) << 8) | (insn & 0xff))
+    {
+    case (N32_OP6_MEM << 8) | N32_MEM_LB:
+    case (N32_OP6_MEM << 8) | N32_MEM_SB:
+    case (N32_OP6_MEM << 8) | N32_MEM_LBS:
+      /* The range is +/-16k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT)
+       {
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S0);
+         success = 1;
+         break;
+       }
+      /* Fall through.  */
+    case (N32_OP6_MEM << 8) | N32_MEM_LH:
+    case (N32_OP6_MEM << 8) | N32_MEM_SH:
+    case (N32_OP6_MEM << 8) | N32_MEM_LHS:
+      /* The range is +/-32k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S1
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S1)
+       {
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S1);
+         success = 1;
+         break;
+       }
+      /* Fall through.  */
+    case (N32_OP6_MEM << 8) | N32_MEM_LW:
+    case (N32_OP6_MEM << 8) | N32_MEM_SW:
+      /* The range is +/-64k.  */
+      if ((bfd_signed_vma) (foff) < CONSERVATIVE_15BIT_S2
+         && (bfd_signed_vma) (foff) >= -CONSERVATIVE_15BIT_S2)
+       {
+         insn =
+           ((insn & 0xff) << 25) | (insn & 0x1f00000) | ((insn & 0x7c00) << 5);
+         irel->r_info =
+           ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_TLS_LE_15S2);
+         success = 1;
+         break;
+       }
+      /* Fall through.  */
+    default:
+      break;
+    }
 
-      /* Check whether relas is big enough.  */
-      if (iter->count >= iter->relas_capcity)
+  if (success)
+    {
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
        {
-         iter->relas_capcity *= 2;
-         iter->relas = bfd_realloc
-           (iter->relas, iter->relas_capcity * sizeof (void *));
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
        }
-      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;
+/* Relax PTR relocation for nds32_elf_relax_section.  */
 
-  nds32_fag_verify (head);
-}
-
-static void
-nds32_fag_free_list (struct nds32_fag *head)
+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)
 {
-  struct nds32_fag *iter;
+  Elf_Internal_Rela *ptr_irel, *irelend, *count_irel, *re_irel;
 
-  iter = head->next;
-  while (iter)
+  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)
     {
-      struct nds32_fag *tmp = iter;
-      iter = iter->next;
-      free (tmp->relas);
-      tmp->relas = NULL;
-      free (tmp);
+      _bfd_error_handler (unrecognized_reloc_msg, abfd, "R_NDS32_PTR",
+                         (uint64_t) irel->r_offset);
+      return FALSE;
     }
-}
 
-static bfd_boolean
-nds32_fag_isempty (struct nds32_fag *head)
-{
-  return head->next == NULL;
-}
+  if (re_irel->r_addend != 1)
+    return FALSE;
 
-/* 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.
+  /* 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);
 
-   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.  */
+  /* 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;
+    }
 
-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.  */
+  if (ptr_irel != irelend)
+    return FALSE;
 
-  /* Use first fag for initial, and find the last fag in the window.
+  /* 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;
+}
 
-     In each iteration, we could simply subtract previous fag
-     and accumulate following fags which are inside the window,
-     untill we each the end.  */
+/* Relax PLT_GOT_SUFF relocation for nds32_elf_relax_section.  */
 
-  if (nds32_fag_isempty (head))
-    return 0;
+static void
+nds32_elf_relax_pltgot_suff (struct bfd_link_info *link_info, bfd *abfd,
+                            asection *sec, Elf_Internal_Rela *irel,
+                            Elf_Internal_Rela *internal_relocs,
+                            bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                            Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
+{
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
 
-  /* Initialize base.  */
-  base = head->next;
-  best = base;
-  for (last = base;
-       last && last->addr < base->addr + FAG_WINDOW;
-       last = last->next)
-    accu += last->count;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
 
-  baccu = accu;
+  /* FIXME: It's a little trouble to turn JRAL5 to JAL since
+     we need additional space.  It might be help if we could
+     borrow some space from instructions to be eliminated
+     such as sethi, ori, add.  */
+  if (insn & 0x80000000)
+    return;
 
-  /* 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 (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_PLT_GOT_SUFF))
+    return;
 
-  if (bestpp)
-    *bestpp = best;
-  return baccu;
-}
+  i1_irelfn =
+    find_relocs_at_address (irel, internal_relocs, irelend,
+                           R_NDS32_PTR_RESOLVED);
 
-/* 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.  */
+  /* 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.  */
 
-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;
+  if (N32_OP6 (insn) == N32_OP6_ALU1
+      && N32_SUB5 (insn) == N32_ALU1_ADD)
+    {
+      /* Get the value of the symbol referred to by the reloc.  */
+      nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                               &local_sda, FALSE);
+      foff = (bfd_signed_vma) (calculate_plt_memory_address
+                              (abfd, link_info, isymbuf, irel,
+                               symtab_hdr) - local_sda);
+      /* This condition only happened when symbol is undefined.  */
+      if (foff == 0)
+       return;
+
+      if (foff < -CONSERVATIVE_19BIT || foff >= CONSERVATIVE_19BIT)
+       return;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                  R_NDS32_PLT_GOTREL_LO19);
+      /* addi.gp */
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19));
+    }
+  else if (N32_OP6 (insn) == N32_OP6_JREG
+          && N32_SUB5 (insn) == N32_JREG_JRAL)
+    {
+      /* Get the value of the symbol referred to by the reloc.  */
+      foff =
+       calculate_plt_offset (abfd, sec, link_info, isymbuf, irel, symtab_hdr);
+      /* This condition only happened when symbol is undefined.  */
+      if (foff == 0)
+       return;
+      if (foff < -CONSERVATIVE_24BIT_S1 || foff >= CONSERVATIVE_24BIT_S1)
+       return;
+      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_25_PLTREL);
+      insn = INSN_JAL;
+    }
+  else
+    return;
 
-  output_bfd = abfd->sections->output_section->owner;
-  nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
-  best_fpbase = best_fag->addr;
+  bfd_putb32 (insn, contents + laddr);
+  if (i1_irelfn != irelend)
+    {
+      i1_irelfn->r_addend |= 1;
+      *again = TRUE;
+    }
+}
 
-  if (best_fpbase > gp + sdata_range[4][1]
-      || best_fpbase < gp - sdata_range[4][0])
-    return FALSE;
+/* Relax GOT_SUFF relocation for nds32_elf_relax_section.  */
 
-  /* 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;
+static void
+nds32_elf_relax_got_suff (struct bfd_link_info *link_info, bfd *abfd,
+                         asection *sec, Elf_Internal_Rela *irel,
+                         Elf_Internal_Rela *internal_relocs,
+                         bfd_byte *contents, Elf_Internal_Shdr *symtab_hdr,
+                         bfd_boolean *again)
+{
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
 
-      for (i = 0; i < ifag->count; i++)
-       {
-         Elf_Internal_Rela *insn16_rel;
-         Elf_Internal_Rela *fag_rel;
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
+  if (insn & 0x80000000)
+    return;
 
-         fag_rel = ifag->relas[i];
+  if (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_GOT_SUFF))
+    return;
 
-         /* Only if this is within the WINDOWS, FP7U2_FLAG
-            is applied.  */
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
 
-         insn16_rel = find_relocs_at_address
-           (fag_rel, internal_relocs, irelend, R_NDS32_INSN16);
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  foff = calculate_got_memory_address (abfd, link_info, irel,
+                                      symtab_hdr) - local_sda;
 
-         if (insn16_rel != irelend)
-           insn16_rel->r_addend = R_NDS32_INSN16_FP7U2_FLAG;
+  if (foff < CONSERVATIVE_19BIT && foff >= -CONSERVATIVE_19BIT)
+    {
+      /* Turn LW to LWI.GP.  Change relocation type to R_NDS32_GOT_REL.  */
+      insn = N32_TYPE1 (HWGP, N32_RT5 (insn), __MF (6, 17, 3));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_GOT17S2_RELA);
+      bfd_putb32 (insn, contents + laddr);
+      if (i1_irelfn != irelend)
+       {
+         i1_irelfn->r_addend |= 1;
+         *again = TRUE;
        }
     }
-  return TRUE;
 }
 
-/* This is the main function of fp-as-gp optimization.
-   It should be called by relax_section.  */
+/* Relax PLT_GOT_SUFF relocation for nds32_elf_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)
+static void
+nds32_elf_relax_gotoff_suff (struct bfd_link_info *link_info, bfd *abfd,
+                            asection *sec, Elf_Internal_Rela *irel,
+                            Elf_Internal_Rela *internal_relocs,
+                            bfd_byte *contents, Elf_Internal_Sym *isymbuf,
+                            Elf_Internal_Shdr *symtab_hdr, bfd_boolean *again)
 {
-  Elf_Internal_Rela *begin_rel = NULL;
-  Elf_Internal_Rela *irel;
-  struct nds32_fag fag_head;
-  Elf_Internal_Shdr *symtab_hdr;
-  bfd_byte *contents;
+  int opc_insn_gotoff;
+  uint32_t insn;
+  bfd_signed_vma foff;
+  Elf_Internal_Rela *i1_irelfn, *i2_irelfn, *irelend;
+  bfd_vma local_sda, laddr;
 
-  /* FIXME: Can we bfd_elf_link_read_relocs for the relocs?  */
+  irelend = internal_relocs + sec->reloc_count;
+  laddr = irel->r_offset;
+  insn = bfd_getb32 (contents + laddr);
 
-  /* 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.
+  if (insn & 0x80000000)
+    return;
 
-     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.
+  if (nds32_elf_check_dup_relocs
+      (irel, internal_relocs, irelend, R_NDS32_GOTOFF_SUFF))
+    return;
 
-     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.
+  i1_irelfn = find_relocs_at_address (irel, internal_relocs, irelend,
+                                     R_NDS32_PTR_RESOLVED);
+  nds32_elf_final_sda_base (sec->output_section->owner, link_info,
+                           &local_sda, FALSE);
+  foff = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+  foff = foff - local_sda;
 
-     To suppress the conversion, we simply NOT to apply
-     R_NDS32_INSN16_FP7U2_FLAG flag.  */
+  if (foff >= CONSERVATIVE_19BIT || foff < -CONSERVATIVE_19BIT)
+    return;
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  /* 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), N32_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), N32_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), N32_BIT (19));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    case (N32_OP6_MEM << 8) | N32_MEM_SB:
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), 0);
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    case (N32_OP6_ALU1 << 8) | N32_ALU1_ADD:
+      insn = N32_TYPE1 (SBGP, N32_RT5 (insn), N32_BIT (19));
+      irel->r_info =
+       ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_NDS32_SDA19S0_RELA);
+      break;
+    default:
+      return;
+    }
 
-  if (!nds32_get_section_contents (abfd, sec, &contents)
-      || !nds32_get_local_syms (abfd, sec, &isymbuf))
-    return FALSE;
+  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);
 
-  /* 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.  */
+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;
 
-  for (irel = internal_relocs; irel < irelend; irel++)
+  /* 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++)
     {
-      /* 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 (label_rel->r_info) != R_NDS32_LABEL)
+       continue;
 
-      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);
+      /* 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++;
 
-         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;
+      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;
 
-         /* End of the region.
-            Check whether it is worth to do fp-as-gp.  */
+      if (insn_rel < irelend && insn_rel->r_offset == label_rel->r_offset
+         && insn_rel < label_rel)
+       {
+         /* Swap the two reloc if the R_NDS32_INSN16 is
+            before R_NDS32_LABEL.  */
+         memcpy (&rel_temp, insn_rel, sizeof (Elf_Internal_Rela));
+         memcpy (insn_rel, label_rel, sizeof (Elf_Internal_Rela));
+         memcpy (label_rel, &rel_temp, sizeof (Elf_Internal_Rela));
+       }
+    }
 
-         if (begin_rel == NULL)
+  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)
            {
-             (*_bfd_error_handler) (_("%B: Unmatched OMIT_FP in %A."), abfd, sec);
+             if (tmp_rel->r_addend < 2)
+               label_rel = tmp_rel;
              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))
+         else if (tmp_rel->r_addend > 1)
            {
-             /* 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;
+             /* Remove all LABEL relocation from label_rel to tmp_rel
+                including relocations with same offset as tmp_rel.  */
+             for (tmp2_rel = label_rel; tmp2_rel < tmp_rel
+                  || tmp2_rel->r_offset == tmp_rel->r_offset; tmp2_rel++)
+               {
+                 if (ELF32_R_TYPE (tmp2_rel->r_info) == R_NDS32_LABEL
+                     && tmp2_rel->r_addend < 2)
+                   tmp2_rel->r_info =
+                     ELF32_R_INFO (ELF32_R_SYM (tmp2_rel->r_info),
+                                   R_NDS32_NONE);
+               }
+             label_rel = NULL;
            }
-
-         /* 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;
        }
+      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;
+       }
+    }
 
-      if (begin_rel == NULL)
-       /* Skip if we are not in the region of fp-as-gp.  */
+  label_rel = NULL;
+  insn_rel = NULL;
+  /* Optimized for speed and nothing has not been relaxed.
+     It's time to align labels.
+     We may convert a 16-bit instruction right before a label to
+     32-bit, in order to align the label if necessary
+     all reloc entries has been sorted by r_offset.  */
+  for (irel = internal_relocs; irel < irelend; irel++)
+    {
+      if (ELF32_R_TYPE (irel->r_info) != R_NDS32_INSN16
+         && ELF32_R_TYPE (irel->r_info) != R_NDS32_LABEL)
        continue;
 
-      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA
-         || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA)
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_INSN16)
        {
-         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;
+         /* A new INSN16 found, resize the old one.  */
+         if (is_convert_32_to_16
+             (abfd, sec, irel, internal_relocs, irelend, &insn16)
+             || is_16bit_NOP (abfd, sec, irel))
+           {
+             if (insn_rel)
+               {
+                 /* Previous INSN16 reloc exists, reduce its
+                    size to 16-bit.  */
+                 if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs,
+                                          irelend, &insn16))
+                   {
+                     nds32_elf_write_16 (abfd, contents, insn_rel,
+                                         internal_relocs, irelend, insn16);
 
-         addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
-         nds32_fag_insert (&fag_head, addr, irel);
+                     if (!insert_nds32_elf_blank_recalc_total
+                         (relax_blank_list, insn_rel->r_offset + 2, 2))
+                       return FALSE;
+                   }
+                 else if (is_16bit_NOP (abfd, sec, insn_rel))
+                   {
+                     if (!insert_nds32_elf_blank_recalc_total
+                         (relax_blank_list, insn_rel->r_offset, 2))
+                       return FALSE;
+                   }
+                 insn_rel->r_info =
+                   ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info), R_NDS32_NONE);
+               }
+             /* Save the new one for later use.  */
+             insn_rel = irel;
+           }
+         else
+           irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                        R_NDS32_NONE);
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA)
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL)
        {
-         begin_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)
-{
-  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;
+         /* Search for label.  */
+         int force_relax = 0;
 
-  /*
-     NOTE: Disable fp-as-gp if we encounter ifcall relocations.
-     * R_NDS32_17IFC_PCREL_RELA
-     * R_NDS32_10IFCU_PCREL_RELA
+         /* 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;
+           }
 
-     CASE??????????????
-  */
+         address =
+           irel->r_offset - get_nds32_elf_blank_total (relax_blank_list,
+                                                       irel->r_offset, 1);
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  nds32_get_section_contents (abfd, sec, &contents);
+         if (!insn_rel)
+           {
+             /* Check if there is case which can not be aligned.  */
+             if (irel->r_addend == 2 && address & 0x2)
+               return FALSE;
+             continue;
+           }
 
-  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;
+         /* Try to align this label.  */
 
-      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;
+         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.  */
 
-      /* We're not in the region.  */
-      if (!unused_region)
-       continue;
+             /* Search for INSN16 at LABEL location.  If INSN16 is at
+                same location and this LABEL alignment is lower than 2,
+                the INSN16 can be converted to 2-byte.  */
+             for (tmp_rel = irel;
+                  tmp_rel < irelend && tmp_rel->r_offset == irel->r_offset;
+                  tmp_rel++)
+               {
+                 if (ELF32_R_TYPE (tmp_rel->r_info) == R_NDS32_INSN16
+                     && (is_convert_32_to_16
+                         (abfd, sec, tmp_rel, internal_relocs,
+                          irelend, &insn16)
+                         || is_16bit_NOP (abfd, sec, tmp_rel)))
+                   {
+                     force_relax = 1;
+                     break;
+                   }
+               }
+           }
 
-      /* _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;
+         if (force_relax || irel->r_addend == 1 || address & 0x2)
+           {
+             /* Label not aligned.  */
+             /* Previous reloc exists, reduce its size to 16-bit.  */
+             if (is_convert_32_to_16 (abfd, sec, insn_rel,
+                                      internal_relocs, irelend, &insn16))
+               {
+                 nds32_elf_write_16 (abfd, contents, insn_rel,
+                                     internal_relocs, irelend, insn16);
 
-      /* 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 (!insert_nds32_elf_blank_recalc_total
+                     (relax_blank_list, insn_rel->r_offset + 2, 2))
+                   return FALSE;
+               }
+             else if (is_16bit_NOP (abfd, sec, insn_rel))
+               {
+                 if (!insert_nds32_elf_blank_recalc_total
+                     (relax_blank_list, insn_rel->r_offset, 2))
+                   return FALSE;
+               }
 
-      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;
+           }
+         /* INSN16 reloc is used.  */
+         insn_rel = NULL;
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S0_RELA)
+    }
+
+  address =
+    sec->size - get_nds32_elf_blank_total (relax_blank_list, sec->size, 0);
+  if (insn_rel && (address & 0x2 || opt_size))
+    {
+      if (is_convert_32_to_16 (abfd, sec, insn_rel, internal_relocs,
+                              irelend, &insn16))
        {
-         /* addi  $fp, $gp, -256  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (insn != INSN_ADDI_GP_TO_FP)
-           continue;
+         nds32_elf_write_16 (abfd, contents, insn_rel, internal_relocs,
+                             irelend, insn16);
+         if (!insert_nds32_elf_blank_recalc_total
+             (relax_blank_list, insn_rel->r_offset + 2, 2))
+           return FALSE;
+         insn_rel->r_info = ELF32_R_INFO (ELF32_R_SYM (insn_rel->r_info),
+                                          R_NDS32_NONE);
        }
-      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_20_RELA)
+      else if (is_16bit_NOP (abfd, sec, insn_rel))
        {
-         /* movi  $fp, FP_BASE  */
-         insn = bfd_getb32 (contents + irel->r_offset);
-         if (insn != INSN_MOVI_TO_FP)
-           continue;
+         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);
        }
-      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;
+  insn_rel = NULL;
+  return TRUE;
 }
-\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
+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;
-  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;
-};
+  Elf_Internal_Rela *irelend;
+  Elf_Internal_Sym *isymbuf = NULL;
+  bfd_byte *contents = NULL;
+  bfd_boolean result = TRUE;
+  int optimize = 0;
+  int opt_size = 0;
+  uint32_t insn;
+  uint16_t insn16;
 
-static struct elf_nds32_ifc_symbol_entry *ifc_symbol_head = NULL;
+  /* Target dependnet option.  */
+  struct elf_nds32_link_hash_table *table;
+  int load_store_relax;
 
-/* Insert symbol of jal and j for ifc.  */
+  relax_blank_list = NULL;
 
-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;
+  *again = FALSE;
 
-  /* 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;
+  /* 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)
+    return TRUE;
 
-         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;
+  /* 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;
 
-         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;
-    }
+  /* The optimization type to do.  */
 
-  /* 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;
-    }
+  table = nds32_elf_hash_table (link_info);
 
-  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;
+  /* The begining of general relaxation.  */
 
-  if (h == NULL)
-    {
-      /* Local symbols.  */
-      ptr->sec = sec;
-      ptr->irel_head->sec = NULL;
-    }
-  else
+  if (is_SDA_BASE_set == 0)
     {
-      /* Global symbol.  */
-      ptr->sec = NULL;
-      ptr->irel_head->sec = sec;
+      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);
     }
 
-  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_Rela *internal_relocs;
-  Elf_Internal_Rela *irelend;
-  Elf_Internal_Rela *irel;
-  Elf_Internal_Shdr *symtab_hdr;
-  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);
-  struct elf_nds32_link_hash_table *table;
-  bfd_boolean ifc_loop_aware;
-
+  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 */);
-  irelend = internal_relocs + sec->reloc_count;
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  if (internal_relocs == NULL)
+    goto error_return;
 
-  /* Check if the object enable ifc.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  irelend = internal_relocs + sec->reloc_count;
+  irel = find_relocs_at_address (internal_relocs, internal_relocs,
+                                irelend, R_NDS32_RELAX_ENTRY);
 
-  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)))
+  if (irel == irelend)
     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)
+  if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_ENTRY)
     {
-      /* 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 (irel->r_addend & R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG)
+       return TRUE;
 
-      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++;
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG)
+       optimize = 1;
+
+      if (irel->r_addend & R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG)
+       opt_size = 1;
     }
-  return TRUE;
-}
 
-/* Determine whether j and jal should be substituted.  */
+  load_store_relax = table->load_store_relax;
 
-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;
+  /* 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;
 
-  table = nds32_elf_hash_table (info);
-  target_optimize = table->target_optimize;
-  while (ptr)
+  /* Do relax loop only when finalize is not done.
+     Take care of relaxable relocs except INSN16.  */
+  for (irel = internal_relocs; irel < irelend; irel++)
     {
-      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;
-           }
-       }
+      int seq_len;             /* Original length of instruction sequence.  */
+      int insn_len = 0;                /* Final length of instruction sequence.  */
+      bfd_boolean removed;
+
+      insn = 0;
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_LABEL
+         && (irel->r_addend & 0x1f) >= 2)
+       optimize = 1;
+
+      /* Relocation Types
+        R_NDS32_LONGCALL1      53
+        R_NDS32_LONGCALL2      54
+        R_NDS32_LONGCALL3      55
+        R_NDS32_LONGJUMP1      56
+        R_NDS32_LONGJUMP2      57
+        R_NDS32_LONGJUMP3      58
+        R_NDS32_LOADSTORE      59  */
+      if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL1
+         && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LOADSTORE)
+       seq_len = GET_SEQ_LEN (irel->r_addend);
+
+      /* Relocation Types
+        R_NDS32_LONGCALL4      107
+        R_NDS32_LONGCALL5      108
+        R_NDS32_LONGCALL6      109
+        R_NDS32_LONGJUMP4      110
+        R_NDS32_LONGJUMP5      111
+        R_NDS32_LONGJUMP6      112
+        R_NDS32_LONGJUMP7      113  */
+      else if (ELF32_R_TYPE (irel->r_info) >= R_NDS32_LONGCALL4
+              && ELF32_R_TYPE (irel->r_info) <= R_NDS32_LONGJUMP7)
+       seq_len = 4;
+
+       /* Relocation Types
+        R_NDS32_LO12S0_RELA            30
+        R_NDS32_LO12S1_RELA            29
+        R_NDS32_LO12S2_RELA            28
+        R_NDS32_LO12S2_SP_RELA         71
+        R_NDS32_LO12S2_DP_RELA         70
+        R_NDS32_GOT_LO12               46
+        R_NDS32_GOTOFF_LO12            50
+        R_NDS32_PLTREL_LO12            65
+        R_NDS32_PLT_GOTREL_LO12        67
+        R_NDS32_17IFC_PCREL_RELA       96
+        R_NDS32_GOT_SUFF               193
+        R_NDS32_GOTOFF_SUFF            194
+        R_NDS32_PLT_GOT_SUFF           195
+        R_NDS32_MULCALL_SUFF           196
+        R_NDS32_PTR                    197  */
+      else if ((ELF32_R_TYPE (irel->r_info) <= R_NDS32_LO12S0_RELA
+               && ELF32_R_TYPE (irel->r_info) >= R_NDS32_LO12S2_RELA)
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_SP_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_LO12S2_DP_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOT_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTOFF_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_GOTPC_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLTREL_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_PLT_GOTREL_LO12
+              || (ELF32_R_TYPE (irel->r_info) >= R_NDS32_GOT_SUFF
+                  && ELF32_R_TYPE (irel->r_info) <= R_NDS32_PTR)
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LO12
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_ADD
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_TLS_LE_LS)
+       seq_len = 0;
       else
+       continue;
+
+      insn_len = seq_len;
+      removed = FALSE;
+
+      switch (ELF32_R_TYPE (irel->r_info))
        {
-         /* Global symbol.  We have to get the absolute address
-            and decide whether to keep it or not.*/
+       case R_NDS32_LONGCALL1:
+         removed = nds32_elf_relax_longcall1 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL2:
+         removed = nds32_elf_relax_longcall2 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL3:
+         removed = nds32_elf_relax_longcall3 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP1:
+         removed = nds32_elf_relax_longjump1 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP2:
+         removed = nds32_elf_relax_longjump2 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP3:
+         removed = nds32_elf_relax_longjump3 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL4:
+         removed = nds32_elf_relax_longcall4 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL5:
+         removed = nds32_elf_relax_longcall5 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGCALL6:
+         removed = nds32_elf_relax_longcall6 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP4:
+         removed = nds32_elf_relax_longjump4 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, contents, isymbuf,
+                                              symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP5:
+         removed = nds32_elf_relax_longjump5 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP6:
+         removed = nds32_elf_relax_longjump6 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LONGJUMP7:
+         removed = nds32_elf_relax_longjump7 (abfd, sec, irel, internal_relocs,
+                                              &insn_len, &seq_len, contents,
+                                              isymbuf, symtab_hdr);
+         break;
+       case R_NDS32_LOADSTORE:
+         removed = nds32_elf_relax_loadstore (link_info, abfd, sec, irel,
+                                              internal_relocs, &insn_len,
+                                              contents, isymbuf, symtab_hdr,
+                                              load_store_relax);
+         break;
+       case R_NDS32_LO12S0_RELA:
+       case R_NDS32_LO12S1_RELA:
+       case R_NDS32_LO12S2_DP_RELA:
+       case R_NDS32_LO12S2_SP_RELA:
+       case R_NDS32_LO12S2_RELA:
+         /* Relax for low part.  */
+         nds32_elf_relax_lo12 (link_info, abfd, sec, irel, internal_relocs,
+                               contents, isymbuf, symtab_hdr);
 
-         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;
-           }
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOT_LO12:
+       case R_NDS32_GOTOFF_LO12:
+       case R_NDS32_PLTREL_LO12:
+       case R_NDS32_PLT_GOTREL_LO12:
+       case R_NDS32_GOTPC_LO12:
+         /* Relax for PIC gp-relative low part.  */
+         nds32_elf_relax_piclo12 (link_info, abfd, sec, irel, contents,
+                                  isymbuf, symtab_hdr);
 
-         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;
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_LO12:
+         /* Relax for LE TLS low part.  */
+         nds32_elf_relax_letlslo12 (link_info, abfd, irel, contents,
+                                    isymbuf, symtab_hdr);
 
-             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;
-           }
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_ADD:
+         nds32_elf_relax_letlsadd (link_info, abfd, sec, irel, internal_relocs,
+                                   contents, isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_TLS_LE_LS:
+         nds32_elf_relax_letlsls (link_info, abfd, sec, irel, internal_relocs,
+                                  contents, isymbuf, symtab_hdr, again);
+         continue;
+       case R_NDS32_PTR:
+         removed = nds32_elf_relax_ptr (abfd, sec, irel, internal_relocs,
+                                        &insn_len, &seq_len, contents);
+         break;
+       case R_NDS32_PLT_GOT_SUFF:
+         nds32_elf_relax_pltgot_suff (link_info, abfd, sec, irel,
+                                      internal_relocs, contents,
+                                      isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOT_SUFF:
+         nds32_elf_relax_got_suff (link_info, abfd, sec, irel,
+                                   internal_relocs, contents,
+                                   symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       case R_NDS32_GOTOFF_SUFF:
+         nds32_elf_relax_gotoff_suff (link_info, abfd, sec, irel,
+                                      internal_relocs, contents,
+                                      isymbuf, symtab_hdr, again);
+         /* It is impossible to delete blank, so just continue.  */
+         continue;
+       default:
+         continue;
 
-         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;
-           }
        }
+      if (removed && seq_len - insn_len > 0)
+       {
+         if (!insert_nds32_elf_blank
+             (&relax_blank_list, irel->r_offset + insn_len,
+              seq_len - insn_len))
+           goto error_return;
+         *again = TRUE;
+       }
+    }
+
+  calc_nds32_blank_total (relax_blank_list);
+
+  if (table->relax_fp_as_gp)
+    {
+      if (!nds32_relax_fp_as_gp (link_info, abfd, sec, internal_relocs,
+                                irelend, isymbuf))
+       goto error_return;
 
-       /* 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 (!*again)
+       {
+         if (!nds32_fag_remove_unused_fpbase (abfd, sec, internal_relocs,
+                                              irelend))
+           goto error_return;
+       }
     }
-}
 
-/* Determine whether j and jal should be substituted after ex9 done.  */
+  if (!*again)
+    {
+      if (!nds32_relax_adjust_label (abfd, sec, internal_relocs, contents,
+                                    &relax_blank_list, optimize, opt_size))
+       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;
+  /* 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;
+    }
 
-  while (ptr)
+  if (!*again)
     {
-      if (ptr->enable == 0)
+      /* 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 + (~((-1U) << sec->alignment_power)))
+                      & ((-1U) << sec->alignment_power);
+      if ((sec_size_align - sec->size) & 0x2)
        {
-         /* 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;
-           }
+         insn16 = NDS32_NOP16;
+         bfd_putb16 (insn16, contents + sec->size);
+         sec->size += 2;
        }
-      ptr = ptr->next;
-    }
-}
 
-/* Wrapper to do ifc relaxation.  */
+      while (sec_size_align != sec->size)
+       {
+         insn = NDS32_NOP32;
+         bfd_putb32 (insn, contents + sec->size);
+         sec->size += 4;
+       }
 
-bfd_boolean
-nds32_elf_ifc_finish (struct bfd_link_info *info)
-{
-  int relax_status;
-  struct elf_nds32_link_hash_table *table;
+      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;
 
-  table = nds32_elf_hash_table (info);
-  relax_status = table->relax_status;
+      clean_nds32_elf_blank ();
+    }
 
-  if (!(relax_status & NDS32_RELAX_JUMP_IFC_DONE))
-    nds32_elf_ifc_filter (info);
-  else
-    nds32_elf_ifc_filter_after_ex9 ();
+finish:
+  if (internal_relocs != NULL
+      && elf_section_data (sec)->relocs != internal_relocs)
+    free (internal_relocs);
 
-  if (!nds32_elf_ifc_replace (info))
-    return FALSE;
+  if (contents != NULL
+      && elf_section_data (sec)->this_hdr.contents != contents)
+    free (contents);
 
-  if (table)
-    table->relax_status |= NDS32_RELAX_JUMP_IFC_DONE;
-  return TRUE;
+  if (isymbuf != NULL && symtab_hdr->contents != (bfd_byte *) isymbuf)
+    free (isymbuf);
+
+  return result;
+
+error_return:
+  result = FALSE;
+  goto finish;
 }
 
-/* Traverse the result of ifc filter and replace it with ifcall9.  */
+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_ifc_replace (struct bfd_link_info *info)
+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)
 {
-  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;
+  FILE *sym_ld_script = NULL;
   struct elf_nds32_link_hash_table *table;
-  int relax_status;
 
   table = nds32_elf_hash_table (info);
-  relax_status = table->relax_status;
-
-  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))
-       {
-         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;
+  sym_ld_script = table->sym_ld_script;
 
-             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, &contents))
-               return FALSE;
+  if (check_start_export_sym)
+    fprintf (sym_ld_script, "}\n");
 
-             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;
-               }
+  return 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;
-
-                     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;
-                       }
-                   }
-
-                 irel_ptr = irel_ptr->next;
-               }
-           }
-       }
-      ptr = ptr->next;
-    }
-
-  return TRUE;
-}
-
-/* Relocate ifcall.  */
-
-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;
-
-  bfd_byte *contents = NULL;
-
-  while (ptr)
-    {
-      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;
-           }
-
-         irel_ptr = ptr->irel_head;
-         if (ptr->h == NULL)
-           {
-             /* Local symbol.  */
-             if (!nds32_get_section_contents (ptr->sec->owner, ptr->sec, &contents))
-               return FALSE;
-
-             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;
-                       }
-
-                     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;
-                           }
-                       }
-
-                     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;
-    }
-
-  return TRUE;
-}
-
-/* End of IFC relaxation.  */
-\f
-/* EX9 Instruction Table Relaxation.  */
-
-/* Global hash list.  */
-struct elf_link_hash_entry_list
-{
-  struct elf_link_hash_entry *h;
-  struct elf_link_hash_entry_list *next;
-};
-
-/* Save different destination but same insn.  */
-struct elf_link_hash_entry_mul_list
-{
-  /* 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;
-};
-
-/* Instruction hash table.  */
-struct elf_nds32_code_hash_entry
-{
-  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;
-};
-
-/* 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;
-};
-
-/* J and JAL symbol list.  */
-struct elf_nds32_symbol_entry
-{
-  char *string;
-  unsigned long insn;
-  struct elf_nds32_symbol_entry *next;
-};
-
-/* Relocation list.  */
-struct elf_nds32_irel_entry
-{
-  Elf_Internal_Rela *irel;
-  struct elf_nds32_irel_entry *next;
-};
-
-/* 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;
-};
-
-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;
-
-/* EX9 hash function.  */
-
-static struct bfd_hash_entry *
-nds32_elf_code_hash_newfunc (struct bfd_hash_entry *entry,
-                            struct bfd_hash_table *table,
-                            const char *string)
-{
-  struct elf_nds32_code_hash_entry *ret;
-
-  /* Allocate the structure if it has not already been allocated by a
-     subclass.  */
-  if (entry == NULL)
-    {
-      entry = (struct bfd_hash_entry *)
-       bfd_hash_allocate (table, sizeof (*ret));
-      if (entry == NULL)
-       return entry;
-    }
-
-  /* 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)
-{
-  struct elf_nds32_insn_times_entry *temp;
-  struct elf_nds32_insn_times_entry *temp2;
-
-  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;
-       }
-    }
-}
-
-/* Examine each insn times in hash table.
-   Handle multi-link hash entry.
-
-   TODO: This function doesn't assign so much info since it is fake.  */
-
-static int
-nds32_elf_examine_insn_times (struct elf_nds32_code_hash_entry *h)
-{
-  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;
-
-      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;
-
-      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;
-
-         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);
-       }
-    }
-  return TRUE;
-}
-
-/* Count each insn times in hash table.
-   Handle multi-link hash entry.  */
-
-static int
-nds32_elf_count_insn_times (struct elf_nds32_code_hash_entry *h)
-{
-  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;
-
-      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 (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);
-           }
-       }
-
-      if (h->const_insn == 1)
-       {
-         /* 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);
-       }
-    }
-
-  return TRUE;
-}
-
-/* Hash table traverse function.  */
-
-static void
-nds32_elf_code_hash_traverse (int (*func) (struct elf_nds32_code_hash_entry*))
+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)
 {
-  unsigned int i;
-
-  ex9_code_table.frozen = 1;
-  for (i = 0; i < ex9_code_table.size; i++)
+  switch ((int) ELF32_R_TYPE (rela->r_info))
     {
-      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;
+    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;
     }
-out:
-  ex9_code_table.frozen = 0;
 }
 
-
-/* Give order number to insn list.  */
-
-static void
-nds32_elf_order_insn_times (struct bfd_link_info *info)
+/* 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_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;
-
-/* The max number of entries is 512.  */
-  ex9_insn = ex9_insn_head;
-  table = nds32_elf_hash_table (info);
-  ex9_limit = table->ex9_limit;
-
-  /* Get the minimun one of ex9 list and limitation.  */
-  while (ex9_insn)
-    {
-      total++;
-      ex9_insn = ex9_insn->next;
-    }
-  total = MIN (total, ex9_limit);
-
-  temp = bfd_malloc (sizeof (struct elf_nds32_insn_times_entry));
-  temp->string = bfd_malloc (sizeof (char) * 10);
-  temp->times = 0;
-  temp->sec = NULL;
-  temp->m_list = NULL;
-  temp->irel = NULL;
-  temp->next = NULL;
-  /* Since the struct elf_nds32_insn_times_entry string is const char,
-     it has to allocate another space to write break 0xea.  */
-  insn = bfd_malloc (sizeof (char) * 10);
-  snprintf (insn, sizeof (char) * 10, "%08x", INSN_BREAK_EA);
-  temp->string = (const char *) insn;
-
-  ex9_insn = ex9_insn_head;
-
-  while (ex9_insn != NULL && number <= ex9_limit)
-    {
-      /* 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++;
-
-      if (number == 234)
-       {
-         /* Link break 0xea entry into list.  */
-         temp->next = ex9_insn->next;
-         ex9_insn->next = temp;
-         temp->order = number;
-         number++;
-         ex9_insn = ex9_insn->next;
-       }
-
-      if (number > ex9_limit)
-       {
-         temp = ex9_insn;
-         ex9_insn = ex9_insn->next;
-         temp->next = NULL;
-         break;
-       }
-      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);
-    }
-}
-
-/* Build .ex9.itable section.  */
-
-static void
-nds32_elf_ex9_build_itable (struct bfd_link_info *link_info)
-{
-  asection *table_sec;
-  struct elf_nds32_insn_times_entry *ptr;
-  bfd *it_abfd;
-  int number = 0;
-  bfd_byte *contents = NULL;
-
-  for (it_abfd = link_info->input_bfds; it_abfd != NULL;
-       it_abfd = it_abfd->link.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;
-
-         for (ptr = ex9_insn_head; ptr !=NULL ; ptr = ptr->next)
-           number++;
-
-         table_sec->size = number * 4;
-
-         if (number == 0)
-           {
-             /* There is no insntruction effective enough to convert to ex9.
-                Only add break 0xea into ex9 table.  */
-             table_sec->size = 4;
-             bfd_putb32 ((bfd_vma) INSN_BREAK_EA, (char *) contents);
-             return;
-           }
-
-         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;
-
-             val = strtol (ptr->string, NULL, 16);
-             bfd_putb32 ((bfd_vma) val, (char *) contents + (number * 4));
-             number++;
-           }
-         break;
-       }
-    }
-}
-
-/* Get insn with regs according to relocation type.  */
-
-static void
-nds32_elf_get_insn_with_reg (Elf_Internal_Rela *irel,
-                            unsigned long insn, unsigned long *insn_with_reg)
-{
-  reloc_howto_type *howto = NULL;
 
-  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)))
-    {
-      *insn_with_reg = insn;
-      return;
-    }
+  table = nds32_elf_hash_table (link_info);
+  if (table == NULL)
+    return;
 
-  howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info));
-  *insn_with_reg = insn & (0xffffffff ^ howto->dst_mask);
+  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.  */
 
-/* Mask number of address bits according to relocation.  */
+#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 unsigned long
-nds32_elf_irel_mask (Elf_Internal_Rela *irel)
+/* 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
 {
-  reloc_howto_type *howto = NULL;
-
-  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;
-
-  howto = bfd_elf32_bfd_reloc_type_table_lookup (ELF32_R_TYPE (irel->r_info));
-  return howto->dst_mask;
-}
+  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_elf_insert_irel_entry (struct elf_nds32_irel_entry **irel_list,
-                            struct elf_nds32_irel_entry *irel_ptr)
+nds32_fag_init (struct nds32_fag *head)
 {
-  if (*irel_list == NULL)
-    {
-      *irel_list = irel_ptr;
-      irel_ptr->next = NULL;
-    }
-  else
-    {
-      irel_ptr->next = *irel_list;
-      *irel_list = irel_ptr;
-    }
+  memset (head, 0, sizeof (struct nds32_fag));
 }
 
 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;
-
-  ptr = bfd_malloc (sizeof (struct elf_nds32_ex9_refix));
-  ptr->sec = sec;
-  ptr->irel = irel;
-  ptr->h = h;
-  ptr->order = order;
-  ptr->next = NULL;
-
-  if (ex9_refix_head == NULL)
-    ex9_refix_head = ptr;
-  else
-    {
-      struct elf_nds32_ex9_refix *temp = ex9_refix_head;
-
-      while (temp->next != NULL)
-       temp = temp->next;
-      temp->next = ptr;
-    }
-}
-
-enum
+nds32_fag_verify (struct nds32_fag *head)
 {
-  DATA_EXIST = 1,
-  CLEAN_PRE = 1 << 1,
-  PUSH_PRE = 1 << 2
-};
-
-/* Check relocation type if supporting for ex9.  */
-
-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;
-
-  table = nds32_elf_hash_table (info);
-  ex9_loop_aware = table->ex9_loop_aware;
+  struct nds32_fag *iter;
+  struct nds32_fag *prev;
 
-  while ((*irel) != NULL && (*irel) < irelend && *off == (*irel)->r_offset)
+  prev = NULL;
+  iter = head->next;
+  while (iter)
     {
-      switch (ELF32_R_TYPE ((*irel)->r_info))
-       {
-       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;
-
-             /* The final instruction in the region, regard this one as data to ignore it.  */
-             result |= DATA_EXIST;
-             return result;
-           }
-         break;
-
-       case R_NDS32_LABEL:
-         if (relax_blank_list && ((*irel)->r_addend & 0x1f) == 2)
-           {
-             /* 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;
-           }
-         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;
-
-       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)
-           {
-             /* 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;
-               }
-           }
-       }
-      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 (irel_save)
-           *irel = irel_save;
-         return result;
-       }
+      if (prev && prev->addr >= iter->addr)
+       puts ("Bug in fp-as-gp insertion.");
+      prev = iter;
+      iter = iter->next;
     }
-  return result;
 }
 
-/* Replace input file instruction which is in ex9 itable.  */
-
-static bfd_boolean
-nds32_elf_ex9_replace_instruction (struct bfd_link_info *info, bfd *abfd, asection *sec)
-{
-  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;
-  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;
-
-  off = 0;
-
-  /* Check if the object enable ex9.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
-
-  /* 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;
-
-  irel = internal_relocs;
-
-  /* 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;
-
-      /* Syn the instruction and the relocation.  */
-      while (irel != NULL && irel < irelend && irel->r_offset < off)
-       irel++;
-
-      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);
-           }
-       }
-
-      if (data_flag & CLEAN_PRE)
-       {
-         pre_off = 0;
-         pre_insn16 = 0;
-         pre_irel_ptr = NULL;
-       }
-      if (data_flag & DATA_EXIST)
-       {
-         /* We save the move offset in the highest byte.  */
-         off += (data_flag >> 24);
-         continue;
-       }
-
-      if (*(contents + off) & 0x80)
-       {
-         /* 2-byte instruction.  */
-         off += 2;
-         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;
-
-         if (irel != NULL && irel < irelend && irel->r_offset == off)
-           {
-             /* Insn with relocation.  */
-             nds32_elf_get_insn_with_reg (irel, insn, &insn_with_reg);
-
-             if (ex9_insn->irel != NULL)
-                 nds32_elf_get_insn_with_reg (ex9_insn->irel, it_insn, &it_insn_with_reg);
-
-             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;
-
-                         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;
-
-                         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;
-
-                         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-                         m_list = ex9_insn->m_list;
-
-                         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;
-                           }
-                       }
-                   }
-               }
-
-             /* 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;
-
-                     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;
-               }
-           }
-         else
-           {
-             /* Instruction without relocation, we only
-                have to compare their byte code.  */
-             if (insn == it_insn && ex9_insn->irel == NULL)
-               do_replace = 1;
-           }
-
-         /* Insntruction match so replacing the code here.  */
-         if (do_replace == 1)
-           {
-             /* 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)
-               {
-                 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;
+/* Insert a fag in ascending order.
+   If a fag of the same address already exists,
+   they are chained by relas array.  */
 
-             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;
-               }
-             else
-               pre_irel_ptr = NULL;
-             break;
-           }
-         ex9_insn = ex9_insn->next;
-       }
-      off += 4;
-    }
+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;
 
-  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);
-    }
+  for (iter = head;
+       iter->next && iter->next->addr <= addr;
+       iter = iter->next)
+    /* Find somewhere to insert.  */ ;
 
-  /* Delete the redundant code.  */
-  if (relax_blank_list)
+  /* `iter' will be equal to `head' if the list is empty.  */
+  if (iter != head && iter->addr == addr)
     {
-      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
-      relax_blank_list = NULL;
+      /* 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;
     }
 
-  /* Clear the relocation that is replaced by ex9.  */
-  while (irel_list)
-    {
-      struct elf_nds32_irel_entry *irel_ptr;
+  /* 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;
 
-      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);
-    }
-  return TRUE;
+  nds32_fag_verify (head);
 }
 
-/* Initialize ex9 hash table.  */
-
-int
-nds32_elf_ex9_init (void)
+static void
+nds32_fag_free_list (struct nds32_fag *head)
 {
-  if (!bfd_hash_table_init_n (&ex9_code_table, nds32_elf_code_hash_newfunc,
-                             sizeof (struct elf_nds32_code_hash_entry),
-                             1023))
+  struct nds32_fag *iter;
+
+  iter = head->next;
+  while (iter)
     {
-      (*_bfd_error_handler) (_("Linker: cannot init ex9 hash table error \n"));
-      return FALSE;
+      struct nds32_fag *tmp = iter;
+      iter = iter->next;
+      free (tmp->relas);
+      tmp->relas = NULL;
+      free (tmp);
     }
-  return TRUE;
 }
 
-/* Predict how many bytes will be relaxed with ex9 and ifc.  */
+/* 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.
 
-static void
-nds32_elf_ex9_total_relax (struct bfd_link_info *info)
+   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 elf_nds32_insn_times_entry *ex9_insn;
-  struct elf_nds32_insn_times_entry *temp;
-  int target_optimize;
-  struct elf_nds32_link_hash_table *table;
+  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.  */
 
-  if (ex9_insn_head == NULL)
-    return;
+  /* Use first fag for initial, and find the last fag in the window.
 
-  table = nds32_elf_hash_table (info);
-  target_optimize  = table->target_optimize;
-  ex9_insn = ex9_insn_head;
-  while (ex9_insn)
+     In each iteration, we could simply subtract previous fag
+     and accumulate following fags which are inside the window,
+     untill we each the end.  */
+
+  if (head->next == NULL)
     {
-      ex9_relax_size = ex9_insn->times * 2 + ex9_relax_size;
-      temp = ex9_insn;
-      ex9_insn = ex9_insn->next;
-      free (temp);
+      *bestpp = NULL;
+      return 0;
     }
-  ex9_insn_head = NULL;
 
-  if ((target_optimize & NDS32_RELAX_JUMP_IFC_ON))
+  /* 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)
     {
-      /* 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;
+      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;
 
-      while (ifc_ent)
+      /* A better fp-base?  */
+      if (accu > baccu)
        {
-         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;
+         best = base;
+         baccu = accu;
        }
-      ex9_relax_size += size;
     }
+
+  if (bestpp)
+    *bestpp = best;
+  return baccu;
 }
 
-/* Finish ex9 table.  */
+/* 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.  */
 
-void
-nds32_elf_ex9_finish (struct bfd_link_info *link_info)
+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 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;
-}
+  struct nds32_fag *ifag;
+  bfd_vma best_fpbase, gp;
+  bfd *output_bfd;
 
-/* Relocate the entries in ex9 table.  */
+  output_bfd = abfd->sections->output_section->owner;
+  nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
+  best_fpbase = best_fag->addr;
 
-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;
+  if (best_fpbase > gp + sdata_range[1][1]
+      || best_fpbase < gp - sdata_range[1][0])
+    return FALSE;
 
-  if (ptr->m_list != NULL)
+  /* 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)
     {
-      /* 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))
+      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);
 
-         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;
+         if (insn16_rel != irelend)
+           insn16_rel->r_addend = R_NDS32_INSN16_FP7U2_FLAG;
        }
-      else
-       relocation = 0;
     }
-  else if (ptr->sec !=NULL)
-    {
-      /* 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;
+  return TRUE;
+}
 
-      if (!nds32_get_local_syms (abfd, sec, &isym))
-       return FALSE;
-      isym = isym + ELF32_R_SYM (ptr->irel->r_info);
+/* Reset INSN16 to clean fp as gp.  */
 
-      sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
-      if (sec != NULL)
-       *isec_ptr = *sec;
-      sym = *isym;
+static void
+nds32_fag_unmark_relax (struct nds32_fag *fag,
+                       Elf_Internal_Rela *internal_relocs,
+                       Elf_Internal_Rela *irelend)
+{
+  struct nds32_fag *ifag;
+  int i;
+  Elf_Internal_Rela *insn16_rel;
+  Elf_Internal_Rela *fag_rel;
 
-      /* 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)
+  for (ifag = fag; ifag; ifag = ifag->next)
+    {
+      for (i = 0; i < ifag->count; i++)
        {
-         sym.st_value =
-           _bfd_merged_section_offset (ptr->sec->output_section->owner, &isec_ptr,
-                                       elf_section_data (isec_ptr)->sec_info,
-                                       isym->st_value);
-       }
-      relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, &sym,
-                                           &ptr->sec, ptr->irel);
-      if (ptr->irel != NULL)
-       relocation += ptr->irel->r_addend;
+         fag_rel = ifag->relas[i];
 
-      /* 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;
-    }
+         /* Restore the INSN16 relocation.  */
+         insn16_rel = find_relocs_at_address
+           (fag_rel, internal_relocs, irelend, R_NDS32_INSN16);
 
-  return relocation;
+         if (insn16_rel != irelend)
+           insn16_rel->r_addend &= ~R_NDS32_INSN16_FP7U2_FLAG;
+       }
+    }
 }
 
-/* Import ex9 table and build list.  */
+/* This is the main function of fp-as-gp optimization.
+   It should be called by relax_section.  */
 
-void
-nds32_elf_ex9_import_table (struct bfd_link_info *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,
+                     Elf_Internal_Sym *isymbuf)
 {
-  int count = 0, num = 1;
+  Elf_Internal_Rela *begin_rel = NULL;
+  Elf_Internal_Rela *irel;
+  struct nds32_fag fag_head;
+  Elf_Internal_Shdr *symtab_hdr;
   bfd_byte *contents;
-  unsigned long insn;
-  FILE *ex9_import_file;
-  int update_ex9_table;
-  struct elf_nds32_link_hash_table *table;
+  bfd_boolean ifc_inside = FALSE;
 
-  table = nds32_elf_hash_table (info);
-  ex9_import_file = table->ex9_import_file;
+  /* FIXME: Can we bfd_elf_link_read_relocs for the relocs?  */
 
-  contents = bfd_malloc (sizeof (bfd_byte) * 4);
+  /* 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.
 
-  /* 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)
+     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, TRUE)
+      || !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++)
     {
-      char *code;
-      struct elf_nds32_insn_times_entry *ptr;
-      size_t nread;
+      /* 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.  */
 
-      nread = fread (contents, sizeof (bfd_byte) * 4, 1, ex9_import_file);
-      if (nread < sizeof (bfd_byte) * 4)
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_RELAX_REGION_BEGIN
+         && (irel->r_addend & R_NDS32_RELAX_REGION_OMIT_FP_FLAG))
        {
-         (*_bfd_error_handler) ("Unexpected size of imported ex9 table.");
-         break;
+         /* Begin of the region.  */
+         if (begin_rel)
+           /* xgettext:c-format */
+           _bfd_error_handler (_("%pB: nested OMIT_FP in %pA"), abfd, sec);
+
+         begin_rel = irel;
+         nds32_fag_init (&fag_head);
+         ifc_inside = FALSE;
        }
-      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);
-    }
-}
+      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, *tmp_fag;
+         int dist;
 
-/* Export ex9 table.  */
+         /* End of the region.
+            Check whether it is worth to do fp-as-gp.  */
 
-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;
+         if (begin_rel == NULL)
+           {
+             /* xgettext:c-format */
+             _bfd_error_handler (_("%pB: unmatched OMIT_FP in %pA"),
+                                 abfd, sec);
+             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);
-}
+         accu = nds32_fag_find_base (&fag_head, &best_fag);
+
+         /* Clean FP7U2_FLAG because they may set ever.  */
+         tmp_fag = fag_head.next;
+         nds32_fag_unmark_relax (tmp_fag, internal_relocs, irelend);
 
-/* Adjust relocations of J and JAL in ex9.itable.
-   Export ex9 table.  */
+         /* 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;
+           }
 
-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;
+         /* 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;
 
-  table = nds32_elf_hash_table (link_info);
-  if (table)
-    table->relax_status |= NDS32_RELAX_EX9_DONE;
+         nds32_fag_free_list (&fag_head);
+         begin_rel = NULL;
+       }
 
+      if (begin_rel == NULL || ifc_inside)
+       /* Skip if we are not in the region of fp-as-gp.  */
+       continue;
 
-  update_ex9_table = table->update_ex9_table;
-  /* Generated ex9.itable exactly.  */
-  if (update_ex9_table == 0)
-    {
-      for (it_abfd = link_info->input_bfds; it_abfd != NULL;
-          it_abfd = it_abfd->link.next)
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA15S2_RELA
+         || ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA17S2_RELA)
        {
-         table_sec = bfd_get_section_by_name (it_abfd, ".ex9.itable");
-         if (table_sec != NULL)
-           break;
-       }
+         bfd_vma addr;
+         uint32_t insn;
 
-      if (table_sec != NULL)
-       {
-         bfd *output_bfd;
-         struct bfd_link_hash_entry *bh = NULL;
+         /* A gp-relative access is found.  Insert it to the fag-list.  */
 
-         output_bfd = table_sec->output_section->owner;
-         nds32_elf_final_sda_base (output_bfd, link_info, &gp, FALSE);
-         if (table_sec->size == 0)
-           return;
+         /* 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;
 
-         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;
+         addr = calculate_memory_address (abfd, irel, isymbuf, symtab_hdr);
+         nds32_fag_insert (&fag_head, addr, irel);
        }
-    }
-  else
-    {
-      /* Set gp.  */
-      bfd *output_bfd;
-
-      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);
-    }
-
-  /* Relocate instruction.  */
-  while (ex9_insn)
-    {
-      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)
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA_FP7U2_RELA)
        {
-         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))
-           {
-             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);
-           }
-         else if (ELF32_R_TYPE (rel_backup.r_info) == R_NDS32_HI20_RELA)
-           {
-             /* Sethi may be multiple entry for one insn.  */
-             if (ex9_insn->next && ((ex9_insn->m_list && ex9_insn->m_list == ex9_insn->next->m_list)
-                               || (ex9_insn->m_list && ex9_insn->next->order == 234
-                                   && ex9_insn->next->next
-                                   && ex9_insn->m_list == ex9_insn->next->next->m_list)))
-               {
-                 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;
-                           }
-
-                         /* 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;
-                   }
-               }
-             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);
-               }
-           }
+         begin_rel = NULL;
        }
-      else
+      else if (ELF32_R_TYPE (irel->r_info) == R_NDS32_17IFC_PCREL_RELA
+              || ELF32_R_TYPE (irel->r_info) == R_NDS32_10IFCU_PCREL_RELA)
        {
-         /* 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);
+         /* Suppress fp as gp when encounter ifc.  */
+         ifc_inside = TRUE;
        }
-      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);
-    }
+  return TRUE;
 }
 
-/* Generate ex9 hash table.  */
+/* Remove unused `la $fp, _FD_BASE_' instruction.  */
 
 static bfd_boolean
-nds32_elf_ex9_build_hash_table (bfd * abfd, asection * sec,
-                               struct bfd_link_info *link_info)
+nds32_fag_remove_unused_fpbase (bfd *abfd, asection *sec,
+                               Elf_Internal_Rela *internal_relocs,
+                               Elf_Internal_Rela *irelend)
 {
-  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;
+  nds32_elf_blank_t *relax_blank_list = NULL;
+  bfd_boolean result = TRUE;
+  bfd_boolean unused_region = FALSE;
 
-  sym_hashes = elf_sym_hashes (abfd);
-  /* Load section instructions, relocations, and symbol table.  */
-  if (!nds32_get_section_contents (abfd, sec, &contents))
-    return FALSE;
+  /*
+     NOTE: Disable fp-as-gp if we encounter ifcall relocations.
+     * R_NDS32_17IFC_PCREL_RELA
+     * R_NDS32_10IFCU_PCREL_RELA
+
+     CASE??????????????
+  */
 
-  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;
+  nds32_get_section_contents (abfd, sec, &contents, TRUE);
 
-  /* Check the object if enable ex9.  */
-  irel = find_relocs_at_address (internal_relocs, internal_relocs, irelend,
-                                R_NDS32_RELAX_ENTRY);
+  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;
 
-  /* 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;
+      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;
 
-  irel = internal_relocs;
+      /* We're not in the region.  */
+      if (!unused_region)
+       continue;
 
-  /* Push each insn into hash table.  */
-  while (off < sec->size)
-    {
-      char code[10];
-      struct elf_nds32_code_hash_entry *entry;
+      /* _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;
 
-      while (irel != NULL && irel < irelend && irel->r_offset < off)
-       irel++;
+      /* The symbol name must be _FP_BASE_.  */
+      syname = elf_sym_hashes (abfd)[syndx]->root.root.string;
+      if (strcmp (syname, FP_BASE_NAME) != 0)
+       continue;
 
-      data_flag = nds32_elf_ex9_relocation_check (link_info, &irel, irelend, NULL,
-                                                 sec, &off, contents);
-      if (data_flag & DATA_EXIST)
+      if (ELF32_R_TYPE (irel->r_info) == R_NDS32_SDA19S0_RELA)
        {
-         /* We save the move offset in the highest byte.  */
-         off += (data_flag >> 24);
-         continue;
+         /* addi.gp  $fp, -256  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (insn != INSN_ADDIGP_TO_FP)
+           continue;
        }
-
-      if (*(contents + off) & 0x80)
+      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)
        {
-         off += 2;
+         /* movi  $fp, FP_BASE  */
+         insn = bfd_getb32 (contents + irel->r_offset);
+         if (insn != INSN_MOVI_TO_FP)
+           continue;
        }
       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)
-           {
-             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))
-               {
-                 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;
+       continue;
 
-                     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
-                   {
-                     /* 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)
-                       {
-                         off += 4;
-                         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;
+    }
 
-                 /* 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)
-                       {
-                         off += 4;
-                         continue;
-                       }
+finish:
+  if (relax_blank_list)
+    {
+      nds32_elf_relax_delete_blanks (abfd, sec, relax_blank_list);
+      relax_blank_list = NULL;
+    }
+  return result;
 
-                     relocation -= gp;
+error_return:
+  result = FALSE;
+  goto finish;
+}
 
-                     /* 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;
-                       }
-                   }
+/* 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.  */
 
-                 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;
-               }
+static bfd_byte *
+nds32_elf_get_relocated_section_contents (bfd *abfd,
+                                         struct bfd_link_info *link_info,
+                                         struct bfd_link_order *link_order,
+                                         bfd_byte *data,
+                                         bfd_boolean relocatable,
+                                         asymbol **symbols)
+{
+  bfd *input_bfd = link_order->u.indirect.section->owner;
+  asection *input_section = link_order->u.indirect.section;
+  long reloc_size;
+  arelent **reloc_vector;
+  long reloc_count;
+
+  reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+  if (reloc_size < 0)
+    return NULL;
+
+  /* Read in the section.  */
+  if (!nds32_get_section_contents (input_bfd, input_section, &data, FALSE))
+    return NULL;
+
+  if (reloc_size == 0)
+    return data;
+
+  reloc_vector = (arelent **) bfd_malloc (reloc_size);
+  if (reloc_vector == NULL)
+    return NULL;
+
+  reloc_count = bfd_canonicalize_reloc (input_bfd, input_section,
+                                       reloc_vector, symbols);
+  if (reloc_count < 0)
+    goto error_return;
+
+  if (reloc_count > 0)
+    {
+      arelent **parent;
+      for (parent = reloc_vector; *parent != NULL; parent++)
+       {
+         char *error_message = NULL;
+         asymbol *symbol;
+         bfd_reloc_status_type r;
+
+         symbol = *(*parent)->sym_ptr_ptr;
+         if (symbol->section && discarded_section (symbol->section))
+           {
+             bfd_byte *p;
+             static reloc_howto_type none_howto
+               = HOWTO (0, 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL,
+                        "unused", FALSE, 0, 0, FALSE);
+
+             p = data + (*parent)->address * bfd_octets_per_byte (input_bfd);
+             _bfd_clear_contents ((*parent)->howto, input_bfd, input_section,
+                                  p);
+             (*parent)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+             (*parent)->addend = 0;
+             (*parent)->howto = &none_howto;
+             r = bfd_reloc_ok;
            }
+         else
+           r = bfd_perform_relocation (input_bfd, *parent, data,
+                                       input_section,
+                                       relocatable ? abfd : NULL,
+                                       &error_message);
 
-         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)
+         if (relocatable)
            {
-             (*_bfd_error_handler)
-               (_("%P%F: failed creating ex9.it %s hash table: %E\n"), code);
-             return FALSE;
+             asection *os = input_section->output_section;
+
+             /* A partial link, so keep the relocs.  */
+             os->orelocation[os->reloc_count] = *parent;
+             os->reloc_count++;
            }
-         if (h)
+
+         if (r != bfd_reloc_ok)
            {
-             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)
+             switch (r)
                {
-                 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;
+               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;
 
-                 while (m_list)
-                   {
-                     /* 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)
-                       {
-                         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;
-                           }
-                         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)
-                       {
-                         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;
-                         break;
-                       }
-                     m_list = m_list->next;
-                   }
-                 if (!m_list)
-                   {
-                     off += 4;
-                     continue;
-                   }
+               default:
+                 abort ();
+                 break;
                }
            }
-         else
-           {
-             /* Local symbol and insn without relocation*/
-             entry->times++;
-             entry->rel_backup = rel_backup;
-           }
-
-         /* 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;
        }
     }
-  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;
 
-  if (is_ITB_BASE_set == 1)
-    return TRUE;
-
-  is_ITB_BASE_set = 1;
-
-  table = nds32_elf_hash_table (link_info);
-  target_optimize  = table->target_optimize;
+  free (reloc_vector);
+  return data;
 
-  for (abfd = link_info->input_bfds; abfd != NULL;
-       abfd = abfd->link.next)
-    {
-      sec = bfd_get_section_by_name (abfd, ".ex9.itable");
-      if (sec != NULL)
-       {
-         output_bfd = sec->output_section->owner;
-         break;
-       }
-    }
-  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  */
+error_return:
+  free (reloc_vector);
+  return NULL;
+}
 \f
 
 #define ELF_ARCH                               bfd_arch_nds32
 #define ELF_MACHINE_CODE                       EM_NDS32
 #define ELF_MAXPAGESIZE                                0x1000
+#define ELF_TARGET_ID                          NDS32_ELF_DATA
 
 #define TARGET_BIG_SYM                         nds32_elf32_be_vec
 #define TARGET_BIG_NAME                                "elf32-nds32be"
@@ -14221,6 +12679,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 +12690,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 +12699,8 @@ nds32_elf_ex9_itb_base (struct bfd_link_info *link_info)
 #define elf_backend_object_p                   nds32_elf_object_p
 #define elf_backend_final_write_processing     nds32_elf_final_write_processing
 #define elf_backend_special_sections           nds32_elf_special_sections
+#define bfd_elf32_bfd_get_relocated_section_contents \
+                               nds32_elf_get_relocated_section_contents
 
 #define elf_backend_can_gc_sections            1
 #define elf_backend_can_refcount               1
@@ -14251,6 +12711,7 @@ 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         1
 
 #include "elf32-target.h"
 
This page took 0.165035 seconds and 4 git commands to generate.