bfd: Add supported for LoongArch new relocations.
authorliuzhensong <liuzhensong@loongson.cn>
Mon, 11 Jul 2022 07:11:03 +0000 (15:11 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Mon, 25 Jul 2022 01:59:08 +0000 (09:59 +0800)
  Define new reloc types according to linker needs.

  include/elf/
    loongarch.h

  bfd/
    bfd-in2.h
    libbfd.h
    reloc.c
    elfnn-loongarch.c
    elfxx-loongarch.c
    elfxx-loongarch.h

bfd/bfd-in2.h
bfd/elfnn-loongarch.c
bfd/elfxx-loongarch.c
bfd/elfxx-loongarch.h
bfd/libbfd.h
bfd/reloc.c
include/elf/loongarch.h

index 4e1182e93d417807a8eee936a7e15ba4dd43bbc1..91e6ad76b9a3825371f6aa5ead9843c4bbf33b60 100644 (file)
@@ -6274,6 +6274,42 @@ assembler and not (currently) written to any object files.  */
   BFD_RELOC_LARCH_SUB24,
   BFD_RELOC_LARCH_SUB32,
   BFD_RELOC_LARCH_SUB64,
+  BFD_RELOC_LARCH_B16,
+  BFD_RELOC_LARCH_B21,
+  BFD_RELOC_LARCH_B26,
+  BFD_RELOC_LARCH_ABS_HI20,
+  BFD_RELOC_LARCH_ABS_LO12,
+  BFD_RELOC_LARCH_ABS64_LO20,
+  BFD_RELOC_LARCH_ABS64_HI12,
+  BFD_RELOC_LARCH_PCALA_HI20,
+  BFD_RELOC_LARCH_PCALA_LO12,
+  BFD_RELOC_LARCH_PCALA64_LO20,
+  BFD_RELOC_LARCH_PCALA64_HI12,
+  BFD_RELOC_LARCH_GOT_PC_HI20,
+  BFD_RELOC_LARCH_GOT_PC_LO12,
+  BFD_RELOC_LARCH_GOT64_PC_LO20,
+  BFD_RELOC_LARCH_GOT64_PC_HI12,
+  BFD_RELOC_LARCH_GOT_HI20,
+  BFD_RELOC_LARCH_GOT_LO12,
+  BFD_RELOC_LARCH_GOT64_LO20,
+  BFD_RELOC_LARCH_GOT64_HI12,
+  BFD_RELOC_LARCH_TLS_LE_HI20,
+  BFD_RELOC_LARCH_TLS_LE_LO12,
+  BFD_RELOC_LARCH_TLS_LE64_LO20,
+  BFD_RELOC_LARCH_TLS_LE64_HI12,
+  BFD_RELOC_LARCH_TLS_IE_PC_HI20,
+  BFD_RELOC_LARCH_TLS_IE_PC_LO12,
+  BFD_RELOC_LARCH_TLS_IE64_PC_LO20,
+  BFD_RELOC_LARCH_TLS_IE64_PC_HI12,
+  BFD_RELOC_LARCH_TLS_IE_HI20,
+  BFD_RELOC_LARCH_TLS_IE_LO12,
+  BFD_RELOC_LARCH_TLS_IE64_LO20,
+  BFD_RELOC_LARCH_TLS_IE64_HI12,
+  BFD_RELOC_LARCH_TLS_LD_PC_HI20,
+  BFD_RELOC_LARCH_TLS_LD_HI20,
+  BFD_RELOC_LARCH_TLS_GD_PC_HI20,
+  BFD_RELOC_LARCH_TLS_GD_HI20,
+  BFD_RELOC_LARCH_RELAX,
   BFD_RELOC_UNUSED };
 
 typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
index 5b44901b9e098e86e4c5a0faa86c84ffa2c42612..21710dcb3fbddea58bd2d6353f039b0863632e30 100644 (file)
@@ -122,14 +122,16 @@ struct loongarch_elf_link_hash_table
 
 #define elf_backend_plt_readonly 1
 
-#define elf_backend_want_plt_sym 0
+#define elf_backend_want_plt_sym 1
 #define elf_backend_plt_alignment 4
 #define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
 #define elf_backend_want_got_sym 1
 
 #define elf_backend_got_header_size (GOT_ENTRY_SIZE * 1)
 
 #define elf_backend_want_dynrelro 1
+#define elf_backend_rela_normal 1
 
 /* Generate a PLT header.  */
 
@@ -607,9 +609,6 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       struct elf_link_hash_entry *h;
       Elf_Internal_Sym *isym = NULL;
 
-      int need_dynreloc;
-      int only_need_pcrel;
-
       r_symndx = ELFNN_R_SYM (rel->r_info);
       r_type = ELFNN_R_TYPE (rel->r_info);
 
@@ -622,7 +621,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (r_symndx < symtab_hdr->sh_info)
        {
          /* A local symbol.  */
-         isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx);
+         isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
          if (isym == NULL)
            return false;
 
@@ -655,17 +654,20 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (htab->elf.dynobj == NULL)
            htab->elf.dynobj = abfd;
 
+         /* Create 'irelifunc' in PIC object.  */
+         if (bfd_link_pic (info)
+             && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
+           return false;
+         /* If '.plt' not represent, create '.iplt' to deal with ifunc.  */
+         else if (!htab->elf.splt
+                  && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
+           return false;
          /* Create the ifunc sections, iplt and ipltgot, for static
             executables.  */
          if ((r_type == R_LARCH_64 || r_type == R_LARCH_32)
              && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
            return false;
 
-         if (!htab->elf.splt
-             && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
-           /* If '.plt' not represent, create '.iplt' to deal with ifunc.  */
-           return false;
-
          if (h->plt.refcount < 0)
            h->plt.refcount = 0;
          h->plt.refcount++;
@@ -674,17 +676,27 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          elf_tdata (info->output_bfd)->has_gnu_osabi |= elf_gnu_osabi_ifunc;
        }
 
-      need_dynreloc = 0;
-      only_need_pcrel = 0;
+      int need_dynreloc = 0;
+      int only_need_pcrel = 0;
+
       switch (r_type)
        {
+       case R_LARCH_GOT_PC_HI20:
+       case R_LARCH_GOT_HI20:
        case R_LARCH_SOP_PUSH_GPREL:
+         /* For la.global.  */
+         if (h)
+           h->pointer_equality_needed = 1;
          if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
                                                           r_symndx,
                                                           GOT_NORMAL))
            return false;
          break;
 
+       case R_LARCH_TLS_LD_PC_HI20:
+       case R_LARCH_TLS_LD_HI20:
+       case R_LARCH_TLS_GD_PC_HI20:
+       case R_LARCH_TLS_GD_HI20:
        case R_LARCH_SOP_PUSH_TLS_GD:
          if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
                                                           r_symndx,
@@ -692,6 +704,8 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return false;
          break;
 
+       case R_LARCH_TLS_IE_PC_HI20:
+       case R_LARCH_TLS_IE_HI20:
        case R_LARCH_SOP_PUSH_TLS_GOT:
          if (bfd_link_pic (info))
            /* May fail for lazy-bind.  */
@@ -703,6 +717,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return false;
          break;
 
+       case R_LARCH_TLS_LE_HI20:
        case R_LARCH_SOP_PUSH_TLS_TPREL:
          if (!bfd_link_executable (info))
            return false;
@@ -715,6 +730,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            return false;
          break;
 
+       case R_LARCH_ABS_HI20:
        case R_LARCH_SOP_PUSH_ABSOLUTE:
          if (h != NULL)
            /* If this reloc is in a read-only section, we might
@@ -726,16 +742,45 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            h->non_got_ref = 1;
          break;
 
-       case R_LARCH_SOP_PUSH_PCREL:
+       case R_LARCH_PCALA_HI20:
          if (h != NULL)
            {
              h->non_got_ref = 1;
+             h->pointer_equality_needed = 1;
+           }
+
+         break;
+
+       case R_LARCH_B21:
+       case R_LARCH_B16:
+       case R_LARCH_B26:
+         if (h != NULL)
+           {
+             h->needs_plt = 1;
+             if (!bfd_link_pic (info))
+               h->non_got_ref = 1;
+
+             /* We try to create PLT stub for all non-local function.  */
+             if (h->plt.refcount < 0)
+               h->plt.refcount = 0;
+             h->plt.refcount++;
+           }
+
+         break;
+
+       case R_LARCH_SOP_PUSH_PCREL:
+         if (h != NULL)
+           {
+             if (!bfd_link_pic (info))
+               h->non_got_ref = 1;
 
              /* We try to create PLT stub for all non-local function.  */
              if (h->plt.refcount < 0)
                h->plt.refcount = 0;
              h->plt.refcount++;
+             h->pointer_equality_needed = 1;
            }
+
          break;
 
        case R_LARCH_SOP_PUSH_PLT_PCREL:
@@ -762,6 +807,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_LARCH_JUMP_SLOT:
        case R_LARCH_32:
        case R_LARCH_64:
+
          need_dynreloc = 1;
 
          /* If resolved symbol is defined in this object,
@@ -774,9 +820,6 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             Thus, only under pde, it needs pcrel only.  We discard it.  */
          only_need_pcrel = bfd_link_pde (info);
 
-         if (h != NULL)
-           h->non_got_ref = 1;
-
          if (h != NULL
              && (!bfd_link_pic (info)
                  || h->type == STT_GNU_IFUNC))
@@ -899,9 +942,7 @@ loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                     struct elf_link_hash_entry *h)
 {
   struct loongarch_elf_link_hash_table *htab;
-  struct loongarch_elf_link_hash_entry *eh;
   bfd *dynobj;
-  asection *s, *srel;
 
   htab = loongarch_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
@@ -951,73 +992,9 @@ loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       return true;
     }
 
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
-
-  /* If we are creating a shared library, we must presume that the
-     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 (bfd_link_dll (info))
-    return true;
-
-  /* If there are no references to this symbol that do not use the
-     GOT, we don't need to generate a copy reloc.  */
-  if (!h->non_got_ref)
-    return true;
-
-  /* If -z nocopyreloc was given, we won't generate them either.  */
-  if (info->nocopyreloc)
-    {
-      h->non_got_ref = 0;
-      return true;
-    }
-
-  /* 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 (!readonly_dynrelocs (h))
-    {
-      h->non_got_ref = 0;
-      return true;
-    }
-
-  /* We must allocate the symbol in our .dynbss section, which will
-     become part of the .bss section of the executable.  There will be
-     an entry for this symbol in the .dynsym section.  The dynamic
-     object will contain position independent code, so all references
-     from the dynamic object to this symbol will go through the global
-     offset table.  The dynamic linker will use the .dynsym entry to
-     determine the address it must put in the global offset table, so
-     both the dynamic object and the regular object will refer to the
-     same memory location for the variable.  */
-
-  /* We must generate a R_LARCH_COPY reloc to tell the dynamic linker
-     to copy the initial value out of the dynamic object and into the
-     runtime process image.  We need to remember the offset into the
-     .rel.bss section we are going to use.  */
-  eh = (struct loongarch_elf_link_hash_entry *) h;
-  if (eh->tls_type & ~GOT_NORMAL)
-    {
-      s = htab->sdyntdata;
-      srel = htab->elf.srelbss;
-    }
-  else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
-    {
-      s = htab->elf.sdynrelro;
-      srel = htab->elf.sreldynrelro;
-    }
-  else
-    {
-      s = htab->elf.sdynbss;
-      srel = htab->elf.srelbss;
-    }
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
-    {
-      srel->size += sizeof (ElfNN_External_Rela);
-      h->needs_copy = 1;
-    }
-
-  return _bfd_elf_adjust_dynamic_copy (info, h, s);
+  /* R_LARCH_COPY is not adept glibc, not to generate.  */
+  /* Can not print anything, because make check ld.  */
+  return true;
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
@@ -1039,6 +1016,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
   info = (struct bfd_link_info *) inf;
   htab = loongarch_elf_hash_table (info);
+  bool dyn = htab->elf.dynamic_sections_created;
   BFD_ASSERT (htab != NULL);
 
   do
@@ -1052,9 +1030,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
       if (htab->elf.splt)
        {
-         if (h->dynindx == -1 && !h->forced_local
-             && !bfd_elf_link_record_dynamic_symbol (info, h))
-           return false;
+         if (h->dynindx == -1 && !h->forced_local && dyn
+             && h->root.type == bfd_link_hash_undefweak)
+           {
+             if (!bfd_elf_link_record_dynamic_symbol (info, h))
+               return false;
+           }
 
          if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)
              && h->type != STT_GNU_IFUNC)
