my_getExpression (expressionS *ep, const char *str)
 {
   char *save_in, *ret;
+
   if (*str == ':')
     {
       unsigned long j;
       char *str_1 = (char *) str;
-      str_1++;
       j = strtol (str_1, &str_1, 10);
       get_internal_label (ep, j, *str_1 == 'f');
       return NULL;
 reloc (const char *op_c_str, const char *id_c_str, offsetT addend)
 {
   expressionS id_sym_expr;
+  bfd_reloc_code_real_type btype;
 
   if (end <= top)
     as_fatal (_("expr too huge"));
 
-  if (id_c_str)
-    {
-      my_getExpression (&id_sym_expr, id_c_str);
-      id_sym_expr.X_add_number += addend;
-    }
+  /* For compatible old asm code.  */
+  if (0 == strcmp (op_c_str, "plt"))
+    btype = BFD_RELOC_LARCH_B26;
   else
-    {
-      id_sym_expr.X_op = O_constant;
-      id_sym_expr.X_add_number = addend;
-    }
+    btype = loongarch_larch_reloc_name_lookup (NULL, op_c_str);
 
-  if (strcmp (op_c_str, "abs") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
-      top++;
-    }
-  else if (strcmp (op_c_str, "pcrel") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_PCREL;
-      top++;
-    }
-  else if (strcmp (op_c_str, "gprel") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_GPREL;
-      top++;
-    }
-  else if (strcmp (op_c_str, "tprel") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL;
-      top++;
-    }
-  else if (strcmp (op_c_str, "tlsgot") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT;
-      top++;
-    }
-  else if (strcmp (op_c_str, "tlsgd") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GD;
-      top++;
-    }
-  else if (strcmp (op_c_str, "plt") == 0)
-    {
-      top->value = id_sym_expr;
-      top->type = BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL;
-      top++;
-    }
+  if (id_c_str)
+  {
+    my_getExpression (&id_sym_expr, id_c_str);
+    id_sym_expr.X_add_number += addend;
+  }
   else
-    as_fatal (_("unknown reloc hint: %s"), op_c_str);
+  {
+    id_sym_expr.X_op = O_constant;
+    id_sym_expr.X_add_number = addend;
+  }
+
+  top->value = id_sym_expr;
+  top->type = btype;
+  top++;
 }
 
 static void
 
 
 static const expressionS const_0 = { .X_op = O_constant, .X_add_number = 0 };
 
-static const char *
-my_getExpression (expressionS *ep, const char *str)
-{
-  char *save_in, *ret;
-  save_in = input_line_pointer;
-  input_line_pointer = (char *) str;
-  expression (ep);
-  ret = input_line_pointer;
-  input_line_pointer = save_in;
-  return ret;
-}
-
 static void
 s_loongarch_align (int arg)
 {
   label_expr->X_add_number = 0;
 }
 
-extern int loongarch_parse_expr (const char *expr,
-                                struct reloc_info *reloc_stack_top,
-                                size_t max_reloc_num, size_t *reloc_num,
-                                offsetT *imm_if_no_reloc);
-
 static int
 is_internal_label (const char *c_str)
 {
            as_fatal (
                      _("not support reloc bit-field\nfmt: %c%c %s\nargs: %s"),
                      esc_ch1, esc_ch2, bit_field, arg);
+         if (ip->reloc_info[0].type >= BFD_RELOC_LARCH_B16
+             && ip->reloc_info[0].type < BFD_RELOC_LARCH_RELAX)
+           {
+             /* As we compact stack-relocs, it is no need for pop operation.
+                But break out until here in order to check the imm field.
+                May be reloc_num > 1 if implement relax?  */
+             ip->reloc_num += reloc_num;
+             break;
+           }
          reloc_num++;
          ip->reloc_num += reloc_num;
          ip->reloc_info[ip->reloc_num - 1].type = reloc_type;
        {
          ase->name_hash_entry = str_htab_create ();
          for (it = ase->opcodes; it->name; it++)
-           str_hash_insert (ase->name_hash_entry, it->name, (void *) it, 0);
+           {
+             if ((!it->include || (it->include && *it->include))
+                 && (!it->exclude || (it->exclude && !(*it->exclude))))
+               str_hash_insert (ase->name_hash_entry, it->name,
+                                (void *) it, 0);
+           }
        }
 
       if ((it = str_hash_find (ase->name_hash_entry, insn->name)) == NULL)
 check_this_insn_before_appending (struct loongarch_cl_insn *ip)
 {
   int ret = 0;
-  if (strcmp (ip->name, "la.abs") == 0)
+
+  if (strncmp (ip->name, "la.abs", 6) == 0)
     {
       ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_MARK_LA;
-      my_getExpression (&ip->reloc_info[ip->reloc_num].value, ip->arg_strs[1]);
+      ip->reloc_info[ip->reloc_num].value = const_0;
       ip->reloc_num++;
     }
   else if (ip->insn->mask == 0xffff8000
       ret = loongarch_expand_macro (insns_buf, arg_strs, NULL, NULL,
                                    sizeof (args_buf));
     }
+
   return ret;
 }
 
   static int64_t stack_top;
   static int last_reloc_is_sop_push_pcrel_1 = 0;
   int last_reloc_is_sop_push_pcrel = last_reloc_is_sop_push_pcrel_1;
+  segT sub_segment;
   last_reloc_is_sop_push_pcrel_1 = 0;
 
   char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
     case BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL:
     case BFD_RELOC_LARCH_SOP_PUSH_TLS_GD:
     case BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT:
-    case BFD_RELOC_LARCH_SOP_PUSH_PCREL:
-    case BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL:
+    case BFD_RELOC_LARCH_TLS_LE_HI20:
+    case BFD_RELOC_LARCH_TLS_LE_LO12:
+    case BFD_RELOC_LARCH_TLS_LE64_LO20:
+    case BFD_RELOC_LARCH_TLS_LE64_HI12:
+    case BFD_RELOC_LARCH_TLS_IE_PC_HI20:
+    case BFD_RELOC_LARCH_TLS_IE_PC_LO12:
+    case BFD_RELOC_LARCH_TLS_IE64_PC_LO20:
+    case BFD_RELOC_LARCH_TLS_IE64_PC_HI12:
+    case BFD_RELOC_LARCH_TLS_IE_HI20:
+    case BFD_RELOC_LARCH_TLS_IE_LO12:
+    case BFD_RELOC_LARCH_TLS_IE64_LO20:
+    case BFD_RELOC_LARCH_TLS_IE64_HI12:
+    case BFD_RELOC_LARCH_TLS_LD_PC_HI20:
+    case BFD_RELOC_LARCH_TLS_LD_HI20:
+    case BFD_RELOC_LARCH_TLS_GD_PC_HI20:
+    case BFD_RELOC_LARCH_TLS_GD_HI20:
+      /* Add tls lo (got_lo reloc type).  */
       if (fixP->fx_addsy == NULL)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      _("Relocation against a constant"));
+      S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      break;
 
-      if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL
-         || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GD
-         || fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT)
-       S_SET_THREAD_LOCAL (fixP->fx_addsy);
+    case BFD_RELOC_LARCH_SOP_PUSH_PCREL:
+      if (fixP->fx_addsy == NULL)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("Relocation against a constant"));
 
