Bug 2378 - Incorrect opcode in __do_clear_bss if bss has more than 15 bytes
Summary: Incorrect opcode in __do_clear_bss if bss has more than 15 bytes
Status: RESOLVED WONTFIX
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.16
: P3 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-02-21 21:11 UTC by Ken Jackson
Modified: 2021-09-22 17:04 UTC (History)
4 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: avr
Build: i686-pc-linux-gnu
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ken Jackson 2006-02-21 21:11:56 UTC
Sixteen or more bytes of uninitialized data will cause ld to generate an
incorrect opcode in __do_clear_bss in the startup for the avr target as
shown in this example.


Source file, a.S:
        .comm x,16,1
        .global __do_copy_data
        .global __do_clear_bss
        .global main
    main:
        cpi  r26,lo8(16)
        rjmp main

Compile script:
    FLAGS="-m avr4 -Tdata 0x800100 -L/usr/local/lib/gcc/avr/4.0.2/avr4"
    avr-as a.S -o a.o
    avr-ld $FLAGS -o a.hex /usr/local/avr/lib/avr4/crtm88.o --oformat=ihex \
        a.o  -lgcc -lc
    
    avr-ld $FLAGS -o a.elf /usr/local/avr/lib/avr4/crtm88.o  a.o  -lgcc -lc
    avr-objdump -dSCg a.elf > a.lst

Output a.lst, lines 68,69,77,78:
    00000060 <.do_clear_bss_start>:
      60:   a0 31           cpi r26, 0x10   ; 16
    0000006a <main>:
      6a:   a0 31           cpi r26, 0x10   ; 16

Output a.hex, lines 8,11:
    :100056001160A0E1B16001C01D92B031B107E1F7B6
    :04006A00A031FECFF4


The listing is correct for both cpi instructions, "a0 31", but the hex
file is wrong for the first, "B031", though it's correct for the second,
"A031".  And, indeed, test programs fail to execute on real hardware with
16 or more bytes of BSS, but _do_ execute with less.

The first cpi instruction is in function __do_clear_bss in source file
gcc-4.0.2/gcc/config/avr/libgcc.S.  But gcc itself doesn't seem be be
involved, other than supplying the code, which is assembled by avr-as (or
directly by avr-ld?).  It's not clear how the hex is generated or where 
the error occurs.

I'm using Mandriva Linux 2006 (2.6.12-12mdk) and compiled from source
binutils-2.16.1, gcc-4.0.2, and avr-libc-1.4.3.

$ avr-ld -V
GNU ld version 2.16.1
  Supported emulations:
   avr2
   avr1
   avr3
   avr4
   avr5

Note: I thank everyone that works on binutils.
Comment 1 Ken Jackson 2006-02-22 14:52:31 UTC
I've simplified it by stripping away all gcc influence.  This is purely
a binutils bug.  I suspect it is ld's relocation that is causing the
problem.  Or maybe it's the BFD library, if that's a separate entity.


Source file, a.S:
        .comm x,16,1
        .global main
    main:
        cpi  r26,lo8(__bss_end)
        cpi  r26,lo8(16)

Compile script:
    avr-as a.S -o a.o
    avr-ld -m avr4 -Tdata 0x800100 -o a.elf  a.o
    avr-objdump -d a.elf > a.lst
    avr-ld -m avr4 -Tdata 0x800100 -o a.hex --oformat=ihex  a.o

Output file a.lst, lines 7,8:
    0:   a0 31           cpi r26, 0x10   ; 16
    2:   a0 31           cpi r26, 0x10   ; 16

Output file a.hex:
    :04000000B031A0314A
    :00000001FF


The list file shows both opcodes correctly, "a0 31".  But in the hex file
the first one is wrong, "B031", while the second one is correct, "A031".

The difference is that avr-ld had to do a relocation for the first one.
Running "avr-objdump -r a.o" shows one record with type R_AVR_LO8_LDI
relocation, value __bss_end.

R_AVR_LO8_LDI is performed in binutils-2.16.1/bfd/elf32-avr.c.  It works
correctly for the default ELF format, but fails for the IHEX format.

This is progress, but I'm still stumped.
Comment 2 Nick Clifton 2006-02-28 11:57:50 UTC
Subject: Re:  Incorrect opcode in __do_clear_bss if bss has more
 than 15 bytes

Hi Ken,

>     avr-as a.S -o a.o
>     avr-ld -m avr4 -Tdata 0x800100 -o a.elf  a.o
>     avr-objdump -d a.elf > a.lst
>     avr-ld -m avr4 -Tdata 0x800100 -o a.hex --oformat=ihex  a.o

> The list file shows both opcodes correctly, "a0 31".  But in the hex file
> the first one is wrong, "B031", while the second one is correct, "A031".
> 
> The difference is that avr-ld had to do a relocation for the first one.
> Running "avr-objdump -r a.o" shows one record with type R_AVR_LO8_LDI
> relocation, value __bss_end.
> 
> R_AVR_LO8_LDI is performed in binutils-2.16.1/bfd/elf32-avr.c.  It works
> correctly for the default ELF format, but fails for the IHEX format.
> 
> This is progress, but I'm still stumped.

It is quite common that LD is unable to correctly translate binary file 
formats and link at the same time.  Quite a few targets suffer from this 
problem.  The simplest workaround is to perform the link first and then 
use objcopy to perform the binary translation.  ie:

   avr-ld -m avr4 -Tdata 0x800100 -o a.elf a.o
   avr-objcopy --output-target ihex a.elf a.ihex

Cheers
   Nick


Comment 3 Ken Jackson 2006-02-28 13:49:46 UTC
Thank you Nick.

Someone at avrfreaks gave me the same information.  I meant to
update the bug, but didn't get to it.

It's still a bug, because the documented capability does not work.
This cost me nearly two weeks of frustration, and may do the same
to others.  But it's clearly a low priority because avr-objcopy
works.
Comment 4 Ben Elliston 2006-04-04 01:57:05 UTC
Updating priority.
Comment 5 Eric Weddington 2010-09-20 02:54:05 UTC
Resolving bug as WONTFIX.

This is an old bug. Standard operating procedure on AVR is to link first, then
use objcopy to convert to other formats. Plus the user should call the assembler
and linker through avr-gcc.