@@ -1090,7 +1071,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 (!bfd_link_pic(info)
+      if (!bfd_link_pic (info)
          && !h->def_regular)
        {
          h->root.u.def.section = plt;
@@ -1107,51 +1088,68 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (0 < h->got.refcount)
     {
       asection *s;
-      bool dyn;
       int tls_type = loongarch_elf_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.  */
-      if (h->dynindx == -1 && !h->forced_local)
+      if (h->dynindx == -1 && !h->forced_local && dyn
+         && h->root.type == bfd_link_hash_undefweak)
        {
-         if (SYMBOL_REFERENCES_LOCAL (info, h)
-             && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-             && h->start_stop)
-           {
-             /* The pr21964-4. do nothing.  */
-           }
-         else
-           {
-             if( !bfd_elf_link_record_dynamic_symbol (info, h))
-               return false;
-           }
+         if (!bfd_elf_link_record_dynamic_symbol (info, h))
+           return false;
        }
 
       s = htab->elf.sgot;
       h->got.offset = s->size;
-      dyn = htab->elf.dynamic_sections_created;
       if (tls_type & (GOT_TLS_GD | GOT_TLS_IE))
        {
          /* TLS_GD needs two dynamic relocs and two GOT slots.  */
          if (tls_type & GOT_TLS_GD)
            {
              s->size += 2 * GOT_ENTRY_SIZE;
-             htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
+             if (bfd_link_executable (info))
+               {
+                 /* Link exe and not defined local.  */
+                 if (!SYMBOL_REFERENCES_LOCAL (info, h))
+                   htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
+               }
+             else
+               {
+                 if (SYMBOL_REFERENCES_LOCAL (info, h))
+                   htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
+                 else
+                   htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
+               }
            }
 
          /* TLS_IE needs one dynamic reloc and one GOT slot.  */
          if (tls_type & GOT_TLS_IE)
            {
              s->size += GOT_ENTRY_SIZE;
-             htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
+
+             if (bfd_link_executable (info))
+               {
+                 /* Link exe and not defined local.  */
+                 if (!SYMBOL_REFERENCES_LOCAL (info, h))
+                   htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
+               }
+             else
+               {
+                 htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
+               }
            }
        }
       else
        {
          s->size += GOT_ENTRY_SIZE;
-         if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
-              && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
-             || h->type == STT_GNU_IFUNC)
+         if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+              || h->root.type != bfd_link_hash_undefweak)
+             && (bfd_link_pic (info)
+                 || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
+                                                     h))
+             && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+             /* Undefined weak symbol in static PIE resolves to 0 without
+                any dynamic relocations.  */
            htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
        }
     }
@@ -1161,7 +1159,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (h->dyn_relocs == NULL)
     return true;
 
-  if (SYMBOL_REFERENCES_LOCAL (info, h))
+  /* Extra dynamic relocate,
+   * R_LARCH_64
+   * R_LARCH_TLS_DTPRELNN
+   * R_LARCH_JUMP_SLOT
+   * R_LARCH_NN.  */
+
+  if (SYMBOL_CALLS_LOCAL (info, h))
     {
       struct elf_dyn_relocs **pp;
 
@@ -1178,13 +1182,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
   if (h->root.type == bfd_link_hash_undefweak)
     {
-      if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+      if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
+         || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+         || (!bfd_link_pic (info) && h->non_got_ref))
        h->dyn_relocs = NULL;
-      else if (h->dynindx == -1 && !h->forced_local
-              /* Make sure this symbol is output as a dynamic symbol.
-                 Undefined weak syms won't yet be marked as dynamic.  */
-              && !bfd_elf_link_record_dynamic_symbol (info, h))
-       return false;
+      else if (h->dynindx == -1 && !h->forced_local)
+       {
+         /* Make sure this symbol is output as a dynamic symbol.
+            Undefined weak syms won't yet be marked as dynamic.  */
+         if (!bfd_elf_link_record_dynamic_symbol (info, h))
+           return false;
+
+         if (h->dynindx == -1)
+           h->dyn_relocs = NULL;
+       }
     }
 
   for (p = h->dyn_relocs; p != NULL; p = p->next)
@@ -1200,8 +1211,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
    ifunc dynamic relocs.  */
 
 static bool
-elfNN_loongarch_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
-                                         void *inf)
+elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   /* An example of a bfd_link_hash_indirect symbol is versioned
@@ -1223,14 +1233,14 @@ elfNN_loongarch_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
 
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
      here if it is defined and referenced in a non-shared object.  */
-  if (h->type == STT_GNU_IFUNC
-      && h->def_regular)
+  if (h->type == STT_GNU_IFUNC && h->def_regular)
     return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
                                               &h->dyn_relocs,
                                               PLT_ENTRY_SIZE,
                                               PLT_HEADER_SIZE,
                                               GOT_ENTRY_SIZE,
                                               false);
+
   return true;
 }
 
@@ -1238,7 +1248,7 @@ elfNN_loongarch_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
    ifunc dynamic relocs.  */
 
 static bool
-elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
+elfNN_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
 {
   struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
 
@@ -1249,7 +1259,7 @@ elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
       || h->root.type != bfd_link_hash_defined)
     abort ();
 
-  return elfNN_loongarch_allocate_ifunc_dynrelocs (h, inf);
+  return elfNN_allocate_ifunc_dynrelocs (h, inf);
 }
 
 /* Set DF_TEXTREL if we find any dynamic relocs that apply to
@@ -1367,16 +1377,21 @@ loongarch_elf_size_dynamic_sections (bfd *output_bfd,
          if (0 < *local_got)
            {
              *local_got = s->size;
-             s->size += GOT_ENTRY_SIZE;
 
+             /* TLS gd use two got.  */
              if (*local_tls_type & GOT_TLS_GD)
+               s->size += GOT_ENTRY_SIZE * 2;
+             else
+               /* Normal got, tls ie/ld use one got.  */
                s->size += GOT_ENTRY_SIZE;
 
-             /* If R_LARCH_RELATIVE.  */
-             if (bfd_link_pic (info)
-                 /* Or R_LARCH_TLS_DTPRELNN or R_LARCH_TLS_TPRELNN.  */
-                 || (*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)))
-               srel->size += sizeof (ElfNN_External_Rela);
+             if (bfd_link_executable (info)
+                 && (*local_tls_type & (GOT_TLS_GD| GOT_TLS_IE)))
+               ;/* Do nothing.  */
+             else
+               {
+                 srel->size += sizeof (ElfNN_External_Rela);
+               }
            }
          else
            *local_got = MINUS_ONE;
@@ -1389,11 +1404,11 @@ loongarch_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* Allocate global ifunc sym .plt and .got entries, and space for global
      ifunc sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elfNN_loongarch_allocate_ifunc_dynrelocs, info);
+  elf_link_hash_traverse (&htab->elf, elfNN_allocate_ifunc_dynrelocs, info);
 
   /* Allocate .plt and .got entries, and space for local ifunc symbols.  */
   htab_traverse (htab->loc_hash_table,
-                (void *) elfNN_loongarch_allocate_local_dynrelocs, info);
+                (void *) elfNN_allocate_local_ifunc_dynrelocs, info);
 
   /* Don't allocate .got.plt section if there are no PLT.  */
   if (htab->elf.sgotplt && htab->elf.sgotplt->size == GOTPLT_HEADER_SIZE
@@ -1542,10 +1557,13 @@ loongarch_top (int64_t *val)
 static void
 loongarch_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
 {
+  BFD_ASSERT (s && s->contents);
   const struct elf_backend_data *bed;
   bfd_byte *loc;
 
   bed = get_elf_backend_data (abfd);
+  if (!(s->size > s->reloc_count * bed->s->sizeof_rela))
+    BFD_ASSERT (s->size > s->reloc_count * bed->s->sizeof_rela);
   loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela);
   bed->s->swap_reloca_out (abfd, rel, loc);
 }
@@ -1594,19 +1612,15 @@ loongarch_reloc_rewrite_imm_insn (const Elf_Internal_Rela *rel,
   return bfd_reloc_ok;
 }
 
-/* Emplace a static relocation.  */
-
 static bfd_reloc_status_type
 perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
                    reloc_howto_type *howto, bfd_vma value,
                    bfd *input_bfd, bfd_byte *contents)
 {
-  uint32_t insn1;
   int64_t opr1, opr2, opr3;
   bfd_reloc_status_type r = bfd_reloc_ok;
   int bits = bfd_get_reloc_size (howto) * 8;
 
-
   switch (ELFNN_R_TYPE (rel->r_info))
     {
     case R_LARCH_SOP_PUSH_PCREL:
@@ -1679,6 +1693,8 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
     case R_LARCH_SOP_POP_32_S_10_12:
     case R_LARCH_SOP_POP_32_S_10_16:
     case R_LARCH_SOP_POP_32_S_10_16_S2:
+    case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
+    case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
     case R_LARCH_SOP_POP_32_S_5_20:
     case R_LARCH_SOP_POP_32_U_10_12:
     case R_LARCH_SOP_POP_32_U:
@@ -1694,67 +1710,6 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
                                            contents, (bfd_vma)opr1);
       break;
 
-    case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
-       {
-         r = loongarch_pop (&opr1);
-         if (r != bfd_reloc_ok)
-           break;
-
-         if ((opr1 & 0x3) != 0)
-           {
-             r = bfd_reloc_overflow;
-             break;
-           }
-
-         uint32_t imm = opr1 >> howto->rightshift;
-         if ((imm & (~0xfffffU)) && ((imm & (~0xfffffU)) != (~0xfffffU)))
-           {
-             r = bfd_reloc_overflow;
-             break;
-           }
-         r = loongarch_check_offset (rel, input_section);
-         if (r != bfd_reloc_ok)
-           break;
-
-         insn1 = bfd_get (bits, input_bfd, contents + rel->r_offset);
-         insn1 = (insn1 & howto->src_mask)
-           | ((imm & 0xffffU) << 10)
-           | ((imm & 0x1f0000U) >> 16);
-         bfd_put (bits, input_bfd, insn1, contents + rel->r_offset);
-         break;
-       }
-
-    case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
-      {
-       r = loongarch_pop (&opr1);
-       if (r != bfd_reloc_ok)
-         break;
-
-       if ((opr1 & 0x3) != 0)
-         {
-           r = bfd_reloc_overflow;
-           break;
-         }
-
-       uint32_t imm = opr1 >> howto->rightshift;
-       if ((imm & (~0x1ffffffU)) && (imm & (~0x1ffffffU)) != (~0x1ffffffU))
-         {
-           r = bfd_reloc_overflow;
-           break;
-         }
-
-       r = loongarch_check_offset (rel, input_section);
-       if (r != bfd_reloc_ok)
-         break;
-
-       insn1 = bfd_get (bits, input_bfd, contents + rel->r_offset);
-       insn1 = ((insn1 & howto->src_mask)
-                | ((imm & 0xffffU) << 10)
-                | ((imm & 0x3ff0000U) >> 16));
-       bfd_put (bits, input_bfd, insn1, contents + rel->r_offset);
-       break;
-      }
-
     case R_LARCH_TLS_DTPREL32:
     case R_LARCH_32:
     case R_LARCH_TLS_DTPREL64:
@@ -1792,6 +1747,55 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
       bfd_put (bits, input_bfd, opr1 - value, contents + rel->r_offset);
       break;
 
+    /* New reloc type.
+       R_LARCH_B16 ~ R_LARCH_TLS_GD_HI20.  */
+    case R_LARCH_B16:
+    case R_LARCH_B21:
+    case R_LARCH_B26:
+    case R_LARCH_ABS_HI20:
+    case R_LARCH_ABS_LO12:
+    case R_LARCH_ABS64_LO20:
+    case R_LARCH_ABS64_HI12:
+    case R_LARCH_PCALA_HI20:
+    case R_LARCH_PCALA_LO12:
+    case R_LARCH_PCALA64_LO20:
+    case R_LARCH_PCALA64_HI12:
+    case R_LARCH_GOT_PC_HI20:
+    case R_LARCH_GOT_PC_LO12:
+    case R_LARCH_GOT64_PC_LO20:
+    case R_LARCH_GOT64_PC_HI12:
+    case R_LARCH_GOT_HI20:
+    case R_LARCH_GOT_LO12:
+    case R_LARCH_GOT64_LO20:
+    case R_LARCH_GOT64_HI12:
+    case R_LARCH_TLS_LE_HI20:
+    case R_LARCH_TLS_LE_LO12:
+    case R_LARCH_TLS_LE64_LO20:
+    case R_LARCH_TLS_LE64_HI12:
+    case R_LARCH_TLS_IE_PC_HI20:
+    case R_LARCH_TLS_IE_PC_LO12:
+    case R_LARCH_TLS_IE64_PC_LO20:
+    case R_LARCH_TLS_IE64_PC_HI12:
+    case R_LARCH_TLS_IE_HI20:
+    case R_LARCH_TLS_IE_LO12:
+    case R_LARCH_TLS_IE64_LO20:
+    case R_LARCH_TLS_IE64_HI12:
+    case R_LARCH_TLS_LD_PC_HI20:
+    case R_LARCH_TLS_LD_HI20:
+    case R_LARCH_TLS_GD_PC_HI20:
+    case R_LARCH_TLS_GD_HI20:
+      r = loongarch_check_offset (rel, input_section);
+      if (r != bfd_reloc_ok)
+       break;
+
+      r = loongarch_reloc_rewrite_imm_insn (rel, input_section,
+                                           howto, input_bfd,
+                                           contents, value);
+      break;
+
+    case R_LARCH_RELAX:
+      break;
+
     default:
       r = bfd_reloc_notsupported;
     }
@@ -1900,7 +1904,6 @@ loongarch_dump_reloc_record (void (*p) (const char *fmt, ...))
      "-- Record dump end --\n\n");
 }
 
-
 static bool
 loongarch_reloc_is_fatal (struct bfd_link_info *info,
                          bfd *input_bfd,
@@ -1945,8 +1948,27 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
   return fatal;
 }
 