-      if (fixP->fx_r_type == BFD_RELOC_LARCH_SOP_PUSH_PCREL)
-       {
-         last_reloc_is_sop_push_pcrel_1 = 1;
-         if (S_GET_SEGMENT (fixP->fx_addsy) == seg)
-           stack_top = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
-                        - (fixP->fx_where + fixP->fx_frag->fr_address));
-         else
-           stack_top = 0;
-       }
+      last_reloc_is_sop_push_pcrel_1 = 1;
+      if (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+       stack_top = (S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset
+                    - (fixP->fx_where + fixP->fx_frag->fr_address));
+      else
+       stack_top = 0;
       break;
 
     case BFD_RELOC_LARCH_SOP_POP_32_S_10_5:
 
     case BFD_RELOC_64:
     case BFD_RELOC_32:
+    case BFD_RELOC_24:
+    case BFD_RELOC_16:
+    case BFD_RELOC_8:
+
+      if (fixP->fx_r_type == BFD_RELOC_32
+         && fixP->fx_addsy && fixP->fx_subsy
+         && (sub_segment = S_GET_SEGMENT (fixP->fx_subsy))
+         && strcmp (sub_segment->name, ".eh_frame") == 0
+         && S_GET_VALUE (fixP->fx_subsy)
+         == fixP->fx_frag->fr_address + fixP->fx_where)
+       {
+         fixP->fx_r_type = BFD_RELOC_LARCH_32_PCREL;
+         fixP->fx_subsy = NULL;
+         break;
+       }
+
       if (fixP->fx_subsy)
        {
-       case BFD_RELOC_24:
-       case BFD_RELOC_16:
-       case BFD_RELOC_8:
          fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
          fixP->fx_next->fx_addsy = fixP->fx_subsy;
          fixP->fx_next->fx_subsy = NULL;
        }
       break;
 
+    case BFD_RELOC_LARCH_B16:
+    case BFD_RELOC_LARCH_B21:
+    case BFD_RELOC_LARCH_B26:
+      if (fixP->fx_addsy == NULL)
+       {
+         as_bad_where (fixP->fx_file, fixP->fx_line,
+                       _ ("Relocation against a constant."));
+       }
+      if (S_GET_SEGMENT (fixP->fx_addsy) == seg
+         && !S_FORCE_RELOC (fixP->fx_addsy, 1))
+       {
+         int64_t sym_addend = S_GET_VALUE (fixP->fx_addsy) + fixP->fx_offset;
+         int64_t pc = fixP->fx_where + fixP->fx_frag->fr_address;
+         fix_reloc_insn (fixP, sym_addend - pc, buf);
+         fixP->fx_done = 1;
+       }
+
+      break;
+
     default:
       break;
     }
   return 0;
 }
 
+int
+loongarch_fix_adjustable (fixS *fix)
+{
+  /* Prevent all adjustments to global symbols.  */
+  if (S_IS_EXTERNAL (fix->fx_addsy)
+      || S_IS_WEAK (fix->fx_addsy)
+      || S_FORCE_RELOC (fix->fx_addsy, true))
+    return 0;
+
+  return 1;
+}
+
 /* Translate internal representation of relocation info to BFD target
    format.  */
 arelent *
   cfi_add_CFA_def_cfa_register (3 /* $sp */);
 }
 
-int
-loongarch_dwarf2_addr_size (void)
-{
-  return LARCH_opts.ase_lp64 ? 8 : 4;
-}
-
 void
 tc_loongarch_parse_to_dw2regnum (expressionS *exp)
 {