| From 900c0f0aa3d78cd9e67ccd26fbc86224cef4c5b1 Mon Sep 17 00:00:00 2001 |
| From: Alan Modra <amodra@gmail.com> |
| Date: Fri, 16 Feb 2024 22:33:29 +1030 |
| Subject: [PATCH] PR27597, nios: assertion fail in nios2_elf32_install_imm16 |
| |
| The assertion in nios2_elf32_install_imm16 triggers when the PLT is |
| twice the maximum allowable size for a branch from PLTn to reach |
| .PLTresolve, and on no other call to nios2_elf32_install_imm16. That |
| makes the assertion completely useless. We can handle a PIC PLT |
| exceeding 0x8000 in size by bouncing branches that won't reach through |
| previous branches. |
| |
| PR 27597 |
| * elf32-nios2.c (nios2_elf32_install_imm16): Delete BFD_ASSERT. |
| (nios2_build_one_stub): Don't bother masking value passed to |
| nios2_elf32_install_imm16. |
| (nios2_elf32_finish_dynamic_symbol): Likewise. Handle overflow |
| of PLTn branch to .PLTresolve by bouncing through prior branches. |
| |
| Upstream: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=900c0f0aa3d78cd9e67ccd26fbc86224cef4c5b1 |
| |
| Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com> |
| --- |
| bfd/elf32-nios2.c | 40 ++++++++++++++++++++++++---------------- |
| 1 file changed, 24 insertions(+), 16 deletions(-) |
| |
| diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c |
| index bebf4239958..7f61e2f8507 100644 |
| --- a/bfd/elf32-nios2.c |
| +++ b/bfd/elf32-nios2.c |
| @@ -1878,8 +1878,6 @@ nios2_elf32_install_imm16 (asection *sec, bfd_vma offset, bfd_vma value) |
| { |
| bfd_vma word = bfd_get_32 (sec->owner, sec->contents + offset); |
| |
| - BFD_ASSERT (value <= 0xffff || ((bfd_signed_vma) value) >= -0xffff); |
| - |
| bfd_put_32 (sec->owner, word | ((value & 0xffff) << 6), |
| sec->contents + offset); |
| } |
| @@ -2518,7 +2516,7 @@ nios2_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg ATTRIBUTE_U |
| nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset, |
| hiadj (sym_value)); |
| nios2_elf32_install_imm16 (stub_sec, hsh->stub_offset + 4, |
| - (sym_value & 0xffff)); |
| + sym_value); |
| stub_sec->size += 12; |
| break; |
| default: |
| @@ -4986,16 +4984,28 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd, |
| /* Emit the PLT entry. */ |
| if (bfd_link_pic (info)) |
| { |
| + bfd_vma br_offset; |
| + |
| nios2_elf32_install_data (splt, nios2_so_plt_entry, h->plt.offset, |
| 3); |
| plt_index = (h->plt.offset - 24) / 12; |
| got_offset = (plt_index + 3) * 4; |
| nios2_elf32_install_imm16 (splt, h->plt.offset, |
| - hiadj(plt_index * 4)); |
| + hiadj (plt_index * 4)); |
| nios2_elf32_install_imm16 (splt, h->plt.offset + 4, |
| - (plt_index * 4) & 0xffff); |
| - nios2_elf32_install_imm16 (splt, h->plt.offset + 8, |
| - 0xfff4 - h->plt.offset); |
| + plt_index * 4); |
| + br_offset = -(h->plt.offset + 12); |
| + /* If this plt entry is too far away from the start of .plt |
| + for the "br" to reach .PLTresolve, bounce through one or |
| + more of the previous "br" instructions. */ |
| + if (br_offset < (bfd_vma) -32768) |
| + { |
| + br_offset += 32768 / 12 * 12 - 4; |
| + while (br_offset < (bfd_vma) -32768) |
| + br_offset += 32768 / 12 * 12; |
| + } |
| + nios2_elf32_install_imm16 (splt, h->plt.offset + 8, br_offset); |
| + |
| got_address = (sgotplt->output_section->vma + sgotplt->output_offset |
| + got_offset); |
| |
| @@ -5014,9 +5024,8 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd, |
| nios2_elf32_install_data (splt, nios2_plt_entry, h->plt.offset, 3); |
| got_address = (sgotplt->output_section->vma + sgotplt->output_offset |
| + got_offset); |
| - nios2_elf32_install_imm16 (splt, h->plt.offset, hiadj(got_address)); |
| - nios2_elf32_install_imm16 (splt, h->plt.offset + 4, |
| - got_address & 0xffff); |
| + nios2_elf32_install_imm16 (splt, h->plt.offset, hiadj (got_address)); |
| + nios2_elf32_install_imm16 (splt, h->plt.offset + 4, got_address); |
| |
| /* Fill in the entry in the global offset table. */ |
| bfd_put_32 (output_bfd, |
| @@ -5217,8 +5226,8 @@ nios2_elf32_finish_dynamic_sections (bfd *output_bfd, |
| BFD_ASSERT ((got_pcrel & 0xf) == 0); |
| nios2_elf32_install_data (splt, nios2_so_plt0_entry, 0, 6); |
| nios2_elf32_install_imm16 (splt, 4, hiadj (got_pcrel)); |
| - nios2_elf32_install_imm16 (splt, 12, got_pcrel & 0xffff); |
| - nios2_elf32_install_imm16 (splt, 16, (got_pcrel + 4) & 0xffff); |
| + nios2_elf32_install_imm16 (splt, 12, got_pcrel); |
| + nios2_elf32_install_imm16 (splt, 16, got_pcrel + 4); |
| } |
| else |
| { |
| @@ -5240,14 +5249,13 @@ nios2_elf32_finish_dynamic_sections (bfd *output_bfd, |
| |
| nios2_elf32_install_data (splt, nios2_plt0_entry, res_size, 7); |
| nios2_elf32_install_imm16 (splt, res_size, hiadj (res_start)); |
| - nios2_elf32_install_imm16 (splt, res_size + 4, |
| - res_start & 0xffff); |
| + nios2_elf32_install_imm16 (splt, res_size + 4, res_start); |
| nios2_elf32_install_imm16 (splt, res_size + 12, |
| hiadj (got_address)); |
| nios2_elf32_install_imm16 (splt, res_size + 16, |
| - (got_address + 4) & 0xffff); |
| + got_address + 4); |
| nios2_elf32_install_imm16 (splt, res_size + 20, |
| - (got_address + 8) & 0xffff); |
| + got_address + 8); |
| } |
| } |
| } |
| -- |
| 2.34.1 |
| |