-
-
+#define RELOCATE_CALC_PC32_HI20(relocation, pc)        \
+  ({                                                   \
+    bfd_vma lo = (relocation) & ((bfd_vma)0xfff);      \
+    pc = pc & (~(bfd_vma)0xfff);                       \
+    if (lo > 0x7ff)                                    \
+      {                                                        \
+       relocation += 0x1000;                           \
+      }                                                \
+    relocation &= ~(bfd_vma)0xfff;                     \
+    relocation -= pc;                                  \
+  })
+
+#define RELOCATE_CALC_PC64_HI32(relocation, pc)        \
+  ({                                                   \
+    bfd_vma lo = (relocation) & ((bfd_vma)0xfff);      \
+    if (lo > 0x7ff)                                    \
+      {                                                \
+       relocation -= 0x100000000;                      \
+      }                                                \
+    relocation -= (pc & ~(bfd_vma)0xffffffff);         \
+  })
 
 static int
 loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
@@ -1983,8 +2005,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       bool is_ie, is_undefweak, unresolved_reloc, defined_local;
       bool resolved_local, resolved_dynly, resolved_to_const;
       char tls_type;
-      bfd_vma relocation;
-      bfd_vma off, ie_off;
+      bfd_vma relocation, off, ie_off;
       int i, j;
 
       howto = loongarch_elf_rtype_to_howto (input_bfd, r_type);
@@ -2018,9 +2039,12 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          resolved_local = true;
          resolved_dynly = false;
          resolved_to_const = false;
+
+         /* Calc in funtion elf_link_input_bfd,
+          * if #define elf_backend_rela_normal to 1.  */
          if (bfd_link_relocatable (info)
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-           rel->r_addend += sec->output_offset;
+           continue;
        }
       else
        {
@@ -2092,7 +2116,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          resolved_to_const = true;
        }
 
-      /* The ifunc without reference does not generate plt.  */
+      /* The ifunc reference generate plt.  */
       if (h && h->type == STT_GNU_IFUNC && h->plt.offset != MINUS_ONE)
        {
          defined_local = true;
@@ -2150,20 +2174,25 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                                     + h->root.u.def.section->output_section->vma
                                     + h->root.u.def.section->output_offset);
 
-                 /* Dynamic relocations are stored in
-                    1. .rela.ifunc section in PIC object.
-                    2. .rela.got section in dynamic executable.
-                    3. .rela.iplt section in static executable.  */
-                 if (bfd_link_pic (info))
-                   sreloc = htab->elf.irelifunc;
-                 else if (htab->elf.splt != NULL)
-                   sreloc = htab->elf.srelgot;
+                 if (htab->elf.splt != NULL)
+                   sreloc = htab->elf.srelplt;
                  else
                    sreloc = htab->elf.irelplt;
                }
              else if (resolved_dynly)
                {
-                 outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+                 if (h->dynindx == -1)
+                   {
+                     if (h->root.type == bfd_link_hash_undefined)
+                       (*info->callbacks->undefined_symbol)
+                         (info, name, input_bfd, input_section,
+                          rel->r_offset, true);
+
+                     outrel.r_info = ELFNN_R_INFO (0, r_type);
+                   }
+                 else
+                   outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+
                  outrel.r_addend = rel->r_addend;
                }
              else
@@ -2172,7 +2201,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  outrel.r_addend = relocation + rel->r_addend;
                }
 
-             if (unresolved_reloc)
+             /* No alloc space of func allocate_dynrelocs.  */
+             if (unresolved_reloc
+                 && !(h && (h->is_weakalias || !h->dyn_relocs)))
                loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
            }
 
@@ -2341,12 +2372,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        case R_LARCH_SOP_PUSH_PLT_PCREL:
          unresolved_reloc = false;
 
-         if (resolved_to_const)
-           {
-             relocation += rel->r_addend;
-             break;
-           }
-         else if (is_undefweak)
+         if (is_undefweak)
            {
              i = 0, j = 0;
              relocation = 0;
@@ -2427,10 +2453,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
          if (h != NULL)
            {
-             off = h->got.offset;
+             off = h->got.offset & (~1);
 
-             if (off == MINUS_ONE
-                 && h->type != STT_GNU_IFUNC)
+             if (h->got.offset == MINUS_ONE && h->type != STT_GNU_IFUNC)
                {
                  fatal = (loongarch_reloc_is_fatal
                           (info, input_bfd, input_section, rel, howto,
@@ -2441,8 +2466,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
              /* Hidden symbol not has .got entry, only .got.plt entry
                 so gprel is (plt - got).  */
-             if (off == MINUS_ONE
-                 && h->type == STT_GNU_IFUNC)
+             if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
                {
                  if (h->plt.offset == (bfd_vma) -1)
                    {
@@ -2455,79 +2479,76 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  if (htab->elf.splt != NULL)
                    {
                      /* Section .plt header is 2 times of plt entry.  */
-                     off = sec_addr(htab->elf.sgotplt) + off
-                       - sec_addr(htab->elf.sgot);
+                     off = sec_addr (htab->elf.sgotplt) + off
+                       - sec_addr (htab->elf.sgot);
                    }
                  else
                    {
                      /* Section iplt not has plt header.  */
-                     off = sec_addr(htab->elf.igotplt) + off
-                       - sec_addr(htab->elf.sgot);
+                     off = sec_addr (htab->elf.igotplt) + off
+                       - sec_addr (htab->elf.sgot);
                    }
                }
 
-             if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, is_pic, h)
-                 || (is_pic && SYMBOL_REFERENCES_LOCAL (info, h)))
+             if ((h->got.offset & 1) == 0)
                {
-                 /* This is actually a static link, or it is a
-                    -Bsymbolic link and the symbol is defined
-                    locally, or the symbol was forced to be local
-                    because of a version file.  We must initialize
-                    this entry in the global offset table.  Since the
-                    offset must always be a multiple of the word size,
-                    we use the least significant bit to record whether
-                    we have initialized it already.
-
-                    When doing a dynamic link, we create a .rela.got
-                    relocation entry to initialize the value.  This
-                    is done in the finish_dynamic_symbol routine.  */
-
-                 if (resolved_dynly)
+                 if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
+                                                       bfd_link_pic (info), h)
+                     && ((bfd_link_pic (info)
+                          && SYMBOL_REFERENCES_LOCAL (info, h))))
                    {
-                     fatal = (loongarch_reloc_is_fatal
-                              (info, input_bfd, input_section, rel, howto,
-                               bfd_reloc_dangerous, is_undefweak, name,
-                               "Internal: here shouldn't dynamic."));
-                   }
+                     /* This is actually a static link, or it is a
+                        -Bsymbolic link and the symbol is defined
+                        locally, or the symbol was forced to be local
+                        because of a version file.  We must initialize
+                        this entry in the global offset table.  Since the
+                        offset must always be a multiple of the word size,
+                        we use the least significant bit to record whether
+                        we have initialized it already.
+
+                        When doing a dynamic link, we create a rela.got
+                        relocation entry to initialize the value.  This
+                        is done in the finish_dynamic_symbol routine.  */
+
+                     if (resolved_dynly)
+                       {
+                         fatal = (loongarch_reloc_is_fatal
+                                  (info, input_bfd, input_section, rel, howto,
+                                   bfd_reloc_dangerous, is_undefweak, name,
+                                   "Internal: here shouldn't dynamic."));
+                       }
 
-                 if (!(defined_local || resolved_to_const))
-                   {
-                     fatal = (loongarch_reloc_is_fatal
-                              (info, input_bfd, input_section, rel, howto,
-                               bfd_reloc_undefined, is_undefweak, name,
-                               "Internal: "));
-                     break;
-                   }
+                     if (!(defined_local || resolved_to_const))
+                       {
+                         fatal = (loongarch_reloc_is_fatal
+                                  (info, input_bfd, input_section, rel, howto,
+                                   bfd_reloc_undefined, is_undefweak, name,
+                                   "Internal: "));
+                         break;
+                       }
 
-                 if ((off & 1) != 0)
-                   off &= ~1;
-                 else
-                   {
-                     /* The pr21964-4. Create relocate entry.  */
-                     if (is_pic && h->start_stop)
+                     asection *s;
+                     Elf_Internal_Rela outrel;
+                     /* We need to generate a R_LARCH_RELATIVE reloc
+                        for the dynamic linker.  */
+                     s = htab->elf.srelgot;
+                     if (!s)
                        {
-                         asection *s;
-                         Elf_Internal_Rela outrel;
-                         /* We need to generate a R_LARCH_RELATIVE reloc
-                            for the dynamic linker.  */
-                         s = htab->elf.srelgot;
-                         if (!s)
-                           {
-                             fatal = loongarch_reloc_is_fatal (info, input_bfd,
-                                   input_section, rel, howto,
-                                   bfd_reloc_notsupported, is_undefweak, name,
-                                   "Internal: '.rel.got' not represent");
-                             break;
-                           }
-
-                         outrel.r_offset = sec_addr (got) + off;
-                         outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
-                         outrel.r_addend = relocation; /* Link-time addr.  */
-                         loongarch_elf_append_rela (output_bfd, s, &outrel);
+                         fatal = loongarch_reloc_is_fatal
+                           (info, input_bfd,
+                            input_section, rel, howto,
+                            bfd_reloc_notsupported, is_undefweak, name,
+                            "Internal: '.rel.got' not represent");
+                         break;
                        }
-                     bfd_put_NN (output_bfd, relocation, got->contents + off);
-                     h->got.offset |= 1;
+
+                     outrel.r_offset = sec_addr (got) + off;
+                     outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
+                     outrel.r_addend = relocation; /* Link-time addr.  */
+                     loongarch_elf_append_rela (output_bfd, s, &outrel);
                    }
+                 bfd_put_NN (output_bfd, relocation, got->contents + off);
+                 h->got.offset |= 1;
                }
            }
          else
@@ -2541,9 +2562,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                  break;
                }
 
-             off = local_got_offsets[r_symndx];
+             off = local_got_offsets[r_symndx] & (~1);
 
-             if (off == MINUS_ONE)
+             if (local_got_offsets[r_symndx] == MINUS_ONE)
                {
                  fatal = (loongarch_reloc_is_fatal
                           (info, input_bfd, input_section, rel, howto,
@@ -2555,9 +2576,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              /* The offset must always be a multiple of the word size.
                 So, we can use the least significant bit to record
                 whether we have already processed this entry.  */
-             if ((off & 1) != 0)
-               off &= ~1;
-             else
+             if (local_got_offsets[r_symndx] == 0)
                {
                  if (is_pic)
                    {
@@ -2586,160 +2605,519 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                }
            }
          relocation = off;
+
          break;
 
        case R_LARCH_SOP_PUSH_TLS_GOT:
        case R_LARCH_SOP_PUSH_TLS_GD:
-         if (r_type == R_LARCH_SOP_PUSH_TLS_GOT)
-           is_ie = true;
+         {
+           unresolved_reloc = false;
+           if (r_type == R_LARCH_SOP_PUSH_TLS_GOT)
+             is_ie = true;
+
+           bfd_vma got_off = 0;
+           if (h != NULL)
+             {
+               got_off = h->got.offset;
+               h->got.offset |= 1;
+             }
+           else
+             {
+               got_off = local_got_offsets[r_symndx];
+               local_got_offsets[r_symndx] |= 1;
+             }
+
+           BFD_ASSERT (got_off != MINUS_ONE);
+
+           ie_off = 0;
+           tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
+           if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
+             ie_off = 2 * GOT_ENTRY_SIZE;
+
+           if ((got_off & 1) == 0)
+             {
+               Elf_Internal_Rela rela;
+               asection *srel = htab->elf.srelgot;
+               bfd_vma tls_block_off = 0;
+
+               if (SYMBOL_REFERENCES_LOCAL (info, h))
+                 {
+                   BFD_ASSERT (elf_hash_table (info)->tls_sec);
+                   tls_block_off = relocation
+                       - elf_hash_table (info)->tls_sec->vma;
+                 }
+
+               if (tls_type & GOT_TLS_GD)
+                 {
+                   rela.r_offset = sec_addr (got) + got_off;
+                   rela.r_addend = 0;
+                   if (SYMBOL_REFERENCES_LOCAL (info, h))
+                     {
+                       /* Local sym, used in exec, set module id 1.  */
+                       if (bfd_link_executable (info))
+                         bfd_put_NN (output_bfd, 1, got->contents + got_off);
+                       else
+                         {
+                           rela.r_info = ELFNN_R_INFO (0,
+                                                       R_LARCH_TLS_DTPMODNN);
+                           loongarch_elf_append_rela (output_bfd, srel, &rela);
+                         }
+
+                       bfd_put_NN (output_bfd, tls_block_off,
+                                   got->contents + got_off + GOT_ENTRY_SIZE);
+                     }
+                   /* Dynamic resolved.  */
+                   else
+                     {
+                       /* Dynamic relocate module id.  */
+                       rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                   R_LARCH_TLS_DTPMODNN);
+                       loongarch_elf_append_rela (output_bfd, srel, &rela);
+
+                       /* Dynamic relocate offset of block.  */
+                       rela.r_offset += GOT_ENTRY_SIZE;
+                       rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                   R_LARCH_TLS_DTPRELNN);
+                       loongarch_elf_append_rela (output_bfd, srel, &rela);
+                     }
+                 }
+               if (tls_type & GOT_TLS_IE)
+                 {
+                   rela.r_offset = sec_addr (got) + got_off + ie_off;
+                   if (SYMBOL_REFERENCES_LOCAL (info, h))
+                     {
+                       /* Local sym, used in exec, set module id 1.  */
+                       if (!bfd_link_executable (info))
+                         {
+                           rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
+                           rela.r_addend = tls_block_off;
+                           loongarch_elf_append_rela (output_bfd, srel, &rela);
+                         }
+
+                       bfd_put_NN (output_bfd, tls_block_off,
+                                   got->contents + got_off + ie_off);
+                     }
+                   /* Dynamic resolved.  */
+                   else
+                     {
+                       /* Dynamic relocate offset of block.  */
+                       rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                   R_LARCH_TLS_TPRELNN);
+                       rela.r_addend = 0;
+                       loongarch_elf_append_rela (output_bfd, srel, &rela);
+                     }
+                 }
+             }
+
+           relocation = (got_off & (~(bfd_vma)1)) + (is_ie ? ie_off : 0);
+         }
+         break;
+
+       /* New reloc types.  */
+       case R_LARCH_B21:
+       case R_LARCH_B26:
+       case R_LARCH_B16:
          unresolved_reloc = false;
