PR27597, nios: assertion fail in nios2_elf32_install_imm16

Message ID Zc9Ux4E8KTGWpvTr@squeak.grove.modra.org
State New
Headers
Series PR27597, nios: assertion fail in nios2_elf32_install_imm16 |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm warning Patch is already merged
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 warning Patch is already merged

Commit Message

Alan Modra Feb. 16, 2024, 12:27 p.m. UTC
  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.
  

Patch

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);
 	    }
 	}
     }