From aed4f7b17889d6cc5f81cba7d5c30694a6b21e18 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 19 Nov 2025 09:27:42 +0800 Subject: [PATCH] LoongArch: fix relaxation overflowing (cherry picked from commit e4cba8c53d7d298b2266b82cb55175ac0da84ea0) --- LoongArch-fix-relaxation-overflowing.patch | 169 +++++++++++++++++++++ binutils.spec | 6 +- 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 LoongArch-fix-relaxation-overflowing.patch diff --git a/LoongArch-fix-relaxation-overflowing.patch b/LoongArch-fix-relaxation-overflowing.patch new file mode 100644 index 0000000..e8b7897 --- /dev/null +++ b/LoongArch-fix-relaxation-overflowing.patch @@ -0,0 +1,169 @@ +From b4de8e83725690ecbe50334360e12beb597f678c Mon Sep 17 00:00:00 2001 +From: Peng Fan +Date: Tue, 18 Nov 2025 14:14:41 +0800 +Subject: [PATCH] LoongArch: fix relaxation overflowing + +--- + bfd/elfnn-loongarch.c | 65 +++++++++++++++++++++++++++++++++---------- + 1 file changed, 51 insertions(+), 14 deletions(-) + +diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c +index 2d9c6444..e5a9fd03 100644 +--- a/bfd/elfnn-loongarch.c ++++ b/bfd/elfnn-loongarch.c +@@ -231,6 +231,10 @@ loongarch_elf_new_section_hook (bfd *abfd, asection *sec) + || (R_TYPE) == R_LARCH_TLS_LE64_LO20 \ + || (R_TYPE) == R_LARCH_TLS_LE64_HI12) + ++#define IS_CALL_RELOC(R_TYPE) \ ++ ((R_TYPE) == R_LARCH_B26 \ ++ ||(R_TYPE) == R_LARCH_CALL36) ++ + /* If TLS GD/IE need dynamic relocations, INDX will be the dynamic indx, + and set NEED_RELOC to true used in allocate_dynrelocs and + loongarch_elf_relocate_section for TLS GD/IE. */ +@@ -1090,12 +1094,16 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, + + /* Since shared library global symbols interpose, any + PC-relative relocations against external symbols +- should not be used to build shared libraries. */ ++ should not be used to build shared libraries. ++ In static PIE undefined weak symbols may be allowed ++ by rewriting pcaddi to addi.w if addend is in [-2048, 2048). */ + case R_LARCH_PCREL20_S2: + if (bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_READONLY) != 0 +- && ! LARCH_REF_LOCAL (info, h)) ++ && ! LARCH_REF_LOCAL (info, h) ++ && (!info->nointerp ++ || h->root.type != bfd_link_hash_undefweak)) + return bad_static_reloc (abfd, rel, sec, r_type, h, NULL); + + break; +@@ -1118,12 +1126,16 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, + } + + /* PC-relative relocations are allowed For first version +- medium cmodel function call. */ ++ medium cmodel function call. Those against undefined ++ weak symbol are allowed for static PIE by rewritting ++ pcalau12i to lu12i.w. */ + if (h != NULL && !h->needs_plt + && bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_READONLY) != 0 +- && ! LARCH_REF_LOCAL (info, h)) ++ && ! LARCH_REF_LOCAL (info, h) ++ && (!info->nointerp ++ || h->root.type != bfd_link_hash_undefweak)) + return bad_static_reloc (abfd, rel, sec, r_type, h, NULL); + + break; +@@ -4008,9 +4020,43 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + case R_LARCH_B26: + case R_LARCH_CALL36: + unresolved_reloc = false; ++ bool via_plt = ++ plt != NULL && h != NULL && h->plt.offset != (bfd_vma) - 1; + if (is_undefweak) + { + relocation = 0; ++ ++ /* A call to an undefined weak symbol is converted to 0. */ ++ if (!via_plt && IS_CALL_RELOC (r_type)) ++ { ++ /* call36 fn1 => pcaddu18i $ra,0+jirl $ra,$zero,0 ++ tail36 $t0,fn1 => pcaddi18i $t0,0+jirl $zero,$zero,0 */ ++ if (R_LARCH_CALL36 == r_type) ++ { ++ uint32_t jirl = bfd_get (32, input_bfd, ++ contents + rel->r_offset + 4); ++ uint32_t rd = LARCH_GET_RD (jirl); ++ jirl = LARCH_OP_JIRL | rd; ++ ++ bfd_put (32, input_bfd, jirl, ++ contents + rel->r_offset + 4); ++ } ++ else ++ { ++ uint32_t b_bl = bfd_get (32, input_bfd, ++ contents + rel->r_offset); ++ /* b %plt(fn1) => jirl $zero,zero,0. */ ++ if (LARCH_INSN_B (b_bl)) ++ bfd_put (32, input_bfd, LARCH_OP_JIRL, ++ contents + rel->r_offset); ++ else ++ /* bl %plt(fn1) => jirl $ra,zero,0. */ ++ bfd_put (32, input_bfd, LARCH_OP_JIRL | 0x1, ++ contents + rel->r_offset); ++ } ++ r = bfd_reloc_continue; ++ break; ++ } + } + + if (resolved_local) +@@ -4073,7 +4119,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + + /* If sym is undef weak and it's hidden or we are doing a static + link, (sym + addend) should be resolved to runtime address +- (0 + addend). */ ++ (0 + addend). */ + resolve_pcrel_undef_weak = + ((info->nointerp + || (h && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)) +@@ -5281,8 +5327,6 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec, + /* If pc and symbol not in the same segment, add/sub segment alignment if the + section has not undergone alignment processing because distances may grow + after alignment. */ +- if (!loongarch_sec_closed_for_deletion (sec)) +- { + if (!loongarch_two_sections_in_same_segment (info->output_bfd, + sec->output_section, + sym_sec->output_section)) +@@ -5293,7 +5337,6 @@ loongarch_relax_pcala_addi (bfd *abfd, asection *sec, asection *sym_sec, + pc -= (max_alignment > 4 ? max_alignment : 0); + else if (symval < pc) + pc += (max_alignment > 4 ? max_alignment : 0); +- } + + const uint32_t pcaddi = LARCH_OP_PCADDI; + +@@ -5351,8 +5394,6 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, + /* If pc and symbol not in the same segment, add/sub segment alignment if the + section has not undergone alignment processing because distances may grow + after alignment. */ +- if (!loongarch_sec_closed_for_deletion (sec)) +- { + if (!loongarch_two_sections_in_same_segment (info->output_bfd, + sec->output_section, + sym_sec->output_section)) +@@ -5363,7 +5404,6 @@ loongarch_relax_call36 (bfd *abfd, asection *sec, asection *sym_sec, + pc -= (max_alignment > 4 ? max_alignment : 0); + else if (symval < pc) + pc += (max_alignment > 4 ? max_alignment : 0); +- } + + /* Is pcalau12i + addi.d insns? */ + if (!LARCH_INSN_JIRL (jirl) +@@ -5553,8 +5593,6 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec, + /* If pc and symbol not in the same segment, add/sub segment alignment if the + section has not undergone alignment processing because distances may grow + after alignment. */ +- if (!loongarch_sec_closed_for_deletion (sec)) +- { + if (!loongarch_two_sections_in_same_segment (info->output_bfd, + sec->output_section, + sym_sec->output_section)) +@@ -5565,7 +5603,6 @@ loongarch_relax_tls_ld_gd_desc (bfd *abfd, asection *sec, asection *sym_sec, + pc -= (max_alignment > 4 ? max_alignment : 0); + else if (symval < pc) + pc += (max_alignment > 4 ? max_alignment : 0); +- } + + const uint32_t pcaddi = LARCH_OP_PCADDI; + +-- +2.43.7 + diff --git a/binutils.spec b/binutils.spec index 0d08260..0662301 100644 --- a/binutils.spec +++ b/binutils.spec @@ -2,7 +2,7 @@ Summary: A GNU collection of binary utilities Name: binutils%{?_with_debug:-debug} Version: 2.41 -Release: 25 +Release: 26 License: GPL-3.0-or-later AND (GPL-3.0-or-later WITH Bison-exception-2.2) AND (LGPL-2.0-or-later WITH GCC-exception-2.0) AND BSD-3-Clause AND GFDL-1.3-or-later AND GPL-2.0-or-later AND LGPL-2.1-or-later AND LGPL-2.0-or-later URL: https://sourceware.org/binutils @@ -314,6 +314,7 @@ Patch3144: 0010-LoongArch-Batch-delete-bytes-at-the-end-of-each-rela.patch Patch3145: 0011-LoongArch-Allow-to-relax-instructions-into-NOPs-afte.patch Patch3146: 0012-LoongArch-Fix-errors-due-to-version-differences.patch Patch3147: Support-x86-Zhaoxin-GMI-PadLock.patch +Patch3148: LoongArch-fix-relaxation-overflowing.patch # Part 5000 - @@ -1447,6 +1448,9 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Wed Nov 19 2025 Peng Fan - 2.41-26 +- LoongArch: fix relaxation overflowing + * Tue Sep 2 2025 timhu_806d - 2.41-25 - Backport patch from trunk to 2.41 -- Gitee