From aae8784c58d693fa8bc0161b325fc8bcd76d18fc Mon Sep 17 00:00:00 2001 From: changjiachen Date: Thu, 28 Dec 2023 20:07:54 +0800 Subject: [PATCH] LoongArch: bfd: Add support for tls le relax. 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 | Bin 0 -> 16384 bytes bfd/bfd-in2.h | 4 ++ bfd/elfnn-loongarch.c | 105 +++++++++++++++++++++++++++++++++++++ bfd/elfxx-loongarch.c | 55 +++++++++++++++++-- bfd/libbfd.h | 3 ++ bfd/reloc.c | 7 +++ 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 bfd/.elfnn-loongarch.c.swp diff --git a/bfd/.elfnn-loongarch.c.swp b/bfd/.elfnn-loongarch.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..74539aabdd73056a3e5bed1cfa9c166afc362545 GIT binary patch literal 16384 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 literal 0 Hc-jL100001 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 550704ae89f..f04e3692d81 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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 diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index bd448cda453..add916e02f5 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -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, diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c index 4fe8cbff14c..2c40fb02872 100644 --- a/bfd/elfxx-loongarch.c +++ b/bfd/elfxx-loongarch.c @@ -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) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 196e7e55ea6..a52fabdf7c9 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -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", diff --git a/bfd/reloc.c b/bfd/reloc.c index 30852b1422f..3edcbab51e9 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -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 -- 2.39.5