Bug 28686 - [avr] linker relaxations generate incorrect value
Summary: [avr] linker relaxations generate incorrect value
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.37
: P2 normal
Target Milestone: ---
Assignee: Nick Clifton
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2021-12-12 22:55 UTC by Joerg Wunsch
Modified: 2021-12-16 16:42 UTC (History)
1 user (show)

See Also:
Host: any
Target: avr
Build:
Last reconfirmed: 2021-12-16 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joerg Wunsch 2021-12-12 22:55:38 UTC
This appears to be similar to

https://www.sourceware.org/bugzilla/show_bug.cgi?id=20545

However, as that one is "resolved fixed", opening a new bug instead.

In a setup with an assembler file requesting alignment for a particular block of code, the ZH value for that block of code is miscalculated when linker relaxations are requested.

Without linker relaxations, the correct code is generated.

Testcode:

.rept 300
call test
.endr
clr ZL
ldi ZH,hi8(matrix)
1:rjmp 1b
test:
ret

.balign 256
matrix:
.byte 1,2,3,4,5

Compiler (i.e. combined assembler+linker) commandline:

avr-gcc main.S -o main.elf -mmcu=atmega328 -nostartfiles -mrelax

Without -mrelax, ZH is (correctly) loaded with 5, as matrix is located at 0x500. With -mrelax, as there are 300 CALL instructions turned into RCALLs, matrix is located at 0x300, yet the value loaded into ZH becomes 2 rather than 3.

Cross reference:

https://www.mikrocontroller.net/topic/528827

(German-language forum discussion the bug has been reported to originally.)
Comment 1 Nick Clifton 2021-12-16 16:19:04 UTC
Hi Joerg,

  The root cause for this problem is the assembler.  When it assembles
  the test file it created a relocation for the LDI instruction which 
  references the .text section:

    % objdump -dr main.o
    [...]
     4b2:	f0 e0       	ldi	r31, 0x00	; 0
			4b2: R_AVR_HI8_LDI	.text+0x500

  So when the relaxation happens the code adjusts the relocation
  eventually ending up with .text+0x2ab which then translates into
  a value of 2 (the top 8 bits of the addition) for LDI instruction.

  This error of course is that the relocation should not be against
  an offset from the .text section, but rather against the matrix
  symbol itself.  Since this symbol stays aligned, it does not move
  as far back as the .text+offset value.

  I am currently testing a local patch which stops the assembler
  from trying to optimize away symbol names in relocations if it
  knows that linker relaxation is going to occur.  With this patch
  applied the object file looks like:

   % objdump -dr main.o
   [...]
    4b2:	f0 e0       	ldi	r31, 0x00	; 0
			4b2: R_AVR_HI8_LDI	matrix

  And when finally linked the correct value - 3 - is used by the 
  LDI instruction.
Comment 2 Sourceware Commits 2021-12-16 16:41:52 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit f3be70df1b1681ad1b9b0490587011bde433d220
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Dec 16 16:40:57 2021 +0000

    Fix AVR assembler so that it creates relocs that will work with linker relaxation.
    
            PR 28686
    gas     * config/tc-avr.h (tc_fix_adjustable): Define.
            * config/tc-avr.c (avr_fix_adjustable): New function.
            * testsuite/gas/all/gas.exp: Skip tests that need adjustable fixups.
            * testsuite/gas/elf/elf.exp: Likewise.
            * testsuite/gas/avr/diffreloc_withrelax.d: Adjust expected output.
            * testsuite/gas/avr/pc-relative-reloc.d: Adjust expected output.
    
    ld      * testsuite/ld-avr/avr-prop-7.d: Adjust expected output.
            * testsuite/ld-avr/avr-prop-8.d: Likewise.
            * testsuite/ld-avr/pr13402.d: Likewise.
Comment 3 Nick Clifton 2021-12-16 16:42:25 UTC
Patch applied.