[PATCH v2 2/5] RISCV: Arrange DELETE pass after .align pass

Patrick O'Neill patrick@rivosinc.com
Mon May 2 13:50:45 GMT 2022


By moving the deletion pass after the align pass, the linker can touch
each byte once via piecewise deletion. Otherwise, it may need to move
the same bytes twice.

2022-04-29 Patrick O'Neill <patrick@rivosinc.com>

	* elfnn-riscv.c (_bfd_riscv_relax_align): Count to-be-deleted
	  bytes so the alignments are still accurate.
	* elfnn-riscv.c (_bfd_riscv_relax_section): Move DELETE pass
	  after ALIGN pass.

Signed-off-by: Patrick O'Neill <patrick@rivosinc.com>
---
This gives us an O(n^2) runtime when the align pass counts the number of 
deleted bytes preceding it, but this will be fixed in Patch 4/5.
---
 bfd/elfnn-riscv.c | 45 +++++++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 16 deletions(-)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 8f9f0d8a86a..17f9607744f 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -4435,7 +4435,7 @@ _bfd_riscv_relax_tls_le (bfd *abfd,
 static bool
 _bfd_riscv_relax_align (bfd *abfd, asection *sec,
 			asection *sym_sec,
-			struct bfd_link_info *link_info,
+			struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
 			Elf_Internal_Rela *rel,
 			bfd_vma symval,
 			bfd_vma max_alignment ATTRIBUTE_UNUSED,
@@ -4449,6 +4449,18 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
   while (alignment <= rel->r_addend)
     alignment *= 2;
 
+  Elf_Internal_Rela *relocs = elf_section_data (sec)->relocs;
+  for (unsigned int i = 0; i < sec->reloc_count; i++)
+    {
+      Elf_Internal_Rela *reloc = relocs + i;
+      /* Ignore annotations after this alignment directive.  */
+      if (reloc == rel)
+	break;
+      /* Account for to-be-deleted bytes  */
+      else if (ELFNN_R_TYPE (reloc->r_info) == R_RISCV_DELETE)
+	symval -= reloc->r_addend;
+    }
+
   symval -= rel->r_addend;
   bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
   bfd_vma nop_bytes = aligned_addr - symval;
@@ -4468,12 +4480,12 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
       return false;
     }
 
-  /* Delete the reloc.  */
-  rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
-
-  /* If the number of NOPs is already correct, there's nothing to do.  */
+  /* If the number of NOPs is already correct, delete the reloc.  */
   if (nop_bytes == rel->r_addend)
-    return true;
+    {
+      rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE);
+      return true;
+    }
 
   /* Write as many RISC-V NOPs as we need.  */
   for (pos = 0; pos < (nop_bytes & -4); pos += 4)
@@ -4483,10 +4495,11 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec,
   if (nop_bytes % 4 != 0)
     bfd_putl16 (RVC_NOP, contents + rel->r_offset + pos);
 
-  /* Delete the excess bytes.  */
-  return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
-				   rel->r_addend - nop_bytes, link_info,
-				   NULL);
+  /* Mark the excess bytes for deletion.  */
+  rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE);
+  rel->r_addend = rel->r_addend - nop_bytes;
+  rel->r_offset = rel->r_offset + nop_bytes;
+  return true;
 }
 
 /* Relax PC-relative references to GP-relative references.  */
@@ -4677,8 +4690,8 @@ bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info,
 /* Relax a section.
 
    Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs.
-   Pass 1: Deletes the bytes that PCREL relaxation in pass 0 made obsolete.
-   Pass 2: Which cannot be disabled, handles code alignment directives.  */
+   Pass 1: Which cannot be disabled, handles code alignment directives.
+   Pass 2: Handle DELETE directives.  */
 
 static bool
 _bfd_riscv_relax_section (bfd *abfd, asection *sec,
@@ -4697,7 +4710,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
   *again = false;
 
   if (bfd_link_relocatable (info)
-      || sec->sec_flg0
+      || (sec->sec_flg0 && info->relax_pass == 0)
       || (sec->flags & SEC_RELOC) == 0
       || sec->reloc_count == 0
       || (info->disable_target_specific_optimizations
@@ -4771,10 +4784,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
 	  /* Skip over the R_RISCV_RELAX.  */
 	  i++;
 	}
-      else if (info->relax_pass == 1 && type == R_RISCV_DELETE)
-	relax_func = _bfd_riscv_relax_delete;
-      else if (info->relax_pass == 2 && type == R_RISCV_ALIGN)
+      else if (info->relax_pass == 1 && type == R_RISCV_ALIGN)
 	relax_func = _bfd_riscv_relax_align;
+      else if (info->relax_pass == 2 && type == R_RISCV_DELETE)
+	relax_func = _bfd_riscv_relax_delete;
       else
 	continue;
 
-- 
2.25.1



More information about the Binutils mailing list