Bug 20545 - [avr] Incorrect offsets computed for PC relative jumps with linker relaxation and alignment directives
Summary: [avr] Incorrect offsets computed for PC relative jumps with linker relaxation...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.27
: P2 normal
Target Milestone: ---
Assignee: Senthil Kumar Selvaraj
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-09-01 05:40 UTC by Senthil Kumar Selvaraj
Modified: 2016-09-06 09:55 UTC (History)
1 user (show)

See Also:
Host:
Target: avr
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Senthil Kumar Selvaraj 2016-09-01 05:40:26 UTC
There are a couple of cases where linker relaxation causes incorrect computation of addends for relocs, resulting in wrong code or reloc overflow errors.

$ cat repro.s
        call foo
        nop 
        .p2align        1
        nop
.L618:
        ldi r24,lo8(6)
        brsh .L618
foo:    nop
$ avr-as -mavr5 repro.s -o test.o && avr-ld -mavr5 --relax test.o && avr-objdump -S a.out

a.out:     file format elf32-avr


Disassembly of section .text:

00000000 <__ctors_end>:
   0:	03 d0       	rcall	.+6      	; 0x8 <__ctors_end+0x8>
   2:	00 00       	nop
   4:	00 00       	nop
   6:	86 e0       	ldi	r24, 0x06	; 6
   8:	e8 f7       	brcc	.-6      	; 0x4 <__ctors_end+0x4>

0000000a <foo>:
	...

Note that the brsh in the source code jumps to the ldi instruction, whereas the disassembly of the linker output shows that it jumps to the instruction before it (nop).

$ cat repro2.s
foo:
	jmp foo
	call foo
.L1:
	brsh .L1
.p2align	1
	nop
$ ~/avr/install/bin/avr-as -mavr5 repro2.s -o test.o && ~/avr/install/bin/avr-ld -mavr5 --relax test.o && ~/avr/install/bin/avr-objdump -S a.out

a.out:     file format elf32-avr


Disassembly of section .text:

00000000 <__ctors_end>:
   0:	ff cf       	rjmp	.-2      	; 0x0 <__ctors_end>
   2:	fe df       	rcall	.-4      	; 0x0 <__ctors_end>
   4:	e8 f7       	brcc	.-6      	; 0x0 <__ctors_end>
	...

Again, the brsh in source code jumps to .L1 (i.e. itself), whereas in the disassembled output, it jumps to the first instruction (jmp relaxed to rjmp).
Comment 1 cvs-commit@gcc.gnu.org 2016-09-06 07:02:26 UTC
The master branch has been updated by Senthil Kumar Selvaraj <saaadhu@sourceware.org>:

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

commit bf1865065f64af2f32798c0327143baf99634e8d
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-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-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.
Comment 2 cvs-commit@gcc.gnu.org 2016-09-06 07:16:28 UTC
The binutils-2_27-branch branch has been updated by Senthil Kumar Selvaraj <saaadhu@sourceware.org>:

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.
Comment 3 Senthil Kumar Selvaraj 2016-09-06 09:55:53 UTC
Fixed in trunk and backported to 2.27 branch