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.
This commit is contained in:
changjiachen
2023-12-28 20:07:54 +08:00
committed by liuzhensong
parent 77d242a06e
commit aae8784c58
6 changed files with 169 additions and 5 deletions

BIN
bfd/.elfnn-loongarch.c.swp Normal file

Binary file not shown.

View File

@@ -7476,11 +7476,15 @@ enum bfd_reloc_code_real
BFD_RELOC_LARCH_TLS_DESC64_HI12, BFD_RELOC_LARCH_TLS_DESC64_HI12,
BFD_RELOC_LARCH_TLS_DESC_LD, BFD_RELOC_LARCH_TLS_DESC_LD,
BFD_RELOC_LARCH_TLS_DESC_CALL, 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_LD_PCREL20_S2,
BFD_RELOC_LARCH_TLS_GD_PCREL20_S2, BFD_RELOC_LARCH_TLS_GD_PCREL20_S2,
BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2, BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2,
BFD_RELOC_UNUSED BFD_RELOC_UNUSED
}; };
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
reloc_howto_type *bfd_reloc_type_lookup reloc_howto_type *bfd_reloc_type_lookup

View File

@@ -858,6 +858,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
break; break;
case R_LARCH_TLS_LE_HI20: case R_LARCH_TLS_LE_HI20:
case R_LARCH_TLS_LE_HI20_R:
case R_LARCH_SOP_PUSH_TLS_TPREL: case R_LARCH_SOP_PUSH_TLS_TPREL:
if (!bfd_link_executable (info)) if (!bfd_link_executable (info))
return false; return false;
@@ -2261,6 +2262,8 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
case R_LARCH_GOT64_HI12: case R_LARCH_GOT64_HI12:
case R_LARCH_TLS_LE_HI20: case R_LARCH_TLS_LE_HI20:
case R_LARCH_TLS_LE_LO12: 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_LO20:
case R_LARCH_TLS_LE64_HI12: case R_LARCH_TLS_LE64_HI12:
case R_LARCH_TLS_IE_PC_HI20: case R_LARCH_TLS_IE_PC_HI20:
@@ -2303,6 +2306,7 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
break; break;
case R_LARCH_RELAX: case R_LARCH_RELAX:
case R_LARCH_TLS_LE_ADD_R:
break; break;
default: default:
@@ -2483,6 +2487,16 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
relocation += 0x1000; \ 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 /* For example: pc is 0x11000010000100, symbol is 0x1812348ffff812
offset = (0x1812348ffff812 & ~0xfff) - (0x11000010000100 & ~0xfff) offset = (0x1812348ffff812 & ~0xfff) - (0x11000010000100 & ~0xfff)
= 0x712347ffff000 = 0x712347ffff000
@@ -3481,6 +3495,13 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
break; 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: case R_LARCH_PCALA_LO12:
/* Not support if sym_addr in 2k page edge. /* Not support if sym_addr in 2k page edge.
pcalau12i pc_hi20 (sym_addr) 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_HI20:
case R_LARCH_TLS_LE_LO12: case R_LARCH_TLS_LE_LO12:
case R_LARCH_TLS_LE_LO12_R:
case R_LARCH_TLS_LE64_LO20: case R_LARCH_TLS_LE64_LO20:
case R_LARCH_TLS_LE64_HI12: case R_LARCH_TLS_LE64_HI12:
BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec); BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec);
@@ -4089,6 +4111,82 @@ loongarch_relax_delete_bytes (bfd *abfd,
return true; 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. */ /* Relax pcalau12i,addi.d => pcaddi. */
static bool static bool
@@ -4518,6 +4616,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE); rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
} }
break; 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: case R_LARCH_PCALA_HI20:
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count) if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval, loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,

View File

@@ -1776,9 +1776,56 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
NULL, /* adjust_reloc_bits. */ NULL, /* adjust_reloc_bits. */
"desc_call"), /* larch_reloc_type_name. */ "desc_call"), /* larch_reloc_type_name. */
LOONGARCH_EMPTY_HOWTO (121), LOONGARCH_HOWTO (R_LARCH_TLS_LE_HI20_R, /* type (121). */
LOONGARCH_EMPTY_HOWTO (122), 12, /* rightshift. */
LOONGARCH_EMPTY_HOWTO (123), 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. */ /* For pcaddi, ld_pc_hi20 + ld_pc_lo12 can relax to ld_pcrel20_s2. */
LOONGARCH_HOWTO (R_LARCH_TLS_LD_PCREL20_S2, /* type (124). */ 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, loongarch_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code) bfd_reloc_code_real_type code)
{ {
/*
BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count); BFD_ASSERT (ARRAY_SIZE (loongarch_howto_table) == R_LARCH_count);
*/
/* Fast search for new reloc types. */ /* Fast search for new reloc types. */
if (BFD_RELOC_LARCH_B16 <= code && code < BFD_RELOC_LARCH_RELAX) if (BFD_RELOC_LARCH_B16 <= code && code < BFD_RELOC_LARCH_RELAX)

View 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_DESC64_HI12",
"BFD_RELOC_LARCH_TLS_DESC_LD", "BFD_RELOC_LARCH_TLS_DESC_LD",
"BFD_RELOC_LARCH_TLS_DESC_CALL", "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_LD_PCREL20_S2",
"BFD_RELOC_LARCH_TLS_GD_PCREL20_S2", "BFD_RELOC_LARCH_TLS_GD_PCREL20_S2",
"BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2", "BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2",

View File

@@ -8330,6 +8330,13 @@ ENUMX
ENUMX ENUMX
BFD_RELOC_LARCH_TLS_DESC_CALL 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 ENUMX
BFD_RELOC_LARCH_TLS_LD_PCREL20_S2 BFD_RELOC_LARCH_TLS_LD_PCREL20_S2
ENUMX ENUMX