]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: bfd: Add support for tls le relax.
authorchangjiachen <changjiachen@stu.xupt.edu.cn>
Thu, 28 Dec 2023 12:07:54 +0000 (20:07 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Fri, 29 Dec 2023 07:11:00 +0000 (15:11 +0800)
Add tls le relax support and related relocs in bfd.

New relocation related explanation can refer to the following url:
https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc

This support does two main things:

1. Implement support for three new relocation items in bfd.

The three new relocation items are shown below:

R_LARCH_TLS_LE_ADD_R
R_LARCH_TLS_LE_HI20_R
R_LARCH_TLS_LE_LO12_R

2. ADD a new macro RELOCATE_TLS_TP32_HI20

Handle problems caused by symbol extensions in TLS LE, The processing
is similar to the macro RELOCATE_CALC_PC32_HI20 method.

3. Implement the tls le relax function.

bfd/ChangeLog:

* bfd-in2.h: Add relocs related to tls le relax.
* elfnn-loongarch.c:
(loongarch_relax_tls_le): New function.
(RELOCATE_TLS_TP32_HI20): New macro.
(loongarch_elf_check_relocs): Add new reloc support.
(perform_relocation): Likewise.
(loongarch_elf_relocate_section): Handle new relocs related to relax.
(loongarch_elf_relax_section): Likewise.
* elfxx-loongarch.c:
(LOONGARCH_HOWTO (R_LARCH_TLS_LE_ADD_R)): New reloc how to type.
(LOONGARCH_HOWTO (R_LARCH_TLS_LE_HI20_R)): Likewise.
(LOONGARCH_HOWTO (R_LARCH_TLS_LE_LO12_R)): Likewise.
* libbfd.h: Add relocs related to tls le relax.
* reloc.c: Likewise.

bfd/.elfnn-loongarch.c.swp [new file with mode: 0644]
bfd/bfd-in2.h
bfd/elfnn-loongarch.c
bfd/elfxx-loongarch.c
bfd/libbfd.h
bfd/reloc.c

diff --git a/bfd/.elfnn-loongarch.c.swp b/bfd/.elfnn-loongarch.c.swp
new file mode 100644 (file)
index 0000000..74539aa
Binary files /dev/null and b/bfd/.elfnn-loongarch.c.swp differ
index 550704ae89fb6d23f1114b192c146e05abc6ed04..f04e3692d8149fec4aa286dc5f09d226880657a4 100644 (file)
@@ -7476,11 +7476,15 @@ enum bfd_reloc_code_real
   BFD_RELOC_LARCH_TLS_DESC64_HI12,
   BFD_RELOC_LARCH_TLS_DESC_LD,
   BFD_RELOC_LARCH_TLS_DESC_CALL,
+  BFD_RELOC_LARCH_TLS_LE_HI20_R,
+  BFD_RELOC_LARCH_TLS_LE_ADD_R,
+  BFD_RELOC_LARCH_TLS_LE_LO12_R,
   BFD_RELOC_LARCH_TLS_LD_PCREL20_S2,
   BFD_RELOC_LARCH_TLS_GD_PCREL20_S2,
   BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2,
   BFD_RELOC_UNUSED
 };
+
 typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
 
 reloc_howto_type *bfd_reloc_type_lookup
index bd448cda4534f47bf874ba11e6d7ad68bd9a925f..add916e02f5fbb9f7c9645412668cc3f8ff61629 100644 (file)
@@ -858,6 +858,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
        case R_LARCH_TLS_LE_HI20:
+       case R_LARCH_TLS_LE_HI20_R:
        case R_LARCH_SOP_PUSH_TLS_TPREL:
          if (!bfd_link_executable (info))
            return false;
@@ -2261,6 +2262,8 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
     case R_LARCH_GOT64_HI12:
     case R_LARCH_TLS_LE_HI20:
     case R_LARCH_TLS_LE_LO12:
+    case R_LARCH_TLS_LE_HI20_R:
+    case R_LARCH_TLS_LE_LO12_R:
     case R_LARCH_TLS_LE64_LO20:
     case R_LARCH_TLS_LE64_HI12:
     case R_LARCH_TLS_IE_PC_HI20:
@@ -2303,6 +2306,7 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
       break;
 
     case R_LARCH_RELAX:
+    case R_LARCH_TLS_LE_ADD_R:
       break;
 
     default:
@@ -2483,6 +2487,16 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
        relocation += 0x1000;                           \
   })
 
+/* Handle problems caused by symbol extensions in TLS LE, The processing
+   is similar to the macro RELOCATE_CALC_PC32_HI20 method.  */
+#define RELOCATE_TLS_TP32_HI20(relocation)             \
+  ({                                                   \
+    bfd_vma __lo = (relocation) & ((bfd_vma)0xfff);    \
+    if (__lo > 0x7ff)                                  \
+       relocation += 0x800;                            \
+    relocation = relocation & ~(bfd_vma)0xfff;         \
+  })
+
 /* For example: pc is 0x11000010000100, symbol is 0x1812348ffff812
    offset = (0x1812348ffff812 & ~0xfff) - (0x11000010000100 & ~0xfff)
          = 0x712347ffff000
@@ -3481,6 +3495,13 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
          break;
 
+       case R_LARCH_TLS_LE_HI20_R:
+         relocation -= elf_hash_table (info)->tls_sec->vma;
+
+         RELOCATE_TLS_TP32_HI20 (relocation);
+
+         break;
+
        case R_LARCH_PCALA_LO12:
          /* Not support if sym_addr in 2k page edge.
             pcalau12i pc_hi20 (sym_addr)
@@ -3651,6 +3672,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
        case R_LARCH_TLS_LE_HI20:
        case R_LARCH_TLS_LE_LO12:
+       case R_LARCH_TLS_LE_LO12_R:
        case R_LARCH_TLS_LE64_LO20:
        case R_LARCH_TLS_LE64_HI12:
          BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec);
@@ -4089,6 +4111,82 @@ loongarch_relax_delete_bytes (bfd *abfd,
 
   return true;
 }
+/*  Relax tls le, mainly relax the process of getting TLS le symbolic addresses.
+  there are three situations in which an assembly instruction sequence needs to
+  be relaxed:
+  symbol address = tp + offset (symbol),offset (symbol) = le_hi20_r + le_lo12_r
+
+  Case 1:
+  in this case, the rd register in the st.{w/d} instruction does not store the
+  full tls symbolic address, but tp + le_hi20_r, which is a part of the tls
+  symbolic address, and then obtains the rd + le_lo12_r address through the
+  st.w instruction feature.
+  this is the full tls symbolic address (tp + le_hi20_r + le_lo12_r).
+
+  before relax:                                after relax:
+
+  lu12i.w   $rd,%le_hi20_r (sym)       ==> (instruction deleted)
+  add.{w/d} $rd,$rd,$tp,%le_add_r (sym) ==> (instruction deleted)
+  st.{w/d}  $rs,$rd,%le_lo12_r (sym)    ==> st.{w/d}   $rs,$tp,%le_lo12_r (sym)
+
+  Case 2:
+  in this case, ld.{w/d} is similar to st.{w/d} in case1.
+
+  before relax:                                after relax:
+
+  lu12i.w   $rd,%le_hi20_r (sym)       ==> (instruction deleted)
+  add.{w/d} $rd,$rd,$tp,%le_add_r (sym) ==> (instruction deleted)
+  ld.{w/d}  $rs,$rd,%le_lo12_r (sym)    ==> ld.{w/d}   $rs,$tp,%le_lo12_r (sym)
+
+  Case 3:
+  in this case,the rs register in addi.{w/d} stores the full address of the tls
+  symbol (tp + le_hi20_r + le_lo12_r).
+
+  before relax:                                after relax:
+
+  lu12i.w    $rd,%le_hi20_r (sym)       ==> (instruction deleted)
+  add.{w/d}  $rd,$rd,$tp,%le_add_r (sym) ==> (instruction deleted)
+  addi.{w/d} $rs,$rd,%le_lo12_r (sym)    ==> addi.{w/d} $rs,$tp,%le_lo12_r (sym)
+*/
+static bool
+loongarch_relax_tls_le (bfd *abfd, asection *sec,
+                       Elf_Internal_Rela *rel,
+                       struct bfd_link_info *link_info,
+                       bfd_vma symval)
+{
+  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
+  uint32_t insn = bfd_get (32, abfd, contents + rel->r_offset);
+  static uint32_t insn_rj,insn_rd;
+  symval = symval - elf_hash_table (link_info)->tls_sec->vma;
+  /* Whether the symbol offset is in the interval (offset < 0x800).  */
+  if (ELFNN_R_TYPE ((rel + 1)->r_info == R_LARCH_RELAX) && (symval < 0x800))
+    {
+      switch (ELFNN_R_TYPE (rel->r_info))
+       {
+       case R_LARCH_TLS_LE_HI20_R:
+       case R_LARCH_TLS_LE_ADD_R:
+         /* delete insn.  */
+         rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+         loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info);
+         break;
+       case R_LARCH_TLS_LE_LO12_R:
+         /* Change rj to $tp.  */
+         insn_rj = 0x2 << 5;
+         /* Get rd register.  */
+         insn_rd = insn & 0x1f;
+         /* Write symbol offset.  */
+         symval <<= 10;
+         /* Writes the modified instruction.  */
+         insn = insn & 0xffc00000;
+         insn = insn | symval | insn_rj | insn_rd;
+         bfd_put (32, abfd, insn, contents + rel->r_offset);
+         break;
+       default:
+         break;
+       }
+    }
+  return true;
+}
 
 /* Relax pcalau12i,addi.d => pcaddi.  */
 static bool
@@ -4518,6 +4616,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
              rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
            }
          break;
+       case R_LARCH_TLS_LE_HI20_R:
+       case R_LARCH_TLS_LE_LO12_R:
+       case R_LARCH_TLS_LE_ADD_R:
+         if (0 == info->relax_pass && (i + 2) <= sec->reloc_count)
+           loongarch_relax_tls_le (abfd, sec, rel, info, symval);
+         break;
+
        case R_LARCH_PCALA_HI20:
          if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
            loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
index 4fe8cbff14cdc09d871adfb183f032074f1f108c..2c40fb028725825b554f2e574b6a5bbe83961225 100644 (file)
@@ -1776,9 +1776,56 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         NULL,                                  /* adjust_reloc_bits.  */
         "desc_call"),                          /* larch_reloc_type_name.  */
 
-  LOONGARCH_EMPTY_HOWTO (121),
-  LOONGARCH_EMPTY_HOWTO (122),
-  LOONGARCH_EMPTY_HOWTO (123),
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE_HI20_R,      /* type (121).  */
+        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_R",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask.  */
+        0x1ffffe0,                             /* dst_mask.  */
+        false,                                 /* pcrel_offset.  */
+        BFD_RELOC_LARCH_TLS_LE_HI20_R,         /* bfd_reloc_code_real_type.  */
+        reloc_bits,                            /* adjust_reloc_bits.  */
+        "le_hi20_r"),                          /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE_ADD_R,       /* type (122).  */
+        0,                                     /* rightshift.  */
+        0,                                     /* size.  */
+        0,                                     /* bitsize.  */
+        false,                                 /* pc_relative.  */
+        0,                                     /* bitpos.  */
+        complain_overflow_dont,                /* complain_on_overflow.  */
+        bfd_elf_generic_reloc,                 /* special_function.  */
+        "R_LARCH_TLS_LE_ADD_R",                /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask.  */
+        0,                                     /* dst_mask.  */
+        false,                                 /* pcrel_offset.  */
+        BFD_RELOC_LARCH_TLS_LE_ADD_R,          /* bfd_reloc_code_real_type.  */
+        NULL,                                  /* adjust_reloc_bits.  */
+        "le_add_r"),                           /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_LE_LO12_R,      /* type (123).  */
+        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_R",               /* name.  */
+        false,                                 /* partial_inplace.  */
+        0,                                     /* src_mask.  */
+        0x3ffc00,                              /* dst_mask.  */
+        false,                                 /* pcrel_offset.  */
+        BFD_RELOC_LARCH_TLS_LE_LO12_R,         /* bfd_reloc_code_real_type.  */
+        reloc_bits,                            /* adjust_reloc_bits.  */
+        "le_lo12_r"),                          /* larch_reloc_type_name.  */
 
   /* For pcaddi, ld_pc_hi20 + ld_pc_lo12 can relax to ld_pcrel20_s2.  */
   LOONGARCH_HOWTO (R_LARCH_TLS_LD_PCREL20_S2,  /* type (124).  */
@@ -1870,9 +1917,7 @@ reloc_howto_type *
 loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
                             bfd_reloc_code_real_type code)
 {
-  /*
   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)
index 196e7e55ea644b6def33032998e9c494db6dd838..a52fabdf7c9bcf0f31c24b59c57c0d39d13c1f5c 100644 (file)
@@ -3615,6 +3615,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_LARCH_TLS_DESC64_HI12",
   "BFD_RELOC_LARCH_TLS_DESC_LD",
   "BFD_RELOC_LARCH_TLS_DESC_CALL",
+  "BFD_RELOC_LARCH_TLS_LE_HI20_R",
+  "BFD_RELOC_LARCH_TLS_LE_ADD_R",
+  "BFD_RELOC_LARCH_TLS_LE_LO12_R",
   "BFD_RELOC_LARCH_TLS_LD_PCREL20_S2",
   "BFD_RELOC_LARCH_TLS_GD_PCREL20_S2",
   "BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2",
index 30852b1422fd6afb91614a564ee35401b5b8cad0..3edcbab51e9a6fa4a8bee59c0f174734e130073a 100644 (file)
@@ -8330,6 +8330,13 @@ ENUMX
 ENUMX
   BFD_RELOC_LARCH_TLS_DESC_CALL
 
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE_HI20_R
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE_ADD_R
+ENUMX
+  BFD_RELOC_LARCH_TLS_LE_LO12_R
+
 ENUMX
   BFD_RELOC_LARCH_TLS_LD_PCREL20_S2
 ENUMX