This is the mail archive of the binutils-cvs@sourceware.org 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]

[binutils-gdb/binutils-2_27-branch] Fix PR ld/20545 - relaxation bugs in avr backend


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3cb2b3db2e1163ee324894364538e7247c37350b

commit 3cb2b3db2e1163ee324894364538e7247c37350b
Author: Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
Date:   Tue Sep 6 12:28:37 2016 +0530

    Fix PR ld/20545 - relaxation bugs in avr backend
    
    Prior to the patch, addends for relocs were being adjusted even if
    they went beyond an alignment boundary. This is wrong - to
    preserve alignment constraints, the relaxation logic adds as many padding
    bytes at the alignment boundary as was deleted, so addends beyond the
    boundary should not be adjusted. avr-prop-7.s reproduces this
    scenario.
    
    Also, prior to this patch, the relaxation logic assumed that the addr
    parameter pointed to the middle of the instruction to be deleted, and
    that addr - count would therefore be the shrinked instruction's
    address. This is true when actually shrinking instructions.
    
    The alignment constraints handling logic also invokes the same logic
    though, with addr as the starting offset of padding bytes and
    with count as the number of bytes to be deleted. Calculating the
    shrinked insn's address as addr - count is obviously wrong in this
    case - that offset would point to count bytes before the last
    non-padded byte. avr-prop-8.s reproduces this scenario.
    
    To fix scenario 1, the patch adds an additional check to ensure reloc addends
    aren't adjusted if they cross a shrink boundary. The shrink boundary
    is either the section size or an alignment boundary. Addends pointing
    at an alignment boundary don't need to be adjusted, as padding would
    occur and keep the boundary the same. Addends pointing at section size
    need to be adjusted though, as no padding occurs and the section size
    itself would get decremented. The patch records whether padding
    occured (did_pad) and uses that to detect and handle this condition.
    
    To fix scenario 2, the patch adds an additional parameter
    (delete_shrinks_insn) to elf32_avr_relax_delete_bytes to distinguish
    instruction bytes deletion from padding bytes deletion. It then uses that to
    correctly set shrinked_insn_address.
    
    bfd/ChangeLog:
    
    2016-09-06  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
    
    	Backport from mainline
    	2016-09-02  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
    
    	PR ld/20545
    	* elf32-avr.c (elf32_avr_relax_delete_bytes): Add parameter
    	delete_shrinks_insn. Modify computation of shrinked_insn_address.
    	Compute shrink_boundary and adjust addend only if
    	addend_within_shrink_boundary.
    	(elf32_avr_relax_section): Modify calls to
    	elf32_avr_relax_delete_bytes to pass extra parameter.
    
    ld/ChangeLog:
    
    2016-09-06  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
    
    	Backport from mainline
    	2016-09-02  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
    
    	PR ld/20545
    	* testsuite/ld-avr/avr-prop-7.d: New test.
    	* testsuite/ld-avr/avr-prop-7.s: New test.
    	* testsuite/ld-avr/avr-prop-8.d: New test.
    	* testsuite/ld-avr/avr-prop-8.s: New test.

Diff:
---
 bfd/ChangeLog                    | 13 +++++++++++++
 bfd/elf32-avr.c                  | 40 +++++++++++++++++++++++++++++++++-------
 ld/ChangeLog                     | 11 +++++++++++
 ld/testsuite/ld-avr/avr-prop-7.d | 15 +++++++++++++++
 ld/testsuite/ld-avr/avr-prop-7.s |  8 ++++++++
 ld/testsuite/ld-avr/avr-prop-8.d | 13 +++++++++++++
 ld/testsuite/ld-avr/avr-prop-8.s |  7 +++++++
 7 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4ac73af..d890764 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,16 @@
+2016-09-06  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+	Backport from mainline
+	2016-09-02  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+	PR ld/20545
+	* elf32-avr.c (elf32_avr_relax_delete_bytes): Add parameter
+	delete_shrinks_insn. Modify computation of shrinked_insn_address.
+	Compute shrink_boundary and adjust addend only if
+	addend_within_shrink_boundary.
+	(elf32_avr_relax_section): Modify calls to
+	elf32_avr_relax_delete_bytes to pass extra parameter.
+
 2016-09-01  Alan Modra  <amodra@gmail.com>
 
 	* elf64-ppc.c (synthetic_opd): New static var.
