Fix PR 20221 - adjust syms and relocs only if relax shrunk section.
authorDenis Chertykov <chertykov@gmail.com>
Thu, 9 Jun 2016 16:17:43 +0000 (19:17 +0300)
committerDenis Chertykov <chertykov@gmail.com>
Thu, 9 Jun 2016 16:17:43 +0000 (19:17 +0300)
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.

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

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

bfd/ChangeLog
bfd/elf32-avr.c
ld/ChangeLog
ld/testsuite/ld-avr/avr-prop-5.d [new file with mode: 0644]
ld/testsuite/ld-avr/avr-prop-5.s [new file with mode: 0644]

index d544d0296d017fd6a78470776d852f8689eee696..460e68b8f0ea2914cca35d6a0776671344cd35e7 100644 (file)
@@ -1,3 +1,9 @@
+2016-06-08  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       PR ld/20221
+       * elf32-avr.c (elf32_avr_relax_delete_bytes): Adjust syms
+       and relocs only if shrinking occurred.
+
 2016-06-08  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf64-i386.c (elf_i386_link_hash_entry): Add tls_get_addr.
index d463d78c86109f6c4f92da0dfa9b2d72e4881ca7..b95e251e1e05f06cb5d23eabfa95cdf4cfb5ab4b 100644 (file)
@@ -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;
+    }
   else
     {
       /* 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;
           break;
         };
+      /* 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++)
     {
index cbb98e3dee487e2f1fe2ca1d982d8e60daa695da..11470c56d1631caffab1e9584098221adb5fdbb8 100644 (file)
@@ -1,4 +1,11 @@
+2016-06-08  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+       PR ld/20221
+       * testsuite/ld-avr/avr-prop-5.d: New.
+       * testsuite/ld-avr/avr-prop-5.s: New.
+
 2016-06-09  Pitchumani Sivanupandi  <pitchumani.s@atmel.com>
+
        * testsuite/ld-avr/lds-mega.d: New test.
        * testsuite/ld-avr/lds-mega.s: New test source.
        * testsuite/ld-avr/lds-tiny.d: New test.
diff --git a/ld/testsuite/ld-avr/avr-prop-5.d b/ld/testsuite/ld-avr/avr-prop-5.d
new file mode 100644 (file)
index 0000000..5f62ba3
--- /dev/null
@@ -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 a/ld/testsuite/ld-avr/avr-prop-5.s b/ld/testsuite/ld-avr/avr-prop-5.s
new file mode 100644 (file)
index 0000000..6a3359a
--- /dev/null
@@ -0,0 +1,7 @@
+        .text
+        .global _start, dest
+_start:
+        CALL    dest
+        .align  1
+dest:
+        NOP