+         if (is_undefweak)
+           {
+             relocation = 0;
+           }
 
-         if (rel->r_addend != 0)
+         if (resolved_local)
            {
-             fatal = (loongarch_reloc_is_fatal
-                      (info, input_bfd, input_section, rel, howto,
-                       bfd_reloc_notsupported, is_undefweak, name,
-                       "Shouldn't be with r_addend."));
+             relocation -= pc;
+             relocation += rel->r_addend;
+           }
+         else if (resolved_dynly)
+           {
+             BFD_ASSERT (h
+                         && (h->plt.offset != MINUS_ONE
+                             || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+                         && rel->r_addend == 0);
+             if (h && h->plt.offset == MINUS_ONE
+                 && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+               {
+                 relocation -= pc;
+                 relocation += rel->r_addend;
+               }
+             else
+               relocation = sec_addr (plt) + h->plt.offset - pc;
+           }
+
+         break;
+
+       case R_LARCH_ABS_HI20:
+       case R_LARCH_ABS_LO12:
+       case R_LARCH_ABS64_LO20:
+       case R_LARCH_ABS64_HI12:
+         BFD_ASSERT (!is_pic);
+
+         if (is_undefweak)
+           {
+             BFD_ASSERT (resolved_dynly);
+             relocation = 0;
              break;
            }
+         else if (resolved_to_const || resolved_local)
+           {
+             relocation += rel->r_addend;
+           }
+         else if (resolved_dynly)
+           {
+             unresolved_reloc = false;
+             BFD_ASSERT ((plt && h && h->plt.offset != MINUS_ONE)
+                         && rel->r_addend == 0);
+             relocation = sec_addr (plt) + h->plt.offset;
+           }
+
+         break;
+
+       case R_LARCH_PCALA_HI20:
+         unresolved_reloc = false;
+         if (h && h->plt.offset != MINUS_ONE)
+           relocation = sec_addr (plt) + h->plt.offset;
+         else
+           relocation += rel->r_addend;
 
+         RELOCATE_CALC_PC32_HI20 (relocation, pc);
+
+         break;
+
+       case R_LARCH_PCALA_LO12:
+         /* Not support if sym_addr in 2k page edge.
+            pcalau12i pc_hi20 (sym_addr)
+            ld.w/d pc_lo12 (sym_addr)
+            ld.w/d pc_lo12 (sym_addr + x)
+            ...
+            can not calc correct address
+            if sym_addr < 0x800 && sym_addr + x >= 0x800.  */
+
+         if (h && h->plt.offset != MINUS_ONE)
+           relocation = sec_addr (plt) + h->plt.offset;
+         else
+           relocation += rel->r_addend;
 
-         if (resolved_to_const && is_undefweak && h->dynindx != -1)
            {
-             /* What if undefweak? Let rtld make a decision.  */
-             resolved_to_const = resolved_local = false;
-             resolved_dynly = true;
+             relocation &= 0xfff;
+             /* Signed extend.  */
+             relocation = (relocation ^ 0x800) - 0x800;
+
+             /* For 2G jump, generate pcalau12i, jirl.  */
+             /* If use jirl, turns to R_LARCH_B16.  */
+             uint32_t insn = bfd_get (32, input_bfd, contents + rel->r_offset);
+             if ((insn & 0x4c000000) == 0x4c000000)
+               {
+                 rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_B16);
+                 howto = loongarch_elf_rtype_to_howto (input_bfd, R_LARCH_B16);
+               }
            }
+         break;
 
-         if (resolved_to_const)
+       case R_LARCH_PCALA64_LO20:
+       case R_LARCH_PCALA64_HI12:
+         if (h && h->plt.offset != MINUS_ONE)
            {
-             fatal = (loongarch_reloc_is_fatal
-                      (info, input_bfd, input_section, rel, howto,
-                       bfd_reloc_notsupported, is_undefweak, name,
-                       "Internal: Shouldn't be resolved to const."));
-             break;
+             BFD_ASSERT (rel->r_addend == 0);
+             relocation = sec_addr (plt) + h->plt.offset;
+           }
+         else
+           relocation += rel->r_addend;
+
+         RELOCATE_CALC_PC64_HI32 (relocation, pc);
+
+         break;
+
+       case R_LARCH_GOT_PC_HI20:
+       case R_LARCH_GOT_HI20:
+         /* Calc got offset.  */
+           {
+             unresolved_reloc = false;
+             BFD_ASSERT (rel->r_addend == 0);
+
+             bfd_vma got_off = 0;
+             if (h != NULL)
+               {
+                 /* GOT ref or ifunc.  */
+                 BFD_ASSERT (h->got.offset != MINUS_ONE
+                             || h->type == STT_GNU_IFUNC);
+
+                 got_off = h->got.offset  & (~(bfd_vma)1);
+                 /* Hidden symbol not has got entry,
+                  * only got.plt entry so it is (plt - got).  */
+                 if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
+                   {
+                     bfd_vma idx;
+                     if (htab->elf.splt != NULL)
+                       {
+                         idx = (h->plt.offset - PLT_HEADER_SIZE)
+                           / PLT_ENTRY_SIZE;
+                         got_off = sec_addr (htab->elf.sgotplt)
+                           + GOTPLT_HEADER_SIZE
+                           + (idx * GOT_ENTRY_SIZE)
+                           - sec_addr (htab->elf.sgot);
+                       }
+                     else
+                       {
+                         idx = h->plt.offset / PLT_ENTRY_SIZE;
+                         got_off = sec_addr (htab->elf.sgotplt)
+                           + (idx * GOT_ENTRY_SIZE)
+                           - sec_addr (htab->elf.sgot);
+                       }
+                   }
+
+                 if ((h->got.offset & 1) == 0)
+                   {
+                     /* We need to generate a R_LARCH_RELATIVE reloc once
+                      * in loongarch_elf_finish_dynamic_symbol or now,
+                      * call finish_dyn && nopic
+                      * or !call finish_dyn && pic.  */
+                     if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
+                                                           bfd_link_pic (info),
+                                                           h)
+                         && bfd_link_pic (info)
+                         && SYMBOL_REFERENCES_LOCAL (info, h))
+                       {
+                         Elf_Internal_Rela rela;
+                         rela.r_offset = sec_addr (got) + got_off;
+                         rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
+                         rela.r_addend = relocation;
+                         loongarch_elf_append_rela (output_bfd,
+                                                    htab->elf.srelgot, &rela);
+                       }
+                     h->got.offset |= 1;
+                   }
+               }
+             else
+               {
+                 BFD_ASSERT (local_got_offsets
+                             && local_got_offsets[r_symndx] != MINUS_ONE);
+
+                 got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
+                 if ((local_got_offsets[r_symndx] & 1) == 0)
+                   {
+                     if (bfd_link_pic (info))
+                       {
+                         Elf_Internal_Rela rela;
+                         rela.r_offset = sec_addr (got) + got_off;
+                         rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
+                         rela.r_addend = relocation;
+                         loongarch_elf_append_rela (output_bfd,
+                                                    htab->elf.srelgot, &rela);
+                       }
+                     local_got_offsets[r_symndx] |= 1;
+                   }
+               }
+
+             bfd_put_NN (output_bfd, relocation, got->contents + got_off);
+
+             relocation = got_off + sec_addr (got);
            }
 
+         if (r_type == R_LARCH_GOT_PC_HI20)
+           RELOCATE_CALC_PC32_HI20 (relocation, pc);
+
+         break;
+
+       case R_LARCH_GOT_PC_LO12:
+       case R_LARCH_GOT64_PC_LO20:
+       case R_LARCH_GOT64_PC_HI12:
+       case R_LARCH_GOT_LO12:
+       case R_LARCH_GOT64_LO20:
+       case R_LARCH_GOT64_HI12:
+           {
+             unresolved_reloc = false;
+             bfd_vma got_off;
+             if (h)
+               got_off = h->got.offset & (~(bfd_vma)1);
+             else
+               got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
+
+             if (h && h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
+               {
+                 bfd_vma idx;
+                 if (htab->elf.splt != NULL)
+                   idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+                 else
+                   idx = h->plt.offset / PLT_ENTRY_SIZE;
+
+                 got_off = sec_addr (htab->elf.sgotplt)
+                   + GOTPLT_HEADER_SIZE
+                   + (idx * GOT_ENTRY_SIZE)
+                   - sec_addr (htab->elf.sgot);
+               }
+             relocation = got_off + sec_addr (got);
+           }
+
+         if (r_type == R_LARCH_GOT_PC_LO12)
+           relocation &= (bfd_vma)0xfff;
+         else if (r_type == R_LARCH_GOT64_PC_LO20
+                  || r_type == R_LARCH_GOT64_PC_HI12)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc);
+
+         break;
+
+       case R_LARCH_TLS_LE_HI20:
+       case R_LARCH_TLS_LE_LO12:
+       case R_LARCH_TLS_LE64_LO20:
+       case R_LARCH_TLS_LE64_HI12:
+         BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec);
+
+         relocation -= elf_hash_table (info)->tls_sec->vma;
+         break;
+
+       /* TLS IE LD/GD process separately is troublesome.
+          When a symbol is both ie and LD/GD, h->got.off |= 1
+          make only one type be relocated.  We must use
+          h->got.offset |= 1 and h->got.offset |= 2
+          diff IE and LD/GD.  And all (got_off & (~(bfd_vma)1))
+          (IE LD/GD and reusable GOT reloc) must change to
+          (got_off & (~(bfd_vma)3)), beause we use lowest 2 bits
+          as a tag.
+          Now, LD and GD is both GOT_TLS_GD type, LD seems to
+          can be omitted.  */
+       case R_LARCH_TLS_IE_PC_HI20:
+       case R_LARCH_TLS_IE_HI20:
+       case R_LARCH_TLS_LD_PC_HI20:
+       case R_LARCH_TLS_LD_HI20:
+       case R_LARCH_TLS_GD_PC_HI20:
+       case R_LARCH_TLS_GD_HI20:
+         BFD_ASSERT (rel->r_addend == 0);
+         unresolved_reloc = false;
+
+         if (r_type == R_LARCH_TLS_IE_PC_HI20
+             || r_type == R_LARCH_TLS_IE_HI20)
+           is_ie = true;
+
+         bfd_vma got_off = 0;
          if (h != NULL)
            {
-             off = h->got.offset;
+             got_off = h->got.offset;
              h->got.offset |= 1;
            }
          else
            {
-             off = local_got_offsets[r_symndx];
+             got_off = local_got_offsets[r_symndx];
              local_got_offsets[r_symndx] |= 1;
            }
 
-         if (off == MINUS_ONE)
-           {
-             fatal = (loongarch_reloc_is_fatal
-                      (info, input_bfd, input_section, rel, howto,
-                       bfd_reloc_notsupported, is_undefweak, name,
-                       "Internal: TLS GOT entry doesn't represent."));
-             break;
-           }
-
-         tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
+         BFD_ASSERT (got_off != MINUS_ONE);
 
-         /* If this symbol is referenced by both GD and IE TLS, the IE
-            reference's GOT slot follows the GD reference's slots.  */
          ie_off = 0;
+         tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
          if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
            ie_off = 2 * GOT_ENTRY_SIZE;
 
-         if ((off & 1) != 0)
-           off &= ~1;
-         else
+         if ((got_off & 1) == 0)
            {
+             Elf_Internal_Rela rela;
+             asection *relgot = htab->elf.srelgot;
              bfd_vma tls_block_off = 0;
-             Elf_Internal_Rela outrel;
 
-             if (resolved_local)
+             if (SYMBOL_REFERENCES_LOCAL (info, h))
                {
-                 if (!elf_hash_table (info)->tls_sec)
-                   {
-                     fatal = (loongarch_reloc_is_fatal
-                              (info, input_bfd, input_section, rel, howto,
-                               bfd_reloc_notsupported, is_undefweak, name,
-                               "Internal: TLS sec not represent."));
-                     break;
-                   }
-                 tls_block_off =
-                   relocation - elf_hash_table (info)->tls_sec->vma;
+                 BFD_ASSERT (elf_hash_table (info)->tls_sec);
+                 tls_block_off = relocation
+                     - elf_hash_table (info)->tls_sec->vma;
                }
 
              if (tls_type & GOT_TLS_GD)
                {
-                 outrel.r_offset = sec_addr (got) + off;
-                 outrel.r_addend = 0;
-                 bfd_put_NN (output_bfd, 0, got->contents + off);
-                 if (resolved_local && bfd_link_executable (info))
-                   bfd_put_NN (output_bfd, 1, got->contents + off);
-                 else if (resolved_local /* && !bfd_link_executable (info) */)
-                   {
-                     outrel.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN);
-                     loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
-                                                &outrel);
-                   }
-                 else /* if (resolved_dynly) */
+                 rela.r_offset = sec_addr (got) + got_off;
+                 rela.r_addend = 0;
+                 if (SYMBOL_REFERENCES_LOCAL (info, h))
                    {
-                     outrel.r_info =
-                       ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_DTPMODNN);
-                     loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
-                                                &outrel);
-                   }
+                     /* Local sym, used in exec, set module id 1.  */
+                     if (bfd_link_executable (info))
+                       bfd_put_NN (output_bfd, 1, got->contents + got_off);
+                     else
+                       {
+                         rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN);
+                         loongarch_elf_append_rela (output_bfd, relgot, &rela);
+                       }
 
