[Bug c/43876] New: [avr] Improper updating of struct members when written out of order from struct definition
justin at mattair dot net
gcc-bugzilla@gcc.gnu.org
Sat Apr 24 09:02:00 GMT 2010
avr-gcc may improperly update members of a struct if:
1) The access to the members is in a different order than the struct was
defined and
2) The volatile modifier is used on the struct variable (instance) and
3) The target device is set to atxmega128a1 (possibly all xmega chips) and
4) Optimizations are enabled (I tested -Os)
The following code replicates the problem:
#include <avr/io.h>
typedef struct {
uint16_t year;
uint8_t month;
uint8_t mday;
uint8_t hour;
uint8_t min;
uint8_t sec;
} RTC_time_t;
volatile RTC_time_t t;
void rtc_init (void)
{
t.sec = 0;
t.min = 0;
t.hour = 0;
t.mday = 1;
t.month = 1;
t.year = 2010;
//t.month = 1;
//t.mday = 1;
//t.hour = 0;
//t.min = 0;
//t.sec = 0;
}
void main(void)
{
rtc_init();
while (1);
}
The makefile used was the WinAVR Makefile Template written by Eric B.
Weddington, Jörg Wunsch, et al. with MCU = atxmega128a1. The problem does not
exist when using, for example, MCU = atmega32u2, or if the volatile modifier is
removed.
The problem can be seen in the disassembly of rtc_init(). The disassembly
without the problem:
t.year = 2010;
7a1c: 8a ed ldi r24, 0xDA ; 218
7a1e: 97 e0 ldi r25, 0x07 ; 7
7a20: 80 93 1b 2b sts 0x2B1B, r24
7a24: 90 93 1c 2b sts 0x2B1C, r25
t.month = 1;
7a28: 81 e0 ldi r24, 0x01 ; 1
7a2a: 80 93 1d 2b sts 0x2B1D, r24
t.mday = 1;
7a2e: 80 93 1e 2b sts 0x2B1E, r24
t.hour = 0;
7a32: 10 92 1f 2b sts 0x2B1F, r1
t.min = 0;
7a36: 10 92 20 2b sts 0x2B20, r1
t.sec = 0;
7a3a: 10 92 21 2b sts 0x2B21, r1
which is pretty straightforward.
The disassembly of the nonworking version:
t.sec = 0;
7a1c: 10 92 21 2b sts 0x2B21, r1
t.min = 0;
7a20: e0 e2 ldi r30, 0x20 ; 32
7a22: fb e2 ldi r31, 0x2B ; 43
7a24: 10 82 st Z, r1
t.hour = 0;
7a26: 12 92 st -Z, r1
t.mday = 1;
7a28: 81 e0 ldi r24, 0x01 ; 1
7a2a: 82 93 st -Z, r24
t.month = 1;
7a2c: 82 93 st -Z, r24
t.year = 2010;
7a2e: 8a ed ldi r24, 0xDA ; 218
7a30: 97 e0 ldi r25, 0x07 ; 7
7a32: 31 97 sbiw r30, 0x01 ; 1
7a34: 81 93 st Z+, r24
7a36: 90 83 st Z, r25
7a38: 32 97 sbiw r30, 0x02 ; 2
As you can see, the high byte of t.year is being updated with the low byte of
2010. Then t.month is overwritten with the high byte of 2010. The compiler
should have subtracted 2 from Z (the first sbiw instruction), but it only
subtracts 1. It does manage to subtract 2 in the last instruction, which seems
rather pointless.
I have tested this using both avr-gcc 4.3.3 (built on Linux using the
"build-avr-gcc-4.3.3-binutils-2.20-libc-1.6.8-insight6.8-dude-5.10-insight-patch"
script available on avrfreaks.net), avr-gcc 4.3.4, as well as WinAVR20100110 on
Windows. The problem exists in all of these cases.
Using built-in specs.
Target: avr
Configured with: ../../source/gcc-4.3.4/configure -v --target=avr --disable-nls
--prefix=/usr/local/avr --with-gnu-ld --with-gnu-as --enable-languages=c,c++
--disable-libssp --with-dwarf2
Thread model: single
gcc version 4.3.4 (GCC)
Command Line: avr-gcc -c -mmcu=atxmega128a1 -I. -gdwarf-2 -DF_CPU=32000000UL
-Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wundef -Wall -Wstrict-prototypes -Wa,-adhlns=test.lst
-std=gnu99 -MD -MP -MF .dep/test.o.d test.c -o test.o
--
Summary: [avr] Improper updating of struct members when written
out of order from struct definition
Product: gcc
Version: 4.3.4
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: justin at mattair dot net
GCC target triplet: avr-*-*
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43876
More information about the Gcc-bugs
mailing list