5 Star 0 Fork 13

OpenCloudOS Stream/binutils

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
LoongArch-Optimize-the-relaxation-process.patch 17.50 KB
一键复制 编辑 原始数据 按行查看 历史
油屋 提交于 2024-11-07 15:00 . sync from upstream
From 4c19c0fd7815a9acabdca9954028f772da1d985e Mon Sep 17 00:00:00 2001
From: mengqinggang <[email protected]>
Date: Thu, 10 Oct 2024 16:20:52 +0800
Subject: [PATCH 116/123] LoongArch: Optimize the relaxation process
The symbol value is only calculated when the relocation can be relaxed.
---
bfd/elfnn-loongarch.c | 281 +++++++++++++++++++++---------------------
1 file changed, 139 insertions(+), 142 deletions(-)
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index b6d7d1e8..70522fae 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -4072,7 +4072,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
/* For 2G jump, generate pcalau12i, jirl. */
/* If use jirl, turns to R_LARCH_B16. */
uint32_t insn = bfd_get (32, input_bfd, contents + rel->r_offset);
- if (LARCH_INSN_JIRL(insn))
+ if (LARCH_INSN_JIRL (insn))
{
relocation &= 0xfff;
/* Signed extend. */
@@ -4852,9 +4852,11 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec,
*/
static bool
loongarch_relax_tls_le (bfd *abfd, asection *sec,
- Elf_Internal_Rela *rel,
+ asection *sym_sec ATTRIBUTE_UNUSED,
+ Elf_Internal_Rela *rel, bfd_vma symval,
struct bfd_link_info *link_info,
- bfd_vma symval)
+ bool *agin ATTRIBUTE_UNUSED,
+ bfd_vma max_alignment ATTRIBUTE_UNUSED)
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
uint32_t insn = bfd_get (32, abfd, contents + rel->r_offset);
@@ -4862,7 +4864,7 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec,
symval = symval - elf_hash_table (link_info)->tls_sec->vma;
/* The old LE instruction sequence can be relaxed when the symbol offset
is smaller than the 12-bit range. */
- if (ELFNN_R_TYPE ((rel + 1)->r_info) == R_LARCH_RELAX && (symval <= 0xfff))
+ if (symval <= 0xfff)
{
switch (ELFNN_R_TYPE (rel->r_info))
{
@@ -4975,9 +4977,6 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec,
/* Is pcalau12i + addi.d insns? */
if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_PCALA_LO12)
- || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX)
- || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX)
- || (rel_hi->r_offset + 4 != rel_lo->r_offset)
|| !LARCH_INSN_ADDI_D(add)
/* Is pcalau12i $rd + addi.d $rd,$rd? */
|| (LARCH_GET_RD(add) != rd)
@@ -5035,10 +5034,8 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec,
else if (symval < pc)
pc += (max_alignment > 4 ? max_alignment : 0);
-
/* Is pcalau12i + addi.d insns? */
- if ((ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX)
- || !LARCH_INSN_JIRL(jirl)
+ if (!LARCH_INSN_JIRL (jirl)
|| ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xf8000000)
|| ((bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x7fffffc))
return false;
@@ -5064,7 +5061,12 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec,
/* Relax pcalau12i,ld.d => pcalau12i,addi.d. */
static bool
loongarch_relax_pcala_ld (bfd *abfd, asection *sec,
- Elf_Internal_Rela *rel_hi)
+ asection *sym_sec ATTRIBUTE_UNUSED,
+ Elf_Internal_Rela *rel_hi,
+ bfd_vma symval ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ bool *again ATTRIBUTE_UNUSED,
+ bfd_vma max_alignment ATTRIBUTE_UNUSED)
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
Elf_Internal_Rela *rel_lo = rel_hi + 2;
@@ -5074,9 +5076,6 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec,
uint32_t addi_d = LARCH_OP_ADDI_D;
if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12)
- || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX)
- || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX)
- || (rel_hi->r_offset + 4 != rel_lo->r_offset)
|| (LARCH_GET_RD(ld) != rd)
|| (LARCH_GET_RJ(ld) != rd)
|| !LARCH_INSN_LD_D(ld))
@@ -5106,11 +5105,12 @@ bfd_elfNN_loongarch_set_data_segment_info (struct bfd_link_info *info,
/* Implement R_LARCH_ALIGN by deleting excess alignment NOPs.
Once we've handled an R_LARCH_ALIGN, we can't relax anything else. */
static bool
-loongarch_relax_align (bfd *abfd, asection *sec,
- asection *sym_sec,
- struct bfd_link_info *link_info,
+loongarch_relax_align (bfd *abfd, asection *sec, asection *sym_sec,
Elf_Internal_Rela *rel,
- bfd_vma symval)
+ bfd_vma symval ATTRIBUTE_UNUSED,
+ struct bfd_link_info *link_info,
+ bool *again ATTRIBUTE_UNUSED,
+ bfd_vma max_alignment ATTRIBUTE_UNUSED)
{
bfd_vma addend, max = 0, alignment = 1;
@@ -5198,9 +5198,6 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec,
/* Is pcalau12i + addi.d insns? */
if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12
&& ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_TLS_DESC_PC_LO12)
- || (ELFNN_R_TYPE ((rel_lo + 1)->r_info) != R_LARCH_RELAX)
- || (ELFNN_R_TYPE ((rel_hi + 1)->r_info) != R_LARCH_RELAX)
- || (rel_hi->r_offset + 4 != rel_lo->r_offset)
|| !LARCH_INSN_ADDI_D(add)
/* Is pcalau12i $rd + addi.d $rd,$rd? */
|| (LARCH_GET_RD(add) != rd)
@@ -5257,12 +5254,18 @@ loongarch_get_max_alignment (asection *sec)
return (bfd_vma) 1 << max_alignment_power;
}
+typedef bool (*relax_func_t) (bfd *, asection *, asection *,
+ Elf_Internal_Rela *, bfd_vma,
+ struct bfd_link_info *, bool *,
+ bfd_vma);
+
static bool
loongarch_elf_relax_section (bfd *abfd, asection *sec,
struct bfd_link_info *info,
bool *again)
{
*again = false;
+
if (!is_elf_hash_table (info->hash)
|| elf_hash_table_id (elf_hash_table (info)) != LARCH_ELF_DATA)
return true;
@@ -5277,13 +5280,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
if (bfd_link_relocatable (info)
|| sec->sec_flg0
- || (sec->flags & SEC_RELOC) == 0
|| sec->reloc_count == 0
+ || (sec->flags & SEC_RELOC) == 0
+ || (sec->flags & SEC_HAS_CONTENTS) == 0
+ /* The exp_seg_relro_adjust is enum phase_enum (0x4). */
+ || *(htab->data_segment_phase) == 4
|| (info->disable_target_specific_optimizations
- && info->relax_pass == 0)
- /* The exp_seg_relro_adjust is enum phase_enum (0x4),
- and defined in ld/ldexp.h. */
- || *(htab->data_segment_phase) == 4)
+ && info->relax_pass == 0))
return true;
struct bfd_elf_section_data *data = elf_section_data (sec);
@@ -5293,11 +5296,14 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
else if (!(relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
info->keep_memory)))
return true;
+ data->relocs = relocs;
+ /* Read this BFD's contents if we haven't done so already. */
if (!data->this_hdr.contents
&& !bfd_malloc_and_get_section (abfd, sec, &data->this_hdr.contents))
return true;
+ /* Read this BFD's symbols if we haven't done so already. */
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
if (symtab_hdr->sh_info != 0
&& !symtab_hdr->contents
@@ -5307,8 +5313,6 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
0, NULL, NULL, NULL)))
return true;
- data->relocs = relocs;
-
/* Estimate the maximum alignment for all output sections once time
should be enough. */
bfd_vma max_alignment = htab->max_alignment;
@@ -5330,6 +5334,93 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = elf_sym_hashes (abfd)[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ /* If the conditions for tls type transition are met, type
+ transition is performed instead of relax.
+ During the transition from DESC->IE/LE, there are 2 situations
+ depending on the different configurations of the relax/norelax
+ option.
+ If the -relax option is used, the extra nops will be removed,
+ and this transition is performed in pass 0.
+ If the --no-relax option is used, nop will be retained, and
+ this transition is performed in pass 1. */
+ if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
+ && (i + 1 != sec->reloc_count)
+ && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
+ && rel->r_offset == rel[1].r_offset
+ && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
+ {
+ loongarch_tls_perform_trans (abfd, sec, rel, h, info);
+ r_type = ELFNN_R_TYPE (rel->r_info);
+ }
+
+ relax_func_t relax_func = NULL;
+ if (info->relax_pass == 0)
+ {
+ switch (r_type)
+ {
+ case R_LARCH_PCALA_HI20:
+ relax_func = loongarch_relax_pcala_addi;
+ break;
+ case R_LARCH_GOT_PC_HI20:
+ relax_func = loongarch_relax_pcala_ld;
+ break;
+ case R_LARCH_CALL36:
+ relax_func = loongarch_relax_call36;
+ break;
+ case R_LARCH_TLS_LE_HI20_R:
+ case R_LARCH_TLS_LE_LO12_R:
+ case R_LARCH_TLS_LE_ADD_R:
+ case R_LARCH_TLS_LE_HI20:
+ case R_LARCH_TLS_LE_LO12:
+ case R_LARCH_TLS_LE64_LO20:
+ case R_LARCH_TLS_LE64_HI12:
+ relax_func = loongarch_relax_tls_le;
+ break;
+ case R_LARCH_TLS_LD_PC_HI20:
+ case R_LARCH_TLS_GD_PC_HI20:
+ case R_LARCH_TLS_DESC_PC_HI20:
+ relax_func = loongarch_relax_tls_ld_gd_desc;
+ break;
+ default:
+ continue;
+ }
+
+ /* Only relax this reloc if it is paired with R_RISCV_RELAX. */
+ if (r_type == R_LARCH_TLS_LD_PC_HI20
+ || r_type == R_LARCH_TLS_GD_PC_HI20
+ || r_type == R_LARCH_TLS_DESC_PC_HI20
+ || r_type == R_LARCH_PCALA_HI20
+ || r_type == R_LARCH_GOT_PC_HI20)
+ {
+ if ((i + 2) == sec->reloc_count - 1
+ || ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX
+ || ELFNN_R_TYPE ((rel + 3)->r_info) != R_LARCH_RELAX
+ || rel->r_offset != (rel + 1)->r_offset
+ || (rel + 2)->r_offset != (rel + 3)->r_offset
+ || rel->r_offset + 4 != (rel + 2)->r_offset)
+ continue;
+ }
+ else
+ {
+ if (i == sec->reloc_count - 1
+ || ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX
+ || rel->r_offset != (rel + 1)->r_offset)
+ continue;
+ }
+ }
+ else if (info->relax_pass == 1 && r_type == R_LARCH_ALIGN)
+ relax_func = loongarch_relax_align;
+ else
+ continue;
+
/* Four kind of relocations:
Normal: symval is the symbol address.
R_LARCH_ALIGN: symval is the address of the last NOP instruction
@@ -5342,29 +5433,26 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
{
Elf_Internal_Sym *sym = (Elf_Internal_Sym *)symtab_hdr->contents
+ r_symndx;
+
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
continue;
/* Only TLS instruction sequences that are accompanied by
R_LARCH_RELAX and cannot perform type transition can be
relaxed. */
- if (R_LARCH_TLS_LD_PC_HI20 == r_type
- || R_LARCH_TLS_GD_PC_HI20 == r_type
- || (R_LARCH_TLS_DESC_PC_HI20 == r_type
- && (i + 1 != sec->reloc_count)
- && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
- && ! loongarch_can_trans_tls (abfd, info, h,
- r_symndx, r_type)))
+ if (r_type == R_LARCH_TLS_LD_PC_HI20
+ || r_type == R_LARCH_TLS_GD_PC_HI20
+ || r_type == R_LARCH_TLS_DESC_PC_HI20)
{
sym_sec = htab->elf.sgot;
symval = elf_local_got_offsets (abfd)[r_symndx];
char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
r_symndx);
- if (R_LARCH_TLS_DESC_PC_HI20 == r_type
+ if (r_type == R_LARCH_TLS_DESC_PC_HI20
&& GOT_TLS_GD_BOTH_P (tls_type))
symval += 2 * GOT_ENTRY_SIZE;
}
- else if (sym->st_shndx == SHN_UNDEF || R_LARCH_ALIGN == r_type)
+ else if (sym->st_shndx == SHN_UNDEF || r_type == R_LARCH_ALIGN)
{
sym_sec = sec;
symval = rel->r_offset;
@@ -5375,35 +5463,25 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
symval = sym->st_value;
}
symtype = ELF_ST_TYPE (sym->st_info);
+ is_abs_symbol = sym->st_shndx == SHN_ABS;
}
else
{
- r_symndx = ELFNN_R_SYM (rel->r_info) - symtab_hdr->sh_info;
- h = elf_sym_hashes (abfd)[r_symndx];
-
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
/* Disable the relaxation for ifunc. */
if (h != NULL && h->type == STT_GNU_IFUNC)
continue;
/* The GOT entry of tls symbols must in current execute file or
shared object. */
- if (R_LARCH_TLS_LD_PC_HI20 == r_type
- || R_LARCH_TLS_GD_PC_HI20 == r_type
- || (R_LARCH_TLS_DESC_PC_HI20 == r_type
- && (i + 1 != sec->reloc_count)
- && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
- && !loongarch_can_trans_tls (abfd, info, h,
- r_symndx, r_type)))
+ if (r_type == R_LARCH_TLS_LD_PC_HI20
+ || r_type == R_LARCH_TLS_GD_PC_HI20
+ || r_type == R_LARCH_TLS_DESC_PC_HI20)
{
sym_sec = htab->elf.sgot;
symval = h->got.offset;
char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
r_symndx);
- if (R_LARCH_TLS_DESC_PC_HI20 == r_type
+ if (r_type == R_LARCH_TLS_DESC_PC_HI20
&& GOT_TLS_GD_BOTH_P (tls_type))
symval += 2 * GOT_ENTRY_SIZE;
}
@@ -5412,12 +5490,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
&& h->root.u.def.section != NULL
&& h->root.u.def.section->output_section != NULL)
{
- symval = h->root.u.def.value;
sym_sec = h->root.u.def.section;
+ symval = h->root.u.def.value;
}
else
continue;
+ is_abs_symbol = bfd_is_abs_section (h->root.u.def.section);
if (h && LARCH_REF_LOCAL (info, h))
local_got = true;
symtype = h->type;
@@ -5440,7 +5519,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
+ (alingmeng - 4).
If r_symndx is 0, alignmeng-4 is r_addend.
If r_symndx > 0, alignment-4 is 2^(r_addend & 0xff)-4. */
- else if (R_LARCH_ALIGN == r_type)
+ else if (r_type == R_LARCH_ALIGN)
if (r_symndx > 0)
symval += ((1 << (rel->r_addend & 0xff)) - 4);
else
@@ -5450,96 +5529,14 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
symval += sec_addr (sym_sec);
- /* If the conditions for tls type transition are met, type
- transition is performed instead of relax.
- During the transition from DESC->IE/LE, there are 2 situations
- depending on the different configurations of the relax/norelax
- option.
- If the -relax option is used, the extra nops will be removed,
- and this transition is performed in pass 0.
- If the --no-relax option is used, nop will be retained, and
- this transition is performed in pass 1. */
- if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
- && (i + 1 != sec->reloc_count)
- && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
- && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
- {
- loongarch_tls_perform_trans (abfd, sec, rel, h, info);
- r_type = ELFNN_R_TYPE (rel->r_info);
- }
-
- switch (r_type)
- {
- case R_LARCH_ALIGN:
- if (1 == info->relax_pass)
- loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
- break;
+ if (r_type == R_LARCH_GOT_PC_HI20 && (!local_got || is_abs_symbol))
+ continue;
- case R_LARCH_DELETE:
- if (1 == info->relax_pass)
- {
- loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
- rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
- }
- break;
- case R_LARCH_CALL36:
- if (0 == info->relax_pass && (i + 2) <= sec->reloc_count)
- loongarch_relax_call36 (abfd, sec, sym_sec, rel, symval,
+ if (relax_func (abfd, sec, sym_sec, rel, symval,
+ info, again, max_alignment)
+ && relax_func == loongarch_relax_pcala_ld)
+ loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
info, again, max_alignment);
- break;
-
- case R_LARCH_TLS_LE_HI20_R:
- case R_LARCH_TLS_LE_LO12_R:
- case R_LARCH_TLS_LE_ADD_R:
- case R_LARCH_TLS_LE_HI20:
- case R_LARCH_TLS_LE_LO12:
- case R_LARCH_TLS_LE64_LO20:
- case R_LARCH_TLS_LE64_HI12:
- 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,
- info, again, max_alignment);
- break;
-
- case R_LARCH_GOT_PC_HI20:
- if (h)
- is_abs_symbol = bfd_is_abs_section(h->root.u.def.section);
- else
- {
- Elf_Internal_Sym *sym = (Elf_Internal_Sym *)symtab_hdr->contents
- + ELFNN_R_SYM (rel->r_info);
- is_abs_symbol = sym->st_shndx == SHN_ABS;
- }
- /* If symval is in the range [-2^31, 2^31), we can relax the
- pair of instructions from pcalau12i/ld.d to lu12i.w/ori for
- abosulte symbol. This is not implemented yet, so we just
- remain the r_type which will be needed when relocate for
- absolute symbol. */
- if (local_got && 0 == info->relax_pass
- && !is_abs_symbol
- && (i + 4) <= sec->reloc_count)
- {
- if (loongarch_relax_pcala_ld (abfd, sec, rel))
- loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
- info, again, max_alignment);
- }
- break;
-
- case R_LARCH_TLS_LD_PC_HI20:
- case R_LARCH_TLS_GD_PC_HI20:
- case R_LARCH_TLS_DESC_PC_HI20:
- if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
- loongarch_relax_tls_ld_gd_desc (abfd, sec, sym_sec, rel, symval,
- info, again, max_alignment);
- break;
-
- default:
- break;
- }
}
return true;
--
2.33.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/opencloudos-stream/binutils.git
[email protected]:opencloudos-stream/binutils.git
opencloudos-stream
binutils
binutils
master

搜索帮助