-                 outrel.r_offset += GOT_ENTRY_SIZE;
-                 bfd_put_NN (output_bfd, tls_block_off,
-                             got->contents + off + GOT_ENTRY_SIZE);
-                 if (resolved_local)
-                   /* DTPREL known.  */;
-                 else /* if (resolved_dynly) */
+                     bfd_put_NN (output_bfd, tls_block_off,
+                                 got->contents + got_off + GOT_ENTRY_SIZE);
+                   }
+                 /* Dynamic resolved.  */
+                 else
                    {
-                     outrel.r_info =
-                       ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_DTPRELNN);
-                     loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
-                                                &outrel);
+                     /* Dynamic relocate module id.  */
+                     rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                 R_LARCH_TLS_DTPMODNN);
+                     loongarch_elf_append_rela (output_bfd, relgot, &rela);
+
+                     /* Dynamic relocate offset of block.  */
+                     rela.r_offset += GOT_ENTRY_SIZE;
+                     rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                 R_LARCH_TLS_DTPRELNN);
+                     loongarch_elf_append_rela (output_bfd, relgot, &rela);
                    }
                }
-
              if (tls_type & GOT_TLS_IE)
                {
-                 outrel.r_offset = sec_addr (got) + off + ie_off;
-                 bfd_put_NN (output_bfd, tls_block_off,
-                             got->contents + off + ie_off);
-                 if (resolved_local && bfd_link_executable (info))
-                   /* TPREL known.  */;
-                 else if (resolved_local /* && !bfd_link_executable (info) */)
+                 rela.r_offset = sec_addr (got) + got_off + ie_off;
+                 if (SYMBOL_REFERENCES_LOCAL (info, h))
                    {
-                     outrel.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
-                     outrel.r_addend = tls_block_off;
-                     loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
-                                                &outrel);
-                   }
-                 else /* if (resolved_dynly) */
-                   {
-                     /* Static linking has no .dynsym table.  */
-                     if (!htab->elf.dynamic_sections_created)
-                       {
-                         outrel.r_info =
-                           ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
-                         outrel.r_addend = 0;
-                       }
-                     else
+                     /* Local sym, used in exec, set module id 1.  */
+                     if (!bfd_link_executable (info))
                        {
-                         outrel.r_info =
-                           ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_TPRELNN);
-                         outrel.r_addend = 0;
+                         rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
+                         rela.r_addend = tls_block_off;
+                         loongarch_elf_append_rela (output_bfd, relgot, &rela);
                        }
-                     loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
-                                                &outrel);
+
+                     bfd_put_NN (output_bfd, tls_block_off,
+                                 got->contents + got_off + ie_off);
+                   }
+                 /* Dynamic resolved.  */
+                 else
+                   {
+                     /* Dynamic relocate offset of block.  */
+                     rela.r_info = ELFNN_R_INFO (h->dynindx,
+                                                 R_LARCH_TLS_TPRELNN);
+                     rela.r_addend = 0;
+                     loongarch_elf_append_rela (output_bfd, relgot, &rela);
                    }
                }
            }
+         relocation = (got_off & (~(bfd_vma)1)) + sec_addr (got)
+                       + (is_ie ? ie_off : 0);
+
+         if (r_type == R_LARCH_TLS_LD_PC_HI20
+             || r_type == R_LARCH_TLS_GD_PC_HI20
+             || r_type == R_LARCH_TLS_IE_PC_HI20)
+           RELOCATE_CALC_PC32_HI20 (relocation, pc);
 
-         relocation = off + (is_ie ? ie_off : 0);
+         break;
+
+       case R_LARCH_TLS_IE_PC_LO12:
+       case R_LARCH_TLS_IE64_PC_LO20:
+       case R_LARCH_TLS_IE64_PC_HI12:
+       case R_LARCH_TLS_IE_LO12:
+       case R_LARCH_TLS_IE64_LO20:
+       case R_LARCH_TLS_IE64_HI12:
+         unresolved_reloc = false;
+
+         if (h)
+           relocation = sec_addr (got) + (h->got.offset & (~(bfd_vma)3));
+         else
+           relocation = sec_addr (got)
+             + (local_got_offsets[r_symndx] & (~(bfd_vma)3));
+
+         tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
+         /* Use both TLS_GD and TLS_IE.  */
+         if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_IE))
+           relocation += 2 * GOT_ENTRY_SIZE;
+
+         if (r_type == R_LARCH_TLS_IE_PC_LO12)
+           relocation &= (bfd_vma)0xfff;
+         else if (r_type == R_LARCH_TLS_IE64_PC_LO20
+                  || r_type == R_LARCH_TLS_IE64_PC_HI12)
+           RELOCATE_CALC_PC64_HI32 (relocation, pc);
+
+         break;
+
+       case R_LARCH_RELAX:
          break;
 
        default:
@@ -2759,7 +3137,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
          if (_bfd_elf_section_offset (output_bfd, info, input_section,
                                       rel->r_offset) == MINUS_ONE)
            /* WHY? May because it's invalid so skip checking.
-              But why dynamic reloc a invalid section? */
+              But why dynamic reloc a invalid section?  */
            break;
 
          if (input_section->output_section->flags & SEC_DEBUGGING)
@@ -2825,7 +3203,6 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
        }
 
       fatal = true;
-      break;
     }
 
   return !fatal;
@@ -2889,27 +3266,15 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       for (i = 0; i < PLT_ENTRY_INSNS; i++)
        bfd_put_32 (output_bfd, plt_entry[i], loc + 4 * i);
 
-      /* Fill in the initial value of the .got.plt entry.  */
+      /* Fill in the initial value of the got.plt entry.  */
       loc = gotplt->contents + (got_address - sec_addr (gotplt));
       bfd_put_NN (output_bfd, sec_addr (plt), loc);
 
       rela.r_offset = got_address;
 
-      /* TRUE if this is a PLT reference to a local IFUNC.  */
-      if (PLT_LOCAL_IFUNC_P(info, h))
-       {
-         rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
-         rela.r_addend = (h->root.u.def.value
-                          + h->root.u.def.section->output_section->vma
-                          + h->root.u.def.section->output_offset);
-       }
-      else
-       {
-         /* Fill in the entry in the .rela.plt section.  */
-         rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_JUMP_SLOT);
-         rela.r_addend = 0;
-       }
-
+      /* Fill in the entry in the rela.plt section.  */
+      rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_JUMP_SLOT);
+      rela.r_addend = 0;
       loc = relplt->contents + plt_idx * sizeof (ElfNN_External_Rela);
       bed->s->swap_reloca_out (output_bfd, &rela, loc);
 
@@ -2930,15 +3295,14 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
   if (h->got.offset != MINUS_ONE
       /* TLS got entry have been handled in elf_relocate_section.  */
       && !(loongarch_elf_hash_entry (h)->tls_type & (GOT_TLS_GD | GOT_TLS_IE))
-      /* have allocated got entry but not allocated rela before.  */
+      /* Have allocated got entry but not allocated rela before.  */
       && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
     {
       asection *sgot, *srela;
       Elf_Internal_Rela rela;
-      bfd_vma off = h->got.offset & ~(bfd_vma) 1;
+      bfd_vma off = h->got.offset & ~(bfd_vma)1;
 
       /* This symbol has an entry in the GOT.  Set it up.  */
-
       sgot = htab->elf.sgot;
       srela = htab->elf.srelgot;
       BFD_ASSERT (sgot && srela);
@@ -2963,7 +3327,6 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
                }
              else
                {
-                 BFD_ASSERT ((h->got.offset & 1) == 0);
                  BFD_ASSERT (h->dynindx != -1);
                  rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
                  rela.r_addend = 0;
@@ -2993,7 +3356,6 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
       else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
        {
-         BFD_ASSERT (h->got.offset & 1 /* Has been filled in addr.  */);
          asection *sec = h->root.u.def.section;
          rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
          rela.r_addend = (h->root.u.def.value + sec->output_section->vma
@@ -3001,7 +3363,6 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
        }
       else
        {
-         BFD_ASSERT ((h->got.offset & 1) == 0);
          BFD_ASSERT (h->dynindx != -1);
          rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
          rela.r_addend = 0;
@@ -3010,24 +3371,6 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       loongarch_elf_append_rela (output_bfd, srela, &rela);
     }
 
-  if (h->needs_copy)
-    {
-      Elf_Internal_Rela rela;
-      asection *s;
-
-      /* This symbols needs a copy reloc.  Set it up.  */
-      BFD_ASSERT (h->dynindx != -1);
-
-      rela.r_offset = sec_addr (h->root.u.def.section) + h->root.u.def.value;
-      rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_COPY);
-      rela.r_addend = 0;
-      if (h->root.u.def.section == htab->elf.sdynrelro)
-       s = htab->elf.sreldynrelro;
-      else
-       s = htab->elf.srelbss;
-      loongarch_elf_append_rela (output_bfd, s, &rela);
-    }
-
   /* Mark some specially defined symbols as absolute.  */
   if (h == htab->elf.hdynamic || h == htab->elf.hgot || h == htab->elf.hplt)
     sym->st_shndx = SHN_ABS;
@@ -3337,7 +3680,6 @@ loongarch_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 #define PRPSINFO_OFFSET_PR_PS_ARGS  0x38
 #define PRPSINFO_SIZEOF_PR_PS_ARGS  0x50
 
-
 static bool
 loongarch_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
index 4424969e579b22abac51a2661121a9d9e548de17..f059f1a0c05687981aa3d680c42baf5952fc0274 100644 (file)
@@ -35,27 +35,30 @@ typedef struct loongarch_reloc_howto_type_struct
   reloc_howto_type howto;
   bfd_reloc_code_real_type bfd_type;
   bool (*adjust_reloc_bits)(reloc_howto_type *, bfd_vma *);
-}loongarch_reloc_howto_type;
+  const char *larch_reloc_type_name;
+} loongarch_reloc_howto_type;
 
 #define LOONGARCH_DEFAULT_HOWTO(r_name)                                            \
   { HOWTO (R_LARCH_##r_name, 0, 4, 32, false, 0, complain_overflow_signed,  \
        bfd_elf_generic_reloc, "R_LARCH_" #r_name, false, 0, ALL_ONES,      \
-       false), BFD_RELOC_LARCH_##r_name, NULL }
+       false), BFD_RELOC_LARCH_##r_name, NULL, NULL }
 
 #define LOONGARCH_HOWTO(type, right, size, bits, pcrel, left, ovf, func,  \
-           name, inplace, src_mask, dst_mask, pcrel_off, btype, afunc)   \
+           name, inplace, src_mask, dst_mask, pcrel_off, btype, afunc,lname) \
   { HOWTO(type, right, size, bits, pcrel, left, ovf, func, name,         \
-         inplace, src_mask, dst_mask, pcrel_off), btype, afunc }
+         inplace, src_mask, dst_mask, pcrel_off), btype, afunc, lname }
 
 #define LOONGARCH_EMPTY_HOWTO(C) \
-  { EMPTY_HOWTO(C), BFD_RELOC_NONE, NULL }
-
-bool loongarch_gen_adjust_reloc_bits (reloc_howto_type *howto, bfd_vma *val);
-bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
-                                            bfd_vma *fix_val);
-bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
-                                         bfd_vma *val);
+  { EMPTY_HOWTO (C), BFD_RELOC_NONE, NULL, NULL }
 
+static bool
+reloc_bits (reloc_howto_type *howto, bfd_vma *val);
+static bool
+reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val);
+static bool
+reloc_bits_b21 (reloc_howto_type *howto, bfd_vma *fix_val);
+static bool
+reloc_bits_b26 (reloc_howto_type *howto, bfd_vma *val);
 
 /* This does not include any relocation information, but should be
    good enough for GDB or objdump to read the file.  */
@@ -76,7 +79,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0,                               /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_NONE,                  /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   /* 32 bit relocation.  */
   LOONGARCH_HOWTO (R_LARCH_32,           /* type (1).  */
@@ -93,7 +97,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_32,                    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   /* 64 bit relocation.  */
   LOONGARCH_HOWTO (R_LARCH_64,           /* type (2).  */
@@ -110,7 +115,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_64,                    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_RELATIVE,     /* type (3).  */
         0,                               /* rightshift */
@@ -126,7 +132,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_NONE,                  /* undefined?  */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_COPY,         /* type (4).  */
         0,                               /* rightshift */
@@ -141,8 +148,9 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0,                               /* src_mask */
         0,                               /* dst_mask */
         false,                           /* pcrel_offset */
-        BFD_RELOC_NONE,                          /* undefined?  */
-        NULL),                           /* adjust_reloc_bits */
+        BFD_RELOC_NONE,                  /* undefined?  */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_JUMP_SLOT,    /* type (5).  */
         0,                               /* rightshift */
@@ -157,8 +165,9 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         0,                               /* src_mask */
         0,                               /* dst_mask */
         false,                           /* pcrel_offset */
-        BFD_RELOC_NONE,                          /* undefined?  */
-        NULL),                           /* adjust_reloc_bits */
+        BFD_RELOC_NONE,                  /* undefined?  */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   /* Dynamic TLS relocations.  */
   LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD32,  /* type (6).  */
