From: mengqinggang Date: Mon, 22 Sep 2025 03:43:41 +0000 (+0800) Subject: LoongArch: Add linker relaxation for got_pcadd_hi20 and got_pcadd_lo12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d17b290265a67e32285c2b6ee838f4a1ad8f1e11;p=thirdparty%2Fbinutils-gdb.git LoongArch: Add linker relaxation for got_pcadd_hi20 and got_pcadd_lo12 .L1: pcaddu12i $t0, %got_pcadd_hi20(a) -> pcaddu12i $t0, %pcadd_hi20(a) ld.w/d $t0, $t0, %got_pcadd_lo12(.L1) -> addi.w/d $t0, $t0, %pcadd_lo12(.L1) --- diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index 7a2f4274c5d..f7dcb8453b2 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -4502,7 +4502,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, || (h && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)) && is_undefweak); if (resolve_pcrel_undef_weak) - pc = 0; + relocation = pc; /* Use pc to avoid duplicate pcrel_hi record. */ if (h && h->plt.offset != MINUS_ONE) relocation = sec_addr (plt) + h->plt.offset; @@ -5831,7 +5831,11 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, return true; } -/* Relax pcalau12i,ld.d => pcalau12i,addi.d. */ +/* pcalau12i $t0, %got_pcala_hi20(a) -> pcalau12i $t0, %pcala_hi20(a) + ld.w/d $t0, $t0, %got_pcala_lo12(a) -> addi.w/d $t0, $t0, %pcala_lo12(a) + + pcaddu12i $t0, %got_pcadd_hi20(a) -> pcaddu12i $t0, %pcadd_hi20(a) + ld.w/d $t0, $t0, %got_pcadd_lo12(a) -> addi.w/d $t0, $t0, %pcadd_lo12(a) */ static bool loongarch_relax_pcala_ld (bfd *abfd, asection *sec, asection *sym_sec, @@ -5841,13 +5845,6 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec, bool *again ATTRIBUTE_UNUSED, bfd_vma max_alignment) { - bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; - Elf_Internal_Rela *rel_lo = rel_hi + 2; - uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset); - uint32_t ld = bfd_get (32, abfd, contents + rel_lo->r_offset); - uint32_t rd = LARCH_GET_RD (pca); - uint32_t addi_d = LARCH_OP_ADDI_D; - /* This section's output_offset need to subtract the bytes of instructions relaxed by the previous sections, so it needs to be updated beforehand. size_input_section already took care of updating it after relaxation, @@ -5871,22 +5868,46 @@ loongarch_relax_pcala_ld (bfd *abfd, asection *sec, else if (symval < pc) pc += (max_alignment > 4 ? max_alignment : 0); - if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12) + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; + Elf_Internal_Rela *rel_lo = rel_hi + 2; + uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset); + uint32_t ld = bfd_get (32, abfd, contents + rel_lo->r_offset); + uint32_t rd = LARCH_GET_RD (pca); + + if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PC_LO12 + && ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_GOT_PCADD_LO12) || (LARCH_GET_RD (ld) != rd) || (LARCH_GET_RJ (ld) != rd) - || !LARCH_INSN_LD_D (ld) + || (!LARCH_INSN_LD_D (ld) && !LARCH_INSN_LD_W (ld)) /* Within +-2G addressing range. */ || (bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0x80000000 || (bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x7fffffff) return false; - addi_d = addi_d | (rd << 5) | rd; - bfd_put (32, abfd, addi_d, contents + rel_lo->r_offset); + uint32_t addi; + if (LARCH_INSN_LD_D (ld)) + addi = LARCH_OP_ADDI_D; + else + addi = LARCH_OP_ADDI_W; + + addi = addi | (rd << 5) | rd; + bfd_put (32, abfd, addi, contents + rel_lo->r_offset); + + if (ELFNN_R_TYPE (rel_hi->r_info) == R_LARCH_GOT_PC_HI20) + { + rel_hi->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), + R_LARCH_PCALA_HI20); + rel_lo->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_lo->r_info), + R_LARCH_PCALA_LO12); + } + else + { + rel_hi->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), + R_LARCH_PCADD_HI20); + rel_lo->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_lo->r_info), + R_LARCH_PCADD_LO12); + } - rel_hi->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info), - R_LARCH_PCALA_HI20); - rel_lo->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_lo->r_info), - R_LARCH_PCALA_LO12); return true; } @@ -6232,6 +6253,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, relax_func = loongarch_relax_pcala_addi; break; case R_LARCH_GOT_PC_HI20: + case R_LARCH_GOT_PCADD_HI20: relax_func = loongarch_relax_pcala_ld; break; case R_LARCH_CALL36: @@ -6261,7 +6283,8 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, || 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) + || r_type == R_LARCH_GOT_PC_HI20 + || r_type == R_LARCH_GOT_PCADD_HI20) { if ((i + 2) == sec->reloc_count - 1 || ELFNN_R_TYPE ((rel + 1)->r_info) != R_LARCH_RELAX @@ -6405,7 +6428,9 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec, symval += sec_addr (sym_sec); - if (r_type == R_LARCH_GOT_PC_HI20 && !local_got) + if ((r_type == R_LARCH_GOT_PC_HI20 + || r_type == R_LARCH_GOT_PCADD_HI20) + && !local_got) continue; if (relax_func (abfd, sec, sym_sec, rel, symval, diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c index cf174e44ede..e049427956c 100644 --- a/gas/config/tc-loongarch.c +++ b/gas/config/tc-loongarch.c @@ -907,6 +907,8 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2, || BFD_RELOC_LARCH_TLS_DESC_CALL == reloc_type || BFD_RELOC_LARCH_TLS_IE_PC_HI20 == reloc_type || BFD_RELOC_LARCH_TLS_IE_PC_LO12 == reloc_type + || BFD_RELOC_LARCH_GOT_PCADD_HI20 == reloc_type + || BFD_RELOC_LARCH_GOT_PCADD_LO12 == reloc_type || BFD_RELOC_LARCH_TLS_DESC_PCADD_HI20 == reloc_type || BFD_RELOC_LARCH_TLS_DESC_PCADD_LO12 == reloc_type || BFD_RELOC_LARCH_TLS_IE_PCADD_HI20 == reloc_type @@ -1293,7 +1295,10 @@ append_fixp_and_insn (struct loongarch_cl_insn *ip) || BFD_RELOC_LARCH_TLS_LE_HI20 == reloc_info[0].type || BFD_RELOC_LARCH_TLS_LE_LO12 == reloc_info[0].type || BFD_RELOC_LARCH_TLS_LE64_LO20 == reloc_info[0].type - || BFD_RELOC_LARCH_TLS_LE64_HI12 == reloc_info[0].type)) + || BFD_RELOC_LARCH_TLS_LE64_HI12 == reloc_info[0].type + || BFD_RELOC_LARCH_GOT_PCADD_HI20 == reloc_info[0].type + || BFD_RELOC_LARCH_TLS_IE_PCADD_HI20 == reloc_info[0].type + || BFD_RELOC_LARCH_TLS_DESC_PCADD_HI20 == reloc_info[0].type)) { frag_wane (frag_now); frag_new (0); diff --git a/include/opcode/loongarch.h b/include/opcode/loongarch.h index b76e295b6d4..fb6f8be68de 100644 --- a/include/opcode/loongarch.h +++ b/include/opcode/loongarch.h @@ -36,6 +36,7 @@ extern "C" #define LARCH_MK_ADDI_D 0xffc00000 #define LARCH_OP_ADDI_D 0x02c00000 + #define LARCH_MK_ADDI_W LARCH_MK_ADDI_D #define LARCH_OP_ADDI_W 0x02800000 #define LARCH_MK_PCADDI 0xfe000000 #define LARCH_OP_PCADDI 0x18000000 @@ -50,6 +51,7 @@ extern "C" #define LARCH_OP_LU12I_W 0x14000000 #define LARCH_MK_LD_D 0xffc00000 #define LARCH_OP_LD_D 0x28c00000 + #define LARCH_MK_LD_W LARCH_MK_LD_D #define LARCH_OP_LD_W 0x28800000 #define LARCH_MK_JIRL 0xfc000000 #define LARCH_OP_JIRL 0x4c000000 @@ -85,6 +87,7 @@ extern "C" #define LARCH_INSN_ORI(insn) LARCH_INSN_OPS((insn), ORI) #define LARCH_INSN_LU12I_W(insn) LARCH_INSN_OPS((insn), LU12I_W) #define LARCH_INSN_LD_D(insn) LARCH_INSN_OPS((insn), LD_D) + #define LARCH_INSN_LD_W(insn) LARCH_INSN_OPS((insn), LD_W) #define LARCH_INSN_JIRL(insn) LARCH_INSN_OPS((insn), JIRL) #define LARCH_INSN_BCEQZ(insn) LARCH_INSN_OPS((insn), BCEQZ) #define LARCH_INSN_BCNEZ(insn) LARCH_INSN_OPS((insn), BCNEZ)