This is the mail archive of the mailing list for the binutils project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, avr] Fix PR 20221 - adjust syms and relocs only if relax shrunk section


  This patch fixes an edge case in linker relaxation that causes symbol
  values to be computed incorrectly in the presence of align directives
  in input source code.

  As the below testcase demonstrates, for code like

        CALL    dest
        .align  1

  where the bytes to be deleted (CALL to RCALL, 2 bytes) are adjacent to an
  alignment boundary, no deletion happens - the prop record handling
  merely overwrites the to-be-deleted-bytes with NOPs. AFAICT, this is
  ok - eventually, relaxation sees that the padding is unnecessary and
  strips the NOPs away.

  However, the rest of elf32_avr_relax_delete_bytes runs with the assumption
  that the bytes have been deleted, and this causes symbol values and/or
  reloc offsets to be decremented even if nothing has moved. dest, in the
  above testcase, gets decremented by 2 even when the gap got alignment
  padded, and then again when the padding was removed - it ends up
  getting adjusted down twice.

  The patch fixes this by recording whether shrinking actually occurred,
  and then skipping the reloc offset/sym value adjutment if it did
  not. There's also a testcase that fails with master (and 2.26) that
  passes with this patch.

  Ok for master? Can I backport to 2.26 branch if ok?



2016-06-08  Senthil Kumar Selvaraj  <>

	PR ld/20221
	* elf32-avr.c (elf32_avr_relax_delete_bytes): Adjust syms
  and relocs only if shrinking occurred.


2016-06-08  Senthil Kumar Selvaraj  <>

	PR ld/20221
	* testsuite/ld-avr/avr-prop-5.d: New.
	* testsuite/ld-avr/avr-prop-5.s: New.

diff --git bfd/elf32-avr.c bfd/elf32-avr.c
index d463d78..b95e251 100644
--- bfd/elf32-avr.c
+++ bfd/elf32-avr.c
@@ -1828,6 +1828,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   unsigned int symcount;
   struct avr_relax_info *relax_info;
   struct avr_property_record *prop_record = NULL;
+  bfd_boolean did_shrink = FALSE;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
@@ -1863,10 +1864,16 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   /* Actually delete the bytes.  */
   if (toaddr - addr - count > 0)
-    memmove (contents + addr, contents + addr + count,
-             (size_t) (toaddr - addr - count));
+    {
+      memmove (contents + addr, contents + addr + count,
+               (size_t) (toaddr - addr - count));
+      did_shrink = TRUE;
+    }
   if (prop_record == NULL)
-    sec->size -= count;
+    {
+      sec->size -= count;
+      did_shrink = TRUE;
+    }
       /* Use the property record to fill in the bytes we've opened up.  */
@@ -1885,6 +1892,11 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
           prop_record->data.align.preceding_deleted += count;
+      /* If toaddr == (addr + count), then we didn't delete anything, yet
+         we fill count bytes backwards from toaddr. This is still ok - we
+         end up overwriting the bytes we would have deleted. We just need
+         to remember we didn't delete anything i.e. don't set did_shrink,
+         so that we don't corrupt reloc offsets or symbol values.*/
       memset (contents + toaddr - count, fill, count);
       /* Adjust the TOADDR to avoid moving symbols located at the address
@@ -1892,6 +1904,9 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
       toaddr -= count;
+  if (!did_shrink)
+    return TRUE;
   /* Adjust all the reloc addresses.  */
   for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
diff --git ld/testsuite/ld-avr/avr-prop-5.d ld/testsuite/ld-avr/avr-prop-5.d
new file mode 100644
index 0000000..5f62ba3
--- /dev/null
+++ ld/testsuite/ld-avr/avr-prop-5.d
@@ -0,0 +1,10 @@
+#name: AVR .avr.prop, single .align proper sym val test.
+#as: -mmcu=avrxmega2 -mlink-relax
+#ld: -mavrxmega2 --relax
+#source: avr-prop-5.s
+#objdump: -S
+#target: avr-*-*
+   0:	00 d0\s+rcall\s+\.\+0\s+; 0x2 <dest>
\ No newline at end of file
diff --git ld/testsuite/ld-avr/avr-prop-5.s ld/testsuite/ld-avr/avr-prop-5.s
new file mode 100644
index 0000000..6a3359a
--- /dev/null
+++ ld/testsuite/ld-avr/avr-prop-5.s
@@ -0,0 +1,7 @@
+        .text
+        .global _start, dest
+        CALL    dest
+        .align  1
+        NOP

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]