diff --git a/bfd/elf32-avr.c b/bfd/elf32-avr.c
index a0a5c69..eea76a4 100644
--- a/bfd/elf32-avr.c
+++ b/bfd/elf32-avr.c
@@ -1808,13 +1808,17 @@ elf32_avr_adjust_diff_reloc_value (bfd *abfd,
 /* Delete some bytes from a section while changing the size of an instruction.
    The parameter "addr" denotes the section-relative offset pointing just
    behind the shrinked instruction. "addr+count" point at the first
-   byte just behind the original unshrinked instruction.  */
+   byte just behind the original unshrinked instruction. If delete_shrinks_insn
+   is FALSE, we are deleting redundant padding bytes from relax_info prop
+   record handling. In that case, addr is section-relative offset of start
+   of padding, and count is the number of padding bytes to delete. */
 
 static bfd_boolean
 elf32_avr_relax_delete_bytes (bfd *abfd,
                               asection *sec,
                               bfd_vma addr,
-                              int count)
+                              int count,
+                              bfd_boolean delete_shrinks_insn)
 {
   Elf_Internal_Shdr *symtab_hdr;
   unsigned int sec_shndx;
@@ -1829,6 +1833,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
   struct avr_relax_info *relax_info;
   struct avr_property_record *prop_record = NULL;
   bfd_boolean did_shrink = FALSE;
+  bfd_boolean did_pad = FALSE;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
@@ -1909,6 +1914,7 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
          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);
+      did_pad = TRUE;
 
       /* Adjust the TOADDR to avoid moving symbols located at the address
          of the property record, which has not moved.  */
@@ -1965,7 +1971,9 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
 	 continue;
 
        shrinked_insn_address = (sec->output_section->vma
-                                + sec->output_offset + addr - count);
+                                + sec->output_offset + addr);
+       if (delete_shrinks_insn)
+         shrinked_insn_address -= count;
 
        irel = elf_section_data (isec)->relocs;
        /* PR 12161: Read in the relocs for this section if necessary.  */