@@ -175,7 +184,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_DTPMOD32,    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_TLS_DTPMOD64,  /* type (7).  */
         0,                               /* rightshift */
@@ -191,7 +201,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_DTPMOD64,    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL32,  /* type (8). */
         0,                               /* rightshift */
@@ -207,7 +218,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_DTPREL32,    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_TLS_DTPREL64,  /* type (9).  */
         0,                               /* rightshift */
@@ -223,7 +235,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_DTPREL64,    /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_TLS_TPREL32,          /* type (10).  */
         0,                               /* rightshift */
@@ -239,7 +252,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_TPREL32,     /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_TLS_TPREL64,          /* type (11).  */
         0,                               /* rightshift */
@@ -255,7 +269,8 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_LARCH_TLS_TPREL64,     /* bfd_reloc_code_real_type */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_IRELATIVE,    /* type (12).  */
         0,                               /* rightshift */
@@ -271,63 +286,67 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         ALL_ONES,                        /* dst_mask */
         false,                           /* pcrel_offset */
         BFD_RELOC_NONE,                  /* undefined?  */
-        NULL),                           /* adjust_reloc_bits */
+        NULL,                            /* adjust_reloc_bits */
+        NULL),                           /* larch_reloc_type_name */
 
-  LOONGARCH_EMPTY_HOWTO(13),
-  LOONGARCH_EMPTY_HOWTO(14),
-  LOONGARCH_EMPTY_HOWTO(15),
-  LOONGARCH_EMPTY_HOWTO(16),
-  LOONGARCH_EMPTY_HOWTO(17),
-  LOONGARCH_EMPTY_HOWTO(18),
-  LOONGARCH_EMPTY_HOWTO(19),
+  LOONGARCH_EMPTY_HOWTO (13),
+  LOONGARCH_EMPTY_HOWTO (14),
+  LOONGARCH_EMPTY_HOWTO (15),
+  LOONGARCH_EMPTY_HOWTO (16),
+  LOONGARCH_EMPTY_HOWTO (17),
+  LOONGARCH_EMPTY_HOWTO (18),
+  LOONGARCH_EMPTY_HOWTO (19),
 
   LOONGARCH_HOWTO (R_LARCH_MARK_LA,            /* type (20).  */
-        0,                                     /* rightshift.  */
-        0,                                     /* size.  */
-        0,                                     /* bitsize.  */
+        0,                                     /* rightshift.  */
+        0,                                     /* size.  */
+        0,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
         "R_LARCH_MARK_LA",                     /* name.  */
-        false,                                 /* partial_inplace.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask.  */
         0,                                     /* dst_mask.  */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_MARK_LA,               /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_MARK_PCREL,         /* type (21).  */
-        0,                                     /* rightshift.  */
-        0,                                     /* size.  */
-        0,                                     /* bitsize.  */
+        0,                                     /* rightshift.  */
+        0,                                     /* size.  */
+        0,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
         "R_LARCH_MARK_PCREL",                  /* name.  */
-        false,                                 /* partial_inplace.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask.  */
         0,                                     /* dst_mask.  */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_MARK_PCREL,            /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_PUSH_PCREL,     /* type (22).  */
-        2,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        32,                                    /* bitsize.  */
+        2,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        32,                                    /* bitsize.  */
         true /* FIXME: somewhat use this.  */, /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SOP_PUSH_PCREL",              /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SOP_PUSH_PCREL",              /* name.  */
+        false,                                 /* partial_inplace.  */
         0x03ffffff,                            /* src_mask.  */
         0x03ffffff,                            /* dst_mask.  */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_PUSH_PCREL,        /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
   /* type 23-37.  */
   LOONGARCH_DEFAULT_HOWTO (SOP_PUSH_ABSOLUTE),
@@ -347,343 +366,984 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
   LOONGARCH_DEFAULT_HOWTO (SOP_IF_ELSE),
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_5,    /* type (38).  */
-        0,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        5,                                       /* bitsize.  */
+        0,                                       /* rightshift.  */
+        4,                                       /* size.  */
+        5,                                       /* bitsize.  */
         false,                                   /* pc_relative.  */
-        10,                                      /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_10_5",             /* name.  */
-        false,                                   /* partial_inplace.  */
+        10,                                      /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_10_5",             /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x7c00,                                  /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_10_5,       /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits,                              /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U_10_12,   /* type (39).  */
-        0,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        12,                                      /* bitsize.  */
+        0,                                       /* rightshift.  */
+        4,                                       /* size.  */
+        12,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        10,                                      /* bitpos.  */
-        complain_overflow_unsigned,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_U_10_12",            /* name.  */
-        false,                                   /* partial_inplace.  */
+        10,                                      /* bitpos.  */
+        complain_overflow_unsigned,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_U_10_12",            /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x3ffc00,                                /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_U_10_12,      /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits,                              /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_12,   /* type (40).  */
-        0,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        12,                                      /* bitsize.  */
+        0,                                       /* rightshift.  */
+        4,                                       /* size.  */
+        12,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        10,                                      /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_10_12",            /* name.  */
-        false,                                   /* partial_inplace.  */
+        10,                                      /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_10_12",            /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x3ffc00,                                /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_10_12,      /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits,                              /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16,   /* type (41).  */
-        0,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        16,                                      /* bitsize.  */
+        0,                                       /* rightshift.  */
+        4,                                       /* size.  */
+        16,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        10,                                      /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_10_16",            /* name.  */
-        false,                                   /* partial_inplace.  */
+        10,                                      /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_10_16",            /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x3fffc00,                               /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_10_16,      /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits,                              /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_10_16_S2, /* type (42).  */
         2,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        16,                                      /* bitsize.  */
+        4,                                       /* size.  */
+        16,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        10,                                      /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_10_16_S2",         /* name.  */
-        false,                                   /* partial_inplace.  */
+        10,                                      /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_10_16_S2",         /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x3fffc00,                               /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2,   /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits_b16,                          /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_5_20,    /* type (43).  */
-        0,                                       /* rightshift.  */
-        4,                                       /* size.  */
-        20,                                      /* bitsize.  */
+        0,                                       /* rightshift.  */
+        4,                                       /* size.  */
+        20,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        5,                                       /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_5_20",             /* name.  */
-        false,                                   /* partial_inplace.  */
+        5,                                       /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_5_20",             /* name.  */
+        false,                                   /* partial_inplace.  */
         0,                                       /* src_mask */
         0x1ffffe0,                               /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_5_20,       /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),        /* adjust_reloc_bits */
+        reloc_bits,                              /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
                                                  /* type (44).  */
         2,                                       /* rightshift.  */
         4,                                       /* size.  */
-        21,                                      /* bitsize.  */
+        21,                                      /* bitsize.  */
         false,                                   /* pc_relative.  */
-        0,                                       /* bitpos.  */
-        complain_overflow_signed,                /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                   /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_0_5_10_16_S2",     /* name.  */
-        false,                                   /* partial_inplace.  */
+        0,                                       /* bitpos.  */
+        complain_overflow_signed,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                   /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_0_5_10_16_S2",     /* name.  */
+        false,                                   /* partial_inplace.  */
         0xfc0003e0,                              /* src_mask */
         0xfc0003e0,                              /* dst_mask */
         false,                                   /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_0_5_10_16_S2,
                                                  /* bfd_reloc_code_real_type */
-        loongarch_adjust_reloc_bits_l16_xx5_h5), /* adjust_reloc_bits */
+        reloc_bits_b21,                          /* adjust_reloc_bits */
+        NULL),                                   /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_S_0_10_10_16_S2, /* type (45).  */
-        2,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        26,                                    /* bitsize.  */
-        false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_0_10_10_16_S2",  /* name.  */
-        false,                                 /* partial_inplace.  */
-        0xfc000000,                            /* src_mask */
-        0xfc000000,                            /* dst_mask */
+        2,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        26,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_0_10_10_16_S2",  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x03ffffff,                            /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_S_0_10_10_16_S2,
                                                /* bfd_reloc_code_real_type */
-        loongarch_adjust_reloc_bits_l16_h10),  /* adjust_reloc_bits */
+        reloc_bits_b26,                        /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
   LOONGARCH_HOWTO (R_LARCH_SOP_POP_32_U,       /* type (46).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        32,                                    /* bitsize.  */
-        false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_unsigned,            /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SOP_POP_32_S_U",              /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        32,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_unsigned,            /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SOP_POP_32_S_U",              /* name.  */
+        false,                                 /* partial_inplace.  */
         0xffffffff00000000,                    /* src_mask */
         0x00000000ffffffff,                    /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SOP_POP_32_U,          /* bfd_reloc_code_real_type */
-        loongarch_gen_adjust_reloc_bits),      /* adjust_reloc_bits */
+        reloc_bits,                            /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_ADD8,               /* type (47).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        8,                                     /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_ADD8,               /* type (47).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        8,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_ADD8",                        /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ADD8",                        /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_ADD8,                  /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_ADD16,              /* type (48).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        16,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_ADD16,              /* type (48).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        16,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_ADD16",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ADD16",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_ADD16,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_ADD24,              /* type (49).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        24,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_ADD24,              /* type (49).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        24,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_ADD24",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ADD24",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_ADD24,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_ADD32,              /* type (50).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        32,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_ADD32,              /* type (50).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        32,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_ADD32",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ADD32",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_ADD32,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_ADD64,              /* type (51).  */
-        0,                                     /* rightshift.  */
-        8,                                     /* size.  */
-        64,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_ADD64,              /* type (51).  */
+        0,                                     /* rightshift.  */
+        8,                                     /* size.  */
+        64,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_ADD64",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ADD64",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_ADD64,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_SUB8,               /* type (52).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        8,                                     /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_SUB8,               /* type (52).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        8,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SUB8",                        /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SUB8",                        /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SUB8,                  /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_SUB16,              /* type (53).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        16,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_SUB16,              /* type (53).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        16,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SUB16",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SUB16",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SUB16,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_SUB24,              /* type (54).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        24,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_SUB24,              /* type (54).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        24,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SUB24",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SUB24",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SUB24,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_SUB32,              /* type (55).  */
-        0,                                     /* rightshift.  */
-        4,                                     /* size.  */
-        32,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_SUB32,              /* type (55).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        32,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SUB32",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SUB32",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SUB32,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_SUB64,              /* type (56).  */
-        0,                                     /* rightshift.  */
-        8,                                     /* size.  */
-        64,                                    /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_SUB64,              /* type (56).  */
+        0,                                     /* rightshift.  */
+        8,                                     /* size.  */
+        64,                                    /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_SUB64",                       /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_SUB64",                       /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         ALL_ONES,                              /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_LARCH_SUB64,                 /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_GNU_VTINHERIT,              /* type (57).  */
-        0,                                     /* rightshift.  */
-        0,                                     /* size.  */
-        0,                                     /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_GNU_VTINHERIT,      /* type (57).  */
+        0,                                     /* rightshift.  */
+        0,                                     /* size.  */
+        0,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
-        bfd_elf_generic_reloc,                 /* special_function.  */
-        "R_LARCH_GNU_VTINHERIT",               /* name.  */
-        false,                                 /* partial_inplace.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GNU_VTINHERIT",               /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         0,                                     /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_NONE,                        /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
 
-  LOONGARCH_HOWTO (R_LARCH_GNU_VTENTRY,        /* type (58).  */
-        0,                                     /* rightshift.  */
-        0,                                     /* size.  */
-        0,                                     /* bitsize.  */
+  LOONGARCH_HOWTO (R_LARCH_GNU_VTENTRY,                /* type (58).  */
+        0,                                     /* rightshift.  */
+        0,                                     /* size.  */
+        0,                                     /* bitsize.  */
         false,                                 /* pc_relative.  */
-        0,                                     /* bitpos.  */
-        complain_overflow_signed,              /* complain_on_overflow.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
         NULL,                                  /* special_function.  */
-        "R_LARCH_GNU_VTENTRY",                 /* name.  */
-        false,                                 /* partial_inplace.  */
+        "R_LARCH_GNU_VTENTRY",                 /* name.  */
+        false,                                 /* partial_inplace.  */
         0,                                     /* src_mask */
         0,                                     /* dst_mask */
         false,                                 /* pcrel_offset */
         BFD_RELOC_NONE,                        /* bfd_reloc_code_real_type */
-        NULL),                                 /* adjust_reloc_bits */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
+
+  LOONGARCH_EMPTY_HOWTO (59),
+  LOONGARCH_EMPTY_HOWTO (60),
+  LOONGARCH_EMPTY_HOWTO (61),
+  LOONGARCH_EMPTY_HOWTO (62),
+  LOONGARCH_EMPTY_HOWTO (63),
+
+  /* New reloc types.  */
+  LOONGARCH_HOWTO (R_LARCH_B16,                        /* type (64).  */
+        2,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        16,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_B16",                         /* name.  */
+        false,                                 /* partial_inplace.  */
+        0x3fffc00,                             /* src_mask */
+        0x3fffc00,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_B16,                   /* bfd_reloc_code_real_type */
+        reloc_bits_b16,                        /* adjust_reloc_bits */
+        "b16"),                                /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_B21,                        /* type (65).  */
+        2,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        21,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_B21",                         /* name.  */
+        false,                                 /* partial_inplace.  */
+        0xfc0003e0,                            /* src_mask */
+        0xfc0003e0,                            /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_B21,                   /* bfd_reloc_code_real_type */
+        reloc_bits_b21,                        /* adjust_reloc_bits */
+        "b21"),                                /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_B26,                        /* type (66).  */
+        2,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        26,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_B26",                         /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x03ffffff,                            /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_B26,                   /* bfd_reloc_code_real_type */
+        reloc_bits_b26,                        /* adjust_reloc_bits */
+        "b26"),                                /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_ABS_HI20,           /* type (67).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ABS_HI20",                    /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_ABS_HI20,              /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "abs_hi20"),                           /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_ABS_LO12,           /* type (68).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_unsigned,            /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ABS_LO12",                    /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_ABS_LO12,              /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "abs_lo12"),                           /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_ABS64_LO20,         /* type (69).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ABS64_LO20",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_ABS64_LO20,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "abs64_lo20"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_ABS64_HI12,         /* type (70).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_ABS64_HI12",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_ABS64_HI12,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "abs64_hi12"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_PCALA_HI20,         /* type (71).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_PCALA_HI20",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_PCALA_HI20,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "pc_hi20"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_PCALA_LO12,         /* type (72).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_PCALA_LO12",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_PCALA_LO12,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "pc_lo12"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_PCALA64_LO20,       /* type (73).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_PCALA64_LO20",                /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_PCALA64_LO20,          /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "pc64_lo20"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_PCALA64_HI12,       /* type (74).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_PCALA64_HI12",                /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_PCALA64_HI12,          /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "pc64_hi12"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT_PC_HI20,                /* type (75).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT_PC_HI20",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT_PC_HI20,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got_pc_hi20"),                        /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT_PC_LO12,                /* type (76).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT_PC_LO12",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT_PC_LO12,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got_pc_lo12"),                        /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT64_PC_LO20,      /* type (77).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT64_PC_LO20",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT64_PC_LO20,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got64_pc_lo20"),                      /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT64_PC_HI12,      /* type (78).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT64_PC_HI12",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT64_PC_HI12,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got64_pc_hi12"),                      /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT_HI20,           /* type (79).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT_HI20",                    /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT_HI20,              /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got_hi20"),                           /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT_LO12,           /* type (80).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT_LO12",                    /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT_LO12,              /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got_lo12"),                           /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT64_LO20,         /* type (81).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT64_LO20",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT64_LO20,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got64_lo20"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_GOT64_HI12,         /* type (82).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_GOT64_HI12",                  /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_GOT64_HI12,            /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "got64_hi12"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE_HI20,                /* type (83).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LE_HI20",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LE_HI20,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "le_hi20"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE_LO12,                /* type (84).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LE_LO12",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LE_LO12,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "le_lo12"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE64_LO20,      /* type (85).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LE64_LO20",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LE64_LO20,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "le64_lo20"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE64_HI12,      /* type (86).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LE64_HI12",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LE64_HI12,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "le64_hi12"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE_PC_HI20,     /* type (87).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE_PC_HI20",              /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE_PC_HI20,        /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie_pc_hi20"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE_PC_LO12,     /* type (88).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_unsigned,            /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE_PC_LO12",              /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE_PC_LO12,        /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie_pc_lo12"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_PC_LO20,   /* type (89).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE64_PC_LO20",            /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE64_PC_LO20,      /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie64_pc_lo20"),                       /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_PC_HI12,   /* type (90).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE64_PC_HI12",            /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE64_PC_HI12,      /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie64_pc_hi12"),                       /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE_HI20,        /* type (91).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE_HI20",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE_HI20,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie_hi20"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE_LO12,                /* type (92).  */
+        0,                                     /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE_LO12",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE_LO12,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie_lo12"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_LO20,      /* type (93).  */
+        32,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE64_LO20",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE64_LO20,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie64_lo20"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_IE64_HI12,      /* type (94).  */
+        52,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        12,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        10,                                    /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_IE64_HI12",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x3ffc00,                              /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_IE64_HI12,         /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ie64_hi12"),                          /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LD_PC_HI20,     /* type (95).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LD_PC_HI20",              /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LD_PC_HI20,        /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ld_pc_hi20"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LD_HI20,                /* type (96).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LD_HI20",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_LD_HI20,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "ld_hi20"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_GD_PC_HI20,     /* type (97).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_GD_PC_HI20",              /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_GD_PC_HI20,        /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "gd_pc_hi20"),                         /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_GD_HI20,                /* type (98).  */
+        12,                                    /* rightshift.  */
+        4,                                     /* size.  */
+        20,                                    /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        5,                                     /* bitpos.  */
+        complain_overflow_signed,              /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_GD_HI20",                 /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask */
+        0x1ffffe0,                             /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_TLS_GD_HI20,           /* bfd_reloc_code_real_type */
+        reloc_bits,                            /* adjust_reloc_bits */
+        "gd_hi20"),                            /* larch_reloc_type_name */
+
+  LOONGARCH_HOWTO (R_LARCH_RELAX,              /* type (99).  */
+        0,                                     /* rightshift */
+        1,                                     /* size */
+        0,                                     /* bitsize */
+        false,                                 /* pc_relative */
+        0,                                     /* bitpos */
+        complain_overflow_dont,                /* complain_on_overflow */
+        bfd_elf_generic_reloc,                 /* special_function */
+        "R_LARCH_RELAX",                       /* name */
+        false,                                 /* partial_inplace */
+        0,                                     /* src_mask */
+        0,                                     /* dst_mask */
+        false,                                 /* pcrel_offset */
+        BFD_RELOC_LARCH_RELAX,                 /* bfd_reloc_code_real_type */
+        NULL,                                  /* adjust_reloc_bits */
+        NULL),                                 /* larch_reloc_type_name */
+
 };
 
 reloc_howto_type *
@@ -697,8 +1357,6 @@ loongarch_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
       if (loongarch_howto_table[r_type].howto.type == r_type)
        return (reloc_howto_type *)&loongarch_howto_table[r_type];
 
-      BFD_ASSERT (loongarch_howto_table[r_type].howto.type == r_type);
-
       for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
        if (loongarch_howto_table[i].howto.type == r_type)
          return (reloc_howto_type *)&loongarch_howto_table[i];
@@ -734,6 +1392,17 @@ loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);
 
+  /* Fast search for new reloc types.  */
+  if (BFD_RELOC_LARCH_B16 <= code && code < BFD_RELOC_LARCH_RELAX)
+    {
+      BFD_ASSERT (BFD_RELOC_LARCH_RELAX - BFD_RELOC_LARCH_B16
+                 == R_LARCH_RELAX - R_LARCH_B16);
+      loongarch_reloc_howto_type *ht = NULL;
+      ht = &loongarch_howto_table[code - BFD_RELOC_LARCH_B16 + R_LARCH_B16];
+      BFD_ASSERT (ht->bfd_type == code);
+      return (reloc_howto_type *)ht;
+    }
+
   for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
     if (loongarch_howto_table[i].bfd_type == code)
       return (reloc_howto_type *)&loongarch_howto_table[i];
@@ -745,56 +1414,89 @@ loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   return NULL;
 }
 
+bfd_reloc_code_real_type
+loongarch_larch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                                  const char *l_r_name)
+{
+  for (size_t i = 0; i < ARRAY_SIZE (loongarch_howto_table); i++)
+    {
+      loongarch_reloc_howto_type *lht = &loongarch_howto_table[i];
+      if ((NULL != lht->larch_reloc_type_name)
+         && (0 == strcmp (lht->larch_reloc_type_name, l_r_name)))
+       return lht->bfd_type;
+    }
+
+  (*_bfd_error_handler) (_("%pB: unsupported relocation type name %s"),
+                        abfd, l_r_name);
+  bfd_set_error (bfd_error_bad_value);
+  return BFD_RELOC_NONE;
+}
+
+
+/* Functions for reloc bits field.
+   1.  Signed extend *fix_val.
+   2.  Return false if overflow.  */
+
 #define LARCH_RELOC_BFD_VMA_BIT_MASK(bitsize) \
   (~((((bfd_vma)0x1) << (bitsize)) - 1))
 
 /* Adjust val to perform insn
- * BFD_RELOC_LARCH_SOP_POP_32_S_10_5
- * BFD_RELOC_LARCH_SOP_POP_32_S_10_12
- * BFD_RELOC_LARCH_SOP_POP_32_U_10_12
- * BFD_RELOC_LARCH_SOP_POP_32_S_10_16
- * BFD_RELOC_LARCH_SOP_POP_32_S_10_16_S2
- * BFD_RELOC_LARCH_SOP_POP_32_S_5_20
- * BFD_RELOC_LARCH_SOP_POP_32_U.
-*/
-
-bool loongarch_gen_adjust_reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val)
+   BFD_RELOC_LARCH_SOP_POP_32_S_10_5
+   BFD_RELOC_LARCH_SOP_POP_32_S_10_12
+   BFD_RELOC_LARCH_SOP_POP_32_U_10_12
+   BFD_RELOC_LARCH_SOP_POP_32_S_10_16
+   BFD_RELOC_LARCH_SOP_POP_32_S_5_20
+   BFD_RELOC_LARCH_SOP_POP_32_U.  */
+static bool
+reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val)
 {
-  bfd_vma val = *fix_val;
-  /* Check val low bits if rightshift != 0, before rightshift  */
-  if (howto->rightshift
-      && (((0x1UL << howto->rightshift) - 1) & val))
+  bfd_signed_vma val = ((bfd_signed_vma)(*fix_val)) >> howto->rightshift;
+
+  /* Perform insn bits field.  */
+  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
+  val <<= howto->bitpos;
+
+  *fix_val = (bfd_vma)val;
+
+  return true;
+}
+
+/* Adjust val to perform insn
+   R_LARCH_SOP_POP_32_S_10_16_S2
+   R_LARCH_B16.  */
+static bool
+reloc_bits_b16 (reloc_howto_type *howto, bfd_vma *fix_val)
+{
+  if (howto->complain_on_overflow != complain_overflow_signed)
+    return false;
+
+  bfd_signed_vma val = *fix_val;
+
+  /* Judge whether 4 bytes align.  */
+  if (val & ((0x1UL << howto->rightshift) - 1))
     return false;
 
   int bitsize = howto->bitsize + howto->rightshift;
+  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
 
-  /* Return false if overflow.  */
-  if (howto->complain_on_overflow == complain_overflow_signed)
+  /* If val < 0, sign bit is 1.  */
+  if (sig_bit)
     {
-      bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
-      /* If val < 0.  */
-      if (sig_bit)
-       {
-         if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
-             != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
-           return false;
-       }
-      else
-       {
-         if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
-           return false;
-       }
+      /* Signed bits is 1.  */
+      if ((LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
+         != LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1))
+       return false;
     }
-  else if (howto->complain_on_overflow == complain_overflow_unsigned)
+  else
     {
+      /* Signed bits is 0.  */
       if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
        return false;
     }
-  else
-    return false;
 
   /* Perform insn bits field.  */
-  val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
+  val >>= howto->rightshift;
+  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
   val <<= howto->bitpos;
 
   *fix_val = val;
@@ -802,22 +1504,24 @@ bool loongarch_gen_adjust_reloc_bits (reloc_howto_type *howto, bfd_vma *fix_val)
   return true;
 }
 
-/* Reloc type R_LARCH_SOP_POP_32_S_0_5_10_16_S2.  */
-bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
-                                            bfd_vma *fix_val)
+/* Reloc type :
+   R_LARCH_SOP_POP_32_S_0_5_10_16_S2
+   R_LARCH_B21.  */
+static bool
+reloc_bits_b21 (reloc_howto_type *howto,
+               bfd_vma *fix_val)
 {
-  bfd_vma val = *fix_val;
-  /* Check val low bits if rightshift != 0, before rightshift  */
-  if (howto->rightshift
-      && (((0x1UL << howto->rightshift) - 1) & val))
+  if (howto->complain_on_overflow != complain_overflow_signed)
     return false;
 
-  /* Return false if overflow.  */
-  if (howto->complain_on_overflow != complain_overflow_signed)
+  bfd_signed_vma val = *fix_val;
+
+  if (val & ((0x1UL << howto->rightshift) - 1))
     return false;
 
   int bitsize = howto->bitsize + howto->rightshift;
-  bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
+  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
+
   /* If val < 0.  */
   if (sig_bit)
     {
@@ -827,14 +1531,15 @@ bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
     }
   else
     {
-      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
+      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
        return false;
     }
 
   /* Perform insn bits field.  */
-  val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
+  val >>= howto->rightshift;
+  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
 
-  /* Perform insn bits field. 20:16>>16, 15:0<<10 */
+  /* Perform insn bits field.  15:0<<10, 20:16>>16.  */
   val = ((val & 0xffff) << 10) | ((val >> 16) & 0x1f);
 
   *fix_val = val;
@@ -842,22 +1547,25 @@ bool loongarch_adjust_reloc_bits_l16_xx5_h5 (reloc_howto_type *howto,
   return true;
 }
 
-/* Reloc type R_LARCH_SOP_POP_32_S_0_10_10_16_S2.  */
-bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
-                                         bfd_vma *fix_val)
+/* Reloc type:
+   R_LARCH_SOP_POP_32_S_0_10_10_16_S2
+   R_LARCH_B26.  */
+static bool
+reloc_bits_b26 (reloc_howto_type *howto,
+               bfd_vma *fix_val)
 {
-  bfd_vma val = *fix_val;
-  /* Check val low bits if rightshift != 0, before rightshift  */
-  if (howto->rightshift
-      && (((0x1UL << howto->rightshift) - 1) & val))
-    return false;
-
   /* Return false if overflow.  */
   if (howto->complain_on_overflow != complain_overflow_signed)
     return false;
 
+  bfd_signed_vma val = *fix_val;
+
+  if (val & ((0x1UL << howto->rightshift) - 1))
+    return false;
+
   int bitsize = howto->bitsize + howto->rightshift;
-  bfd_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
+  bfd_signed_vma sig_bit = (val >> (bitsize - 1)) & 0x1;
+
   /* If val < 0.  */
   if (sig_bit)
     {
@@ -867,14 +1575,15 @@ bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
     }
   else
     {
-      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize - 1) & val)
+      if (LARCH_RELOC_BFD_VMA_BIT_MASK (bitsize) & val)
        return false;
     }
 
   /* Perform insn bits field.  */
-  val = (val & ((0x1U << bitsize) - 1)) >> howto->rightshift;
+  val >>= howto->rightshift;
+  val = val & (((bfd_vma)0x1 << howto->bitsize) - 1);
 
-  /* Perform insn bits field. 25:16>>16, 15:0<<10 */
+  /* Perform insn bits field.  25:16>>16, 15:0<<10.  */
   val = ((val & 0xffff) << 10) | ((val >> 16) & 0x3ff);
 
   *fix_val = val;
@@ -882,8 +1591,9 @@ bool loongarch_adjust_reloc_bits_l16_h10 (reloc_howto_type *howto,
   return true;
 }
 
-bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto,
-                                      bfd_vma *fix_val)
+bool
+loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto,
+                                 bfd_vma *fix_val)
 {
   BFD_ASSERT (((loongarch_reloc_howto_type *)howto)->adjust_reloc_bits);
   return ((loongarch_reloc_howto_type *)
index 8ea63d03fa56e3316b7a687cb6709a30353968ad..7b8a72130f19931a225964819669b5b40ff7a340 100644 (file)
@@ -30,6 +30,10 @@ loongarch_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code);
 extern reloc_howto_type *
 loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name);
 
+extern bfd_reloc_code_real_type
+loongarch_larch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+                                  const char *l_r_name);
+
 bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto, bfd_vma *fix_val);
 
 /* TRUE if this is a PLT reference to a local IFUNC.  */
index 29e8187f95f76592243d0eccf7f8bbe1d271b17b..7eaa75ad11e54a7cbecd732f22e4967bd6e532d0 100644 (file)
@@ -3457,6 +3457,42 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_LARCH_SUB24",
   "BFD_RELOC_LARCH_SUB32",
   "BFD_RELOC_LARCH_SUB64",
+  "BFD_RELOC_LARCH_B16",
+  "BFD_RELOC_LARCH_B21",
+  "BFD_RELOC_LARCH_B26",
+  "BFD_RELOC_LARCH_ABS_HI20",
+  "BFD_RELOC_LARCH_ABS_LO12",
+  "BFD_RELOC_LARCH_ABS64_LO20",
+  "BFD_RELOC_LARCH_ABS64_HI12",
+  "BFD_RELOC_LARCH_PCALA_HI20",
+  "BFD_RELOC_LARCH_PCALA_LO12",
+  "BFD_RELOC_LARCH_PCALA64_LO20",
+  "BFD_RELOC_LARCH_PCALA64_HI12",
+  "BFD_RELOC_LARCH_GOT_PC_HI20",
+  "BFD_RELOC_LARCH_GOT_PC_LO12",
+  "BFD_RELOC_LARCH_GOT64_PC_LO20",
+  "BFD_RELOC_LARCH_GOT64_PC_HI12",
+  "BFD_RELOC_LARCH_GOT_HI20",
+  "BFD_RELOC_LARCH_GOT_LO12",
+  "BFD_RELOC_LARCH_GOT64_LO20",
+  "BFD_RELOC_LARCH_GOT64_HI12",
+  "BFD_RELOC_LARCH_TLS_LE_HI20",
+  "BFD_RELOC_LARCH_TLS_LE_LO12",
+  "BFD_RELOC_LARCH_TLS_LE64_LO20",
+  "BFD_RELOC_LARCH_TLS_LE64_HI12",
+  "BFD_RELOC_LARCH_TLS_IE_PC_HI20",
+  "BFD_RELOC_LARCH_TLS_IE_PC_LO12",
+  "BFD_RELOC_LARCH_TLS_IE64_PC_LO20",
+  "BFD_RELOC_LARCH_TLS_IE64_PC_HI12",
+  "BFD_RELOC_LARCH_TLS_IE_HI20",
+  "BFD_RELOC_LARCH_TLS_IE_LO12",
+  "BFD_RELOC_LARCH_TLS_IE64_LO20",
+  "BFD_RELOC_LARCH_TLS_IE64_HI12",
+  "BFD_RELOC_LARCH_TLS_LD_PC_HI20",
+  "BFD_RELOC_LARCH_TLS_LD_HI20",
+  "BFD_RELOC_LARCH_TLS_GD_PC_HI20",
+  "BFD_RELOC_LARCH_TLS_GD_HI20",
+  "BFD_RELOC_LARCH_RELAX",
  "@@overflow: BFD_RELOC_UNUSED@@",
 };
 #endif
index 36999fe9a403a2dfdbfea84beb3b3d2336b2019e..59c2aaa0d316aa2a8422c0be4874eaee4d56eee3 100644 (file)
@@ -8228,6 +8228,85 @@ ENUMX
   BFD_RELOC_LARCH_SUB32
 ENUMX
   BFD_RELOC_LARCH_SUB64
+
+ENUMX
+  BFD_RELOC_LARCH_B16
+ENUMX
+  BFD_RELOC_LARCH_B21
+ENUMX
+  BFD_RELOC_LARCH_B26
+
+ENUMX
+  BFD_RELOC_LARCH_ABS_HI20
+ENUMX
+  BFD_RELOC_LARCH_ABS_LO12
+ENUMX
+  BFD_RELOC_LARCH_ABS64_LO20
+ENUMX
+  BFD_RELOC_LARCH_ABS64_HI12
+
+ENUMX
+  BFD_RELOC_LARCH_PCALA_HI20
+ENUMX
+  BFD_RELOC_LARCH_PCALA_LO12
+ENUMX
+  BFD_RELOC_LARCH_PCALA64_LO20
+ENUMX
+  BFD_RELOC_LARCH_PCALA64_HI12
+
+ENUMX
+  BFD_RELOC_LARCH_GOT_PC_HI20
+ENUMX
+  BFD_RELOC_LARCH_GOT_PC_LO12
+ENUMX
+  BFD_RELOC_LARCH_GOT64_PC_LO20
+ENUMX
+  BFD_RELOC_LARCH_GOT64_PC_HI12
+ENUMX
+  BFD_RELOC_LARCH_GOT_HI20
+ENUMX
+  BFD_RELOC_LARCH_GOT_LO12
+ENUMX
+  BFD_RELOC_LARCH_GOT64_LO20
+ENUMX
+  BFD_RELOC_LARCH_GOT64_HI12
+
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE_LO12
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE64_LO20
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE64_HI12
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE_PC_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE_PC_LO12
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE64_PC_LO20
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE64_PC_HI12
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE_LO12
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE64_LO20
+ENUMX
+  BFD_RELOC_LARCH_TLS_IE64_HI12
+ENUMX
+  BFD_RELOC_LARCH_TLS_LD_PC_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_LD_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_GD_PC_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_GD_HI20
+
+ENUMX
+  BFD_RELOC_LARCH_RELAX
+
 ENUMDOC
   LARCH relocations.
 
index b7aa4ff069c4ce9c60d046274ad9cc74cb2e5d6b..2d2bb6a51612311fb90f36213a7b9e56ac1adae3 100644 (file)
@@ -90,6 +90,142 @@ RELOC_NUMBER (R_LARCH_SUB64, 56)
 RELOC_NUMBER (R_LARCH_GNU_VTINHERIT, 57)
 RELOC_NUMBER (R_LARCH_GNU_VTENTRY, 58)
 
+
+/* B16:
+   beq/bne/blt/bge/bltu/bgeu/jirl
+   %b16 (sym).  */
+RELOC_NUMBER (R_LARCH_B16, 64)
+/* B21:
+   beqz/bnez
+   %b16 (sym).  */
+RELOC_NUMBER (R_LARCH_B21, 65)
+/* B26:
+   b/bl
+   %b26 (sym) or %plt (sym).  */
+RELOC_NUMBER (R_LARCH_B26, 66)
+
+/* ABS: 32/64
+   lu12i.w
+   %abs_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_ABS_HI20, 67)
+/* ABS: 32/64
+   ori
+   %abs_lo12 (sym).  */
+RELOC_NUMBER (R_LARCH_ABS_LO12, 68)
+
+/* ABS: 64
+   lu32i.d
+   %abs64_lo20 (sym).  */
+RELOC_NUMBER (R_LARCH_ABS64_LO20, 69)
+/* ABS: 64
+   lu52i.d
+   %abs64_hi12 (sym).  */
+RELOC_NUMBER (R_LARCH_ABS64_HI12, 70)
+
+/* PCREL: 32/64
+   pcalau12i
+   %pc_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_PCALA_HI20, 71)
+/* PCREL: 32/64
+   addi.w/addi.d
+   %pc_lo12 (sym).  */
+RELOC_NUMBER (R_LARCH_PCALA_LO12, 72)
+/* PCREL: 64
+   lu32i.d
+   %pc64_lo20 (sym).  */
+RELOC_NUMBER (R_LARCH_PCALA64_LO20, 73)
+/* PCREL: 64
+   lu52i.d
+   %pc64_hi12 (sym).  */
+RELOC_NUMBER (R_LARCH_PCALA64_HI12, 74)
+
+/* GOT: 32/64
+   pcalau12i
+   %got_pc_hi20 (got).  */
+RELOC_NUMBER (R_LARCH_GOT_PC_HI20, 75)
+/* GOT: 32/64
+   ld.w/ld.d
+   %got_pc_lo12 (got).  */
+RELOC_NUMBER (R_LARCH_GOT_PC_LO12, 76)
+/* GOT: 32/64
+   lu32i.d
+   %got_pc_lo12 (got).  */
+RELOC_NUMBER (R_LARCH_GOT64_PC_LO20, 77)
+/* GOT64: PCREL
+   lu52i.d
+   %got64_pc_hi12 (got).  */
+RELOC_NUMBER (R_LARCH_GOT64_PC_HI12, 78)
+/* GOT32/64: ABS
+   lu12i.w
+   %got_hi20 (got).  */
+RELOC_NUMBER (R_LARCH_GOT_HI20, 79)
+/* GOT: 32/64: ABS
+   ori
+   %got_lo12 (got).  */
+RELOC_NUMBER (R_LARCH_GOT_LO12, 80)
+/* GOT64: ABS
+   lu32i.d
+   %got64_lo20 (got).  */
+RELOC_NUMBER (R_LARCH_GOT64_LO20, 81)
+/* GOT64: ABS
+   lu52i.d
+   %got64_hi12 (got).  */
+RELOC_NUMBER (R_LARCH_GOT64_HI12, 82)
+
+/* TLS-LE: 32/64
+   lu12i.w
+   %le_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LE_HI20, 83)
+/* TLS-LE: 32/64
+   ori
+   %le_lo12 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LE_LO12, 84)
+/* TLS-LE: 64
+   lu32i.d
+   %le64_lo20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LE64_LO20, 85)
+/* TLS-LE: 64
+   lu52i.d
+   %le64_hi12 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LE64_HI12, 86)
+
+/* TLS-IE: 32/64
+   pcalau12i
+   %ie_pc_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_IE_PC_HI20, 87)
+RELOC_NUMBER (R_LARCH_TLS_IE_PC_LO12, 88)
+RELOC_NUMBER (R_LARCH_TLS_IE64_PC_LO20, 89)
+RELOC_NUMBER (R_LARCH_TLS_IE64_PC_HI12, 90)
+
+/* TLS-IE: 32/64: ABS
+   lu12i.w
+   %ie_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_IE_HI20, 91)
+RELOC_NUMBER (R_LARCH_TLS_IE_LO12, 92)
+RELOC_NUMBER (R_LARCH_TLS_IE64_LO20, 93)
+RELOC_NUMBER (R_LARCH_TLS_IE64_HI12, 94)
+
+/* TLS-LD: 32/64
+   pcalau12i
+   %ld_pc_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LD_PC_HI20, 95)
+/* TLS-LD: 32/64: ABS
+   lu12i.w
+   %ld_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_LD_HI20, 96)
+
+/* TLS-GD: 32/64
+   pcalau12i
+   %gd_pc_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_GD_PC_HI20, 97)
+/* TLS-GD: 32/64: ABS
+   lu12i.w
+   %gd_hi20 (sym).  */
+RELOC_NUMBER (R_LARCH_TLS_GD_HI20, 98)
+
+/* RELAX.  */
+RELOC_NUMBER (R_LARCH_RELAX, 99)
+
 END_RELOC_NUMBERS (R_LARCH_count)
 
 /* Processor specific flags for the ELF header e_flags field.  */