RISC-V: Fix symbol size bug when relaxation deletes bytes.

Message ID 20180301221922.19084-1-jimw@sifive.com
State New
Headers show
Series
  • RISC-V: Fix symbol size bug when relaxation deletes bytes.
Related show

Commit Message

Jim Wilson March 1, 2018, 10:19 p.m.
I noticed some symbols have (unsigned) negative sizes, and tracked it down to
a problem where we would sometimes decrease the start address, and then get
confused by the change to the start address into thinking that the size needed
to change also.  This patch fixes the problem.

There is a testcase in PR 22756, but I haven't had a chance to make a ld
testcase yet.  The testcase works correctly with the patch.

This was tested with riscv{32,64}-{elf,linux} binutils/gas/ld testsuites,
and with riscv64-linux gcc make check.  There were no regressions.

Committed.

Jim

	bfd/
	PR 22756
	* elfnn-riscv.c (riscv_relax_delete_bytes): When adjust st_size, use
	else if instead of if.
---
 bfd/elfnn-riscv.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

-- 
2.14.1

Patch

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 6b2d80c379..582c8d1748 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -2665,10 +2665,16 @@  riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
 
 	  /* If the symbol *spans* the bytes we just deleted (i.e. its
 	     *end* is in the moved bytes but its *start* isn't), then we
-	     must adjust its size.  */
-	  if (sym->st_value <= addr
-	      && sym->st_value + sym->st_size > addr
-	      && sym->st_value + sym->st_size <= toaddr)
+	     must adjust its size.
+
+	     This test needs to use the original value of st_value, otherwise
+	     we might accidentally decrease size when deleting bytes right
+	     before the symbol.  But since deleted relocs can't span across
+	     symbols, we can't have both a st_value and a st_size decrease,
+	     so it is simpler to just use an else.  */
+	  else if (sym->st_value <= addr
+		   && sym->st_value + sym->st_size > addr
+		   && sym->st_value + sym->st_size <= toaddr)
 	    sym->st_size -= count;
 	}
     }
@@ -2716,9 +2722,9 @@  riscv_relax_delete_bytes (bfd *abfd, asection *sec, bfd_vma addr, size_t count,
 	    sym_hash->root.u.def.value -= count;
 
 	  /* As above, adjust the size if needed.  */
-	  if (sym_hash->root.u.def.value <= addr
-	      && sym_hash->root.u.def.value + sym_hash->size > addr
-	      && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
+	  else if (sym_hash->root.u.def.value <= addr
+		   && sym_hash->root.u.def.value + sym_hash->size > addr
+		   && sym_hash->root.u.def.value + sym_hash->size <= toaddr)
 	    sym_hash->size -= count;
 	}
     }