@@ -2002,6 +2010,13 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                   a symbol or section associated with it.  */
                if (sym_sec == sec)
                  {
+                   /* If there is an alignment boundary, we only need to
+                      adjust addends that end up below the boundary. */
+                   bfd_vma shrink_boundary = (reloc_toaddr
+                                              + sec->output_section->vma
+                                              + sec->output_offset);
+                   bfd_boolean addend_within_shrink_boundary = FALSE;
+
                    symval += sym_sec->output_section->vma
                              + sym_sec->output_offset;
 
@@ -2015,8 +2030,17 @@ elf32_avr_relax_delete_bytes (bfd *abfd,
                              (unsigned int) (symval + irel->r_addend),
                              (unsigned int) shrinked_insn_address);
 
+                   /* If we padded bytes, then the boundary didn't change,
+                      so there's no need to adjust addends pointing at the boundary.
+                      If we didn't pad, then we actually shrank the boundary, so
+                      addends pointing at the boundary need to be adjusted too. */
+                    addend_within_shrink_boundary = did_pad
+                      ? ((symval + irel->r_addend) < shrink_boundary)
+                      : ((symval + irel->r_addend) <= shrink_boundary);
+
                    if (symval <= shrinked_insn_address
-                       && (symval + irel->r_addend) > shrinked_insn_address)
+                       && (symval + irel->r_addend) > shrinked_insn_address
+                       && addend_within_shrink_boundary)
                      {
                        if (elf32_avr_is_diff_reloc (irel))
                          {
@@ -2648,7 +2672,8 @@ elf32_avr_relax_section (bfd *abfd,
                   {
                     /* Delete two bytes of data.  */
                     if (!elf32_avr_relax_delete_bytes (abfd, sec,
-                                                       irel->r_offset + 2, 2))
+                                                       irel->r_offset + 2, 2,
+                                                       TRUE))
                       goto error_return;
 
                     /* That will change things, so, we should relax again.
@@ -2972,7 +2997,8 @@ elf32_avr_relax_section (bfd *abfd,
 
 			    /* Delete two bytes of data.  */
 			    if (!elf32_avr_relax_delete_bytes (abfd, sec,
-							       irel->r_offset + insn_size, 2))
+							       irel->r_offset + insn_size, 2,
+							       TRUE))
 			      goto error_return;
 
 			    /* That will change things, so, we should relax
@@ -3040,7 +3066,7 @@ elf32_avr_relax_section (bfd *abfd,
                         record->offset -= count;
                         elf32_avr_relax_delete_bytes (abfd, sec,
                                                       addr - count,
-                                                      count);
+                                                      count, FALSE);
                         *again = TRUE;
                       }
                   }
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 82c6344..a251a21 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,14 @@
+2016-09-06  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+	Backport from mainline
+	2016-09-02  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
+
+	PR ld/20545
+	* testsuite/ld-avr/avr-prop-7.d: New test.
+	* testsuite/ld-avr/avr-prop-7.s: New test.
+	* testsuite/ld-avr/avr-prop-8.d: New test.
+	* testsuite/ld-avr/avr-prop-8.s: New test.
+
 2016-08-09  Roland McGrath  <roland@hack.frob.com>
 
 	* emulparams/armelf.sh (GENERATE_PIE_SCRIPT): Set to yes.
diff --git a/ld/testsuite/ld-avr/avr-prop-7.d b/ld/testsuite/ld-avr/avr-prop-7.d
new file mode 100644
index 0000000..9f2cea9
--- /dev/null
+++ b/ld/testsuite/ld-avr/avr-prop-7.d
@@ -0,0 +1,15 @@
+#name: AVR .avr.prop, AVR_7_PCREL after align
+#as: -mavrxmega2 -mlink-relax
+#ld: -mavrxmega2 --relax
+#source: avr-prop-7.s
+#objdump: -S
+#target: avr-*-*
+
+#...
+00000000 <__ctors_end>:
+   0:	04 d0       	rcall	.+8      	; 0xa <foo>
+   2:	00 00       	nop
+   4:	00 00       	nop
+   6:	86 e0       	ldi	r24, 0x06	; 6
+   8:	f0 f7       	brcc	.-4      	; 0x6 <__ctors_end\+0x6>
+#...
diff --git a/ld/testsuite/ld-avr/avr-prop-7.s b/ld/testsuite/ld-avr/avr-prop-7.s
new file mode 100644
index 0000000..38276ba
--- /dev/null
+++ b/ld/testsuite/ld-avr/avr-prop-7.s
@@ -0,0 +1,8 @@
+	call foo
+	nop
+	.p2align	1
+        nop
+.L618:
+	ldi r24,lo8(6)
+	brsh .L618
+foo:    nop
diff --git a/ld/testsuite/ld-avr/avr-prop-8.d b/ld/testsuite/ld-avr/avr-prop-8.d
new file mode 100644
index 0000000..2905f98
--- /dev/null
+++ b/ld/testsuite/ld-avr/avr-prop-8.d
@@ -0,0 +1,13 @@
+#name: AVR .avr.prop, AVR_7_PCREL just before align
+#as: -mavrxmega2 -mlink-relax
+#ld: -mavrxmega2 --relax
+#source: avr-prop-8.s
+#objdump: -S
+#target: avr-*-*
+
+#...
+00000000 <__ctors_end>:
+   0:	ff cf       	rjmp	.-2      	; 0x0 <__ctors_end>
+   2:	fe df       	rcall	.-4      	; 0x0 <__ctors_end>
+   4:	f8 f7       	brcc	.-2      	; 0x4 <__ctors_end\+0x4>
+#...
diff --git a/ld/testsuite/ld-avr/avr-prop-8.s b/ld/testsuite/ld-avr/avr-prop-8.s
new file mode 100644
index 0000000..34554f2
--- /dev/null
+++ b/ld/testsuite/ld-avr/avr-prop-8.s
@@ -0,0 +1,7 @@
+foo:
+	jmp foo
+	call foo
+.L1:
+	brsh .L1
+.p2align	1
+	nop


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