346 lines
12 KiB
Diff
346 lines
12 KiB
Diff
From 7bba42c3fe6dd98cf8f08fc13fcc246f4c7aee90 Mon Sep 17 00:00:00 2001
|
|
From: changjiachen <changjiachen@stu.xupt.edu.cn>
|
|
Date: Thu, 28 Dec 2023 20:07:54 +0800
|
|
Subject: [PATCH 031/123] 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/bfd-in2.h | 4 ++
|
|
bfd/elfnn-loongarch.c | 105 ++++++++++++++++++++++++++++++++++++++++++
|
|
bfd/elfxx-loongarch.c | 55 ++++++++++++++++++++--
|
|
bfd/libbfd.h | 3 ++
|
|
bfd/reloc.c | 7 +++
|
|
5 files changed, 169 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
|
|
index d7b762d4..4e7ad048 100644
|
|
--- a/bfd/bfd-in2.h
|
|
+++ b/bfd/bfd-in2.h
|
|
@@ -7356,11 +7356,15 @@ assembler and not (currently) written to any object files. */
|
|
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 d46bcd77..f7eb66da 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
|
|
@@ -3474,6 +3488,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)
|
|
@@ -3644,6 +3665,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);
|
|
@@ -4082,6 +4104,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
|
|
@@ -4511,6 +4609,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 4fe8cbff..2c40fb02 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 b5af327f..617d5239 100644
|
|
--- a/bfd/libbfd.h
|
|
+++ b/bfd/libbfd.h
|
|
@@ -3538,6 +3538,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 4782f0f6..bb45027c 100644
|
|
--- a/bfd/reloc.c
|
|
+++ b/bfd/reloc.c
|
|
@@ -8188,6 +8188,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.33.0
|
|
|