Forum: Compiler & IDEs AVR-GCC 4.7.2 Bug?


von Daniel C. (cecky)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich könnte hier einmal die Hilfe der Compilerexperten gebrauchen. Ich 
wollte heute meinen digitalen Müllkalender ein wenig erweitern. Um die 
Farbentöne besser anpassen zu können habe ich eine hsv2rgb-Funktion 
eingebaut (stammt hier irgendwo aus dem Forum), die ich so auch schon 
erfolgreich an anderer Stelle verwendet habe. Leider kam es beim Testen 
zu seltsamen Farbsprüngen. Nach mehreren Stunden erfolglosem testen viel 
mir ein, das ich kürzlich die AVR-Toolchain aktualisiert hatte.
Also habe ich die AVR-Toolchain 3.4.2-1573 deinstalliert und wieder die 
AVR-Toolchain 3.4.1-1195 installiert, anschließend das Projekt neu 
kompiliert, und alles lief Fehlerfrei. Laut dem Artikel hier im Forum 
unterscheiden sich lediglich die AVR-GCC Versionen der beiden Toolchains 
(http://www.mikrocontroller.net/articles/Atmel_Studio)
3.4.2-1573 AVR-GCC 4.7.2
3.4.1-1195 AVR-GCC 4.6.2

Um das ganze nochmal zu überprüfen, habe ich ein kleines Testprogramm 
aufgesetzt:
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include "uart.h"
4
5
uint8_t rot,gruen,blau;
6
7
void setColorHSV(uint8_t h, uint8_t s, uint8_t v)
8
{
9
  uint16_t vs=v*s, h6=6*h, f;
10
  uint8_t i, p, u, r=v, g=v, b=v;
11
12
  p = ((v<<8)-vs) >> 8;
13
  i = h6 >> 8;
14
  f = ((i|1)<<8) - h6;
15
  if(i&1) f = -f;
16
  u = (((uint32_t)v<<16) - (uint32_t)vs*f) >> 16;
17
  switch(i) {
18
    case 0: g = u; b =  p; break;
19
    case 1: r = u; b =  p; break;
20
    case 2: r =  p; b = u; break;
21
    case 3: r =  p; g = u; break;
22
    case 4: r = u; g =  p; break;
23
    case 5: g =  p; b = u; break;
24
  }
25
  rot = r; gruen = g; blau = b;
26
}
27
28
int main (void)
29
{
30
  char buffer[30];
31
  uart_init();
32
33
  uint8_t flag = 0;  
34
35
  while(1)
36
  {
37
    if(!flag)
38
    {
39
      uart_puts("Start\r\n");
40
      for(uint8_t i = 0; i<255;i++)
41
      {
42
        setColorHSV(85,255,i);
43
        sprintf(buffer,"i: %i, rot: %i, gruen: %i, blau: %i \r\n", i, rot, gruen, blau);
44
        uart_puts(buffer);
45
      }
46
      uart_puts("Ende\r\n");
47
      flag = 1;
48
    }
49
  }
50
}

Dann habe ich es nochmal mit jeder Toolchain compiliert und auf einen 
ATmega168 getestet und die Ausgaben mit putty in Log-Files schreiben 
lassen.

Hier zeigt sich, das mit dem AVR-GCC 4.6.2 die Ausgaben völlig korrekt 
sind und mit dem AVR-GCC 4.7.2 in einem Abschnitt falsche Werte erzeugt 
werden.
Hab mir zwar mal die beiden erzeugten lss-files angeschaut, aber meine 
Assemblerkentnisse sind gleich 0 und die Unterschiede viel zu zahlreich 
:-) Prinzipiell gehe ich erst mal davon aus, das der Fehler vor der 
Tastatur sitzt aber in diesem Fall bin ich mir nicht sicher. Vielleicht 
kann sich das ja mal jemand anschauen, der da deutlich mehr Ahnung von 
hat als ich. Ich werde mal das AVR-Studio Projekt anhängen und die 
jeweils erzeugten lss-files sowie die log-files.

Abschließend noch Infos zum Testaufbau:
Hardware:
ATmega168 auf STK500, int. RC @ 8MHz
Software:
AVR-Studio 4.19 Build 730
einmal mit AVR-Toolchain 3.4.2-1573
und einmal mit AVR-Toolchain 3.4.1-1195

Hoffe ich habe im Eifer des Gefechts keine Infos vergessen.

Cecky

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn ich die uart_puts() mal durch puts() ersetze und das auf dem
Host laufen lasse, dann bekomme ich ein:
1
Start
2
*** buffer overflow detected ***: /tmp/hsv terminated
3
======= Backtrace: =========
4
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7ffff7b25817]
5
/lib/x86_64-linux-gnu/libc.so.6(+0x109710)[0x7ffff7b24710]
6
/lib/x86_64-linux-gnu/libc.so.6(+0x108b79)[0x7ffff7b23b79]
7
/lib/x86_64-linux-gnu/libc.so.6(_IO_default_xsputn+0xdd)[0x7ffff7a9713d]
8
/lib/x86_64-linux-gnu/libc.so.6(_IO_vfprintf+0x1ae7)[0x7ffff7a654a7]
9
/lib/x86_64-linux-gnu/libc.so.6(__vsprintf_chk+0x94)[0x7ffff7b23c14]
10
/lib/x86_64-linux-gnu/libc.so.6(__sprintf_chk+0x7d)[0x7ffff7b23b5d]
11
/tmp/hsv[0x4004ef]
12
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7ffff7a3c76d]
13
/tmp/hsv[0x400539]

Sollte dir das zu denken geben?  Vermutlich schon. :-)

Dein char buffer[] ist einfach zu klein.

von Daniel C. (cecky)


Angehängte Dateien:

Lesenswert?

Ja, da gebe ich dir 100%ig recht. War ja klar, das ich mir so nen Patzer 
einbrocke :-) Hatte kurz vorher i noch mit in die Ausgabe aufgenommen 
und vergessen den buffer zu vergrößern. Aber auch wenn ich buffer[60] 
verwende ändert das nichts am Ergebnis. 4.6.2 richtig, 4.7.2 falsch. Und 
da in der Ausgabe keine Zeile mehr als 36 Zeichen lang ist, sollte der 
buffer doch ausreichend groß sein, oder bin ich hier irgendwie 
Betriebsblind?

Davon mal abgesehen, wenn ich das ganze an eine RGB-LED hänge, und mir 
einfach mal die Farbe Grün Ein und Ausfaden lasse (wie in diesem 
Beispiel), dann ist mit 4.6.2 alles wunderbar und mit 4.7.2 kommt es zum 
Farbsprung, der dem Logfile eindeutig entspricht. Im ursprünglichen 
Müllkalender gibt es keine Uart-Ausgabe, also kann da ja auch kein 
buffer zu klein sein.

Cecky

von Heini (Gast)


Lesenswert?

Daniel C. schrieb:
> void setColorHSV(uint8_t h, uint8_t s, uint8_t v)
> {
>   uint16_t vs=v*s, h6=6*h, f;

Typecasted das überhaupt richtig? Ich bin mir bei sowas nie sicher. v 
ist 8 Bit, s auch. v*s passt da nicht rein. Wird da vom Compiler vorher 
erweitert? Oder erst bei der Zuweisung nach vs? Sind ja noch mehr so 
Fälle drin.

von Karl H. (kbuchegg)


Lesenswert?

Heini schrieb:
> Daniel C. schrieb:
>> void setColorHSV(uint8_t h, uint8_t s, uint8_t v)
>> {
>>   uint16_t vs=v*s, h6=6*h, f;
>
> Typecasted das überhaupt richtig?

OK.
Faustregel:

gerechnet wird IMMER mindestens im Datentyp int. (*)
In dem Fall eines AVR also 16 Bit.

Aber .... (nächstes Posting)


(*) Es sei denn der Compiler kann beweisen, dass es keinen Unterschied 
macht, wenn er auf 8 Bit abkürzt. Das dürft ihm allerdings bei einer 
Multiplikation und Zuweisung an einen 16-Bit int schwerfallen.

von Karl H. (kbuchegg)


Lesenswert?

Daniel C. schrieb:
> Ja, da gebe ich dir 100%ig recht. War ja klar, das ich mir so nen Patzer
> einbrocke :-) Hatte kurz vorher i noch mit in die Ausgabe aufgenommen
> und vergessen den buffer zu vergrößern. Aber auch wenn ich buffer[60]
> verwende ändert das nichts am Ergebnis. 4.6.2 richtig, 4.7.2 falsch. Und
> da in der Ausgabe keine Zeile mehr als 36 Zeichen lang ist, sollte der
> buffer doch ausreichend groß sein, oder bin ich hier irgendwie
> Betriebsblind?

Nö. Passt schon.
Lass dir mal innerhalb der Funktion die Zwischenwerte ausgeben.

Fang damit an

  uint16_t vs=v*s


Auch wenn v und s zuerst auf 16 Bit erweitert werden, bin ich mir jetzt 
nicht sicher, ob sie auf int oder unsigned int erweitert werden. Bei int 
hast du hier ein Problem, denn 128*255 wäre grade an der Grenze zum 
Überlaufen. Und du siehst ja auch deinen Sprung bei einem Wert für i von 
128

von Daniel C. (cecky)


Angehängte Dateien:

Lesenswert?

So, hab jetzt mal die Zwischenwerte mit eingebaut. Die Ergebnisse für
uint16_t vs=v*s
sind mit beiden Compilern identisch.

Allerdings sind hier differernzen festzustellen wenn die Zählvariable 
größer als 128 wird:
u = (((uint32_t)v<<16) - (uint32_t)vs*f) >> 16;

von Heini (Gast)


Lesenswert?

Ich trenne die Berechnungen bei solchen Problemen immer weiter auf. 
Hilfsvariablen, einzelne Rechenschritte, etc. So ist dann auch der 
Assemblercode lesbar. Manchmal kann man durch Umstellen sogar noch ein 
paar Bytes rausholen, obwohl der Compiler da schon ziemlich gut geworden 
ist (versuche auch mal den 4.8).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Daniel C. schrieb:

> Hier zeigt sich, das mit dem AVR-GCC 4.6.2 die Ausgaben völlig korrekt
> sind und mit dem AVR-GCC 4.7.2 in einem Abschnitt falsche Werte erzeugt
> werden.

Gibt's dazu einen Testfall? etwa
1
#include <stdlib.h>
2
3
int main (void)
4
{
5
    /* Code */
6
    if (bedingung)
7
      exit (0);
8
    else 
9
      abort();
10
}
Wo der code wider erwarten auf abort() läuft.

Neben dem Testfall braucht man auch die Compilerschalter und -version.

von Daniel C. (cecky)


Lesenswert?

@Johann
Das einzige was ich bis jetzt habe, ist das was ich hier so alles 
angehängt habe.
Aber hier mal die Ergebnisse vom Buildvorgang:

AVR-GCC 4.6.2:
Build started 31.5.2013 at 18:41:54
avr-gcc -I"D:\Eigene Dateien\AVR - 
Mikrocontroller\Projekte\GCC-Testcase\."  -mmcu=atmega168 -Wall 
-gdwarf-2 -std=gnu99   -DF_CPU=8000000UL -Os -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT main.o -MF 
dep/main.o.d  -c  ../mai
n.c

avr-gcc -mmcu=atmega168 -Wl,-Map=GCC-Testcase_4.6.2.map main.o uart.o 
-o GCC-Testcase_4.6.2.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature 
GCC-Testcase_4.6.2.elf GCC-Testcase_4.6.2.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
--change-section-lma .eeprom=0 --no-change-warnings -O ihex 
GCC-Testcase_4.6.2.elf GCC-Testcase_4.6.2.eep || exit 0
avr-objdump -h -S GCC-Testcase_4.6.2.elf > GCC-Testcase_4.6.2.lss

AVR Memory Usage
----------------
Device: atmega168

Program:    3022 bytes (18.4% Full)
(.text + .data + .bootloader)

Data:        231 bytes (22.6% Full)
(.data + .bss + .noinit)


Build succeeded with 0 Warnings...
-----------------------------------------------------------------------
AVR-GCC 4.7.2:
Build started 31.5.2013 at 19:01:43
avr-gcc -I"C:\Dokumente und 
Einstellungen\XPMUser\Desktop\GCC-Testcase\."  -mmcu=atmega168 -Wall 
-gdwarf-2 -std=gnu99     -DF_CPU=8000000UL -Os -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT main.o -MF 
dep/main.o.d  -c  ../mai
n.c

avr-gcc -mmcu=atmega168 -Wl,-Map=GCC-Testcase_4.7.2.map main.o uart.o 
-o GCC-Testcase_4.7.2.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature 
GCC-Testcase_4.7.2.elf GCC-Testcase_4.7.2.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
--change-section-lma .eeprom=0 --no-change-warnings -O ihex 
GCC-Testcase_4.7.2.elf GCC-Testcase_4.7.2.eep || exit 0
avr-objdump -h -S GCC-Testcase_4.7.2.elf > GCC-Testcase_4.7.2.lss
ECHO ist ausgeschaltet (OFF).
AVR Memory Usage
----------------
Device: atmega168

Program:    2788 bytes (17.0% Full)
(.text + .data + .bootloader)

Data:        231 bytes (22.6% Full)
(.data + .bss + .noinit)


Build succeeded with 0 Warnings...

Werde jetzt mal versuchen die Zeile
  u= (((uint32_t)v<<16) - (uint32_t)vs*f) >> 16;
aufzutrennen und davon mal Zwischenergebnisse ausgeben zu lassen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Zwischenergebnisse sind nicht so hilfreich.  Wenn der Code irgendwo 
rechnet 1+1 = 3 dann ist das immer noch nicht für andere 
nachvollziehbar.  Wenn du hingegen einen Testfall hast wie
1
#include <stdlib.h>
2
3
int i = 1;
4
5
int main (void)
6
{
7
    int a = i + 1;
8
9
    if (a == 2)
10
        exit (0);
11
    else
12
        abort ();
13
}
und der Code läuft auf abort — etwa im Simulator — dann können andere 
das nachvollziehen und das Problem dingfest machen.

von Daniel C. (cecky)


Angehängte Dateien:

Lesenswert?

So, hab die fragliche Zeile mal zerlegt. Fakt ist, wenn der 
Schleifenzähler einen wert von 128 hat rechnen beide Compiler das 
Zwischenergebnis u2 gleich aus. Wenn der Schleifenzähler einen Wert von 
129 hat rechnen die Compiler unterschiedlich (Siehe anhang)!!

Witzigerweise, wenn ich die Berechnung mal aus der Funktion ausgliedere 
und die Berechnung einfach per Hand mache wie im folgenden Code:
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include "uart.h"
4
5
int main (void)
6
{
7
  char buffer[90];
8
  uart_init();
9
  uint16_t vs,f;
10
  uint32_t u2;
11
  uint8_t v,s;
12
  s = 255;  
13
  f=254;
14
  // 1:
15
  vs = 32640;
16
  u2 = (uint32_t)vs*f;
17
  sprintf(buffer,"1: u2= %lu\r\n",u2);
18
  uart_puts(buffer);
19
20
  // 2:
21
  vs = -32641;
22
  u2 = (uint32_t)vs*f;
23
  sprintf(buffer,"2: u2= %lu\r\n",u2);
24
  uart_puts(buffer);
25
26
  // 3:
27
  v = 128;
28
  vs = v*s;
29
  u2 = (uint32_t)vs*f;
30
  sprintf(buffer,"3: u2= %lu\r\n",u2);
31
  uart_puts(buffer);
32
33
  // 4:
34
  v = 129;
35
  vs = v*s;
36
  u2 = (uint32_t)vs*f;
37
  sprintf(buffer,"4: u2= %lu\r\n",u2);
38
  uart_puts(buffer);
39
40
  while(1)
41
  {
42
  }
43
}

dann geben beide Compiler das gleiche Ergebnis aus ?!?:
1: u2= 8290560
2: u2= 8355330
3: u2= 8290560
4: u2= 8355330

Irgendwie will mir das nicht in den Schädel, oder ich sehe den Wald vor 
lauter Bäumen nicht ?!?!?!?

von Daniel C. (cecky)


Lesenswert?

@Johann
Leider funktioniert bei mir unter Win7 64bit der Simulator nicht. Da 
kackt mir immer das AVR-Studio ab. Deswegen mache ich das ganze ja per 
UART, damit ich überhaupt mal was debuggen kann. Leider kann ich das 
ganze nicht weiter Eingrenzen wie in meinem letzten Post.

von Heini (Gast)


Lesenswert?

Inwiefern ist das aber jetzt noch die gleiche Berechnung? Ein Teil 
fehlt, ein Teil wurde per Hand berechnet.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es gibt auch robuste Simulatoren :-) Etwa avrtest.

von Daniel C. (cecky)


Lesenswert?

@Henni
Ich wollte halt die Werte zur Berechnung von u2 einfach mal aus der 
Funktion rauslösen um die Suche etwas einzugrenzen. Die Werte die sonst 
an die Funktion übergeben werden, bzw darin berechnet wurden, hab ich 
soweit möglich per Hand vorgegeben.

Zumindestens hab ich es mittlerweile mal geschafft sowohl das Ergebnis
8355330 für u2 (beim 4.6.2) als auch das Ergebnis 4286676482 für u2 
(beim 4.7.2) auf dem Papier nach zu vollziehen.

uint16_t vs = -32641 (0x807F)
uint16_t f  = 254    (0x00FE)
(Die werte von vs und f wurden einem älteren log-file entnommen bei 
Schleifenzähler == 129)

Vermutung 4.6.2
u2 = (uint32_t)vs*f
0x0000807f * 0x00FE = 0x007F7E02 (8355330) wie in 4.6.2.txt

Vermutung 4.7.2
u2 = (uint32_t)vs*f
0xFFFF807f * 0x00FE = 0xFF817E02 (4286676482) wie in 4.7.2.txt

Nur was davon ist wirklich richtig? Mir platzt gleich die Rübe :-)

@Johann
Dann will ich mir mal den robusten Simulator anschauen :-)

von Walter S. (avatar)


Lesenswert?

schreib doch Mal statt:
uint16_t vs=v*s, h6=6*h, f;

uint16_t vs=(uint16_t)v*(uint16_t)s, h6=6*h, f;

von Daniel C. (cecky)


Lesenswert?

Walter S. schrieb:
> schreib doch Mal statt:
> uint16_t vs=v*s, h6=6*h, f;
>
> uint16_t vs=(uint16_t)v*(uint16_t)s, h6=6*h, f;

Bleibt leider beim selben Ergebnis. 4.7.2 rechnet anders als 4.6.2. Hab 
inzwischen in einem Simulator mal die Variableninhalte prüfen können. 
Diese sind identisch mit den sprintf-Ausgaben. Habe auch mal meinen 
Laptop angeschmissen, da war noch ein 4.5.1 installiert. Der erzeugt 
aber die selben Ausgaben wie der 4.6.2.

Ändere ich die Deklaration
uint16_t vs=v*s
in
volatile uint16_t vs=v*s
dann kommt auch mit dem 4.7.2 die gleiche Ausgabe wie mit den anderen 
Versionen.
Ebenso ist die Ausgabe beim 4.7.2 identisch mit den anderen Versionen, 
wenn ich f nicht berechnen lasse, sondern direkt den sonst berechneten 
Wert(254) zuweise.

von Walter S. (avatar)


Lesenswert?

das ist doch Käse:

uint16_t f;
...
if(i&1) f = -f;

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Momentan verwende ich folgendes kleines Testprogramm:
1
#include <stdlib.h>
2
#include <stdint.h>
3
4
uint16_t f  = 254; // 0x00FE
5
6
int main (void)
7
{
8
    uint16_t vs = -32641; // 0x807F
9
    uint32_t u2 = (uint32_t) vs * f;
10
    
11
    if (u2 != 8355330)
12
        abort();
13
    
14
    exit (0);
15
16
    return 0;
17
}

Compiliert mit avr-gcc 4.6.2, 4.7.2 und 4.8.0-rc1 vom 6.3.2013 läuft das 
Programm auf exit.  Binutils ist 2.23 oder neuer:
1
avr-gcc -mmcu=atmega168 cecky.c exit-atmega168.o -Os -save-temps -o cecky.elf -Wl,-Map,cecky.map
2
avr-objdump -d cecky.elf > cecky.lst
3
avrtest -no-stdin -mmcu=avr51 cecky.elf
4
5
 exit status: EXIT
6
      reason: exit function called
7
     program: cecky.elf
8
exit address: 0000c8
9
total cycles: 273

main sieht so aus:
1
000000d0 <main>:
2
  d0:  20 91 00 01   lds  r18, 0x0100
3
  d4:  30 91 01 01   lds  r19, 0x0101
4
  d8:  af e7         ldi  r26, 0x7F  ; 127
5
  da:  b0 e8         ldi  r27, 0x80  ; 128
6
  dc:  0e 94 97 00   call  0x12e  ; 0x12e <__umulhisi3>
7
  e0:  62 30         cpi  r22, 0x02  ; 2
8
  e2:  7e 47         sbci  r23, 0x7E  ; 126
9
  e4:  8f 47         sbci  r24, 0x7F  ; 127
10
  e6:  91 05         cpc  r25, r1
11
  e8:  11 f0         breq  .+4        ; 0xee <main+0x1e>
12
  ea:  0e 94 65 00   call  0xca  ; 0xca <abort>
13
  ee:  80 e0         ldi  r24, 0x00  ; 0
14
  f0:  90 e0         ldi  r25, 0x00  ; 0
15
  f2:  0e 94 63 00   call  0xc6  ; 0xc6 <exit>

exit-atmega168.0 ist wie von avrtest erzeugt für einen ATmega168.

Beachte, daß einige Atmel-Patches zu einer fehlerhaften 32 = 16x16 
Multiplikation führen, siehe z.B. http://gcc.gnu.org/PR52474 und die 
dortige Diskussion.

Im 4.8 Dump sieht __umulhisi3 so aus:
1
0000012e <__umulhisi3>:
2
 12e:  a2 9f         mul  r26, r18
3
 130:  b0 01         movw  r22, r0
4
 132:  b3 9f         mul  r27, r19
5
 134:  c0 01         movw  r24, r0
6
 136:  a3 9f         mul  r26, r19
7
 138:  70 0d         add  r23, r0
8
 13a:  81 1d         adc  r24, r1
9
 13c:  11 24         eor  r1, r1
10
 13e:  91 1d         adc  r25, r1
11
 140:  b2 9f         mul  r27, r18
12
 142:  70 0d         add  r23, r0
13
 144:  81 1d         adc  r24, r1
14
 146:  11 24         eor  r1, r1
15
 148:  91 1d         adc  r25, r1
16
 14a:  08 95         ret

Und in den älteren Versionen:
1
0000012e <__umulhisi3>:
2
 12e:  a2 9f         mul  r26, r18
3
 130:  b0 01         movw  r22, r0
4
 132:  b3 9f         mul  r27, r19
5
 134:  c0 01         movw  r24, r0
6
 136:  a3 9f         mul  r26, r19
7
 138:  01 d0         rcall  .+2        ; 0x13c <__umulhisi3+0xe>
8
 13a:  b2 9f         mul  r27, r18
9
 13c:  70 0d         add  r23, r0
10
 13e:  81 1d         adc  r24, r1
11
 140:  11 24         eor  r1, r1
12
 142:  91 1d         adc  r25, r1
13
 144:  08 95         ret

Beachte, daß __umulhisi3 von der Standard-ABI abweicht.

von Daniel C. (cecky)


Lesenswert?

@johann
Mit deinem Code komm ich zum selben Ergebnis. Wenn ich bei mir f direkt 
mit einem Wert vorbelege, dann funktioniert das auch unter beiden 
Compilern.

@Walter S.
Mag sein, das das Käse ist. Wie oben schon erwähnt habe ich den Code 
hier aus dem Forum, und der werkelt bei mir in 4 Projekten ohne Probleme 
(zumindest machen die RGB-LED's das was sie sollen). Aber selbst wenn 
das Käse ist sollte es doch gleich gut oder gleich schlecht 
funktionieren.

Wie dem auch sei, ich werde mir mal die Diskussion durchlesen aber so 
langsam verlässt mich auch die Motivation da noch mehr Zeit zu 
investieren. Auf meinem System ist einfach Fakt, das es mit der 
aktuellen AVR-Toolchain einfach nicht funktioniert, und mit den beiden 
verhergehenden Versionen das gewünschte Ergebnis erreicht wird. Somit 
warte ich einfach bis zum nächsten Toolchain release und probier es dann 
noch mal :-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Na dann viel Glück.  Bugs lösen sich nicht in Wohlgefallen auf sondern 
dadurch, daß sie samt Testfall reportiert und dann behoben werden.

Mementan ist kein Fehler bekannt, der annähern die genannten Artfakte 
erzeugt.  Siehe die aktuelle Fehlerliste in 
http://www.mikrocontroller.net/articles/Avr-gcc_Bugs

von Walter S. (avatar)


Lesenswert?

Daniel C. schrieb:
> Aber selbst wenn
> das Käse ist sollte es doch gleich gut oder gleich schlecht
> funktionieren.

das ist nicht richtig, ein fehlerhaftes Programm kann unter Umständen 
auch funktionieren (oder auch nicht)

aber das mit dem Käse nehme ich zurück, - von einer unsigned Variable 
ist schon ein erlaubter Ausdruck

von Daniel C. (cecky)


Lesenswert?

Johann L. schrieb:
> Bugs lösen sich nicht in Wohlgefallen auf

Natürlich lösen sie sich nicht von allein. Leider hab ich es nicht 
geschafft einen besseren Testfall zu erzeugen wie mit der uart-ausgabe. 
Und da meine Assembler und Compilerkentnisse annährend 0 sind, bin ich 
vielleicht einfach der falsche für diese Aufgabe. Vielleicht stößt ja 
jemand kompetenteres auf ein ähnliches Problem und kann das dann 
entsprechend besser diagnostizieren.
Ich bin jedenfalls mit meinem Latein am Ende.

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

Deinem Programm von Beitrag "Re: AVR-GCC 4.7.2 Bug?" 
übersetzt mit avr-gcc-4.7.2 funktioniert im avrtest Simulator 
einwandfrei, siehe Anhang.
1
$ avr-gcc -mmcu=atmega168 cecky.c d:/C/avrtest/exit-atmega168.o -Os -funsigned-char -std=c99 -o cecky.elf -Wl,-Map,cecky.map
2
$ avrtest -no-stdin -mmcu=avr51 cecky.elf > cecky.log

von Daniel C. (cecky)


Lesenswert?

Johann L. schrieb:
> übersetzt mit avr-gcc-4.7.2 funktioniert im avrtest Simulator
> einwandfrei, siehe Anhang.

Nein, tut es nicht(vorrausgesetzt dein angehängtes Logfile wurde auch 
von dir erzeugt). Wenn du dir das Log-file näher ansiehst wirst du 
feststellen, das bei i=129 "rot" einen wert von 255 hat. Sollte aber 1 
sein. Vergleiche das mal mit den beiden Logfiles von meinen ersten 
posting. Ab i>128 beginnen die unterschiede.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ok, hab den Testfall weiter reduziert zu
1
#include <stdlib.h>
2
#include <stdint.h>
3
4
uint8_t __attribute__((__noinline__))
5
rot (uint8_t v)
6
{
7
    uint16_t vs = v * 255;
8
9
    return (0x810000 - (uint32_t) vs*254) >> 16;
10
}
11
12
int main (void)
13
{
14
    uint8_t r = rot (129);
15
16
    if (r != 1)
17
        abort();
18
    exit (0);
19
}

und übersetzt mit
1
$ avr-gcc -mmcu=atmega168 cecky.c -Os -funsigned-char -o cecky.elf

Mit 4.7 und 4.8 läuft das auf abort und mit 4.6 auf exit.  Grund ist, 
daß __usmulhisi3 verwendet wird, d.h. bei der widening mul wird ein 
Operand sign-extended.  Die korrekte Multiplikationsroutine ist hingegen 
__umulhisi3.  Im 4.6 gibt es diese Routine noch nicht; statt dessen 
werden die Werte auf 32 Bits expandiert und ein __mulsi3 ausgeführt.

Das s-dump von 4.7.2 ist:
1
rot:
2
  push r16   ;  36  pushqi1/1  [length = 1]
3
  push r17   ;  37  pushqi1/1  [length = 1]
4
  ldi r25,lo8(-1)   ;  34  movqi_insn/2  [length = 1]
5
  mul r24,r25   ;  35  umulqihi3  [length = 3]
6
  movw r26,r0
7
  clr __zero_reg__
8
  ldi r18,lo8(-2)   ;  28  *movhi/5  [length = 2]
9
  ldi r19,0
10
  call __usmulhisi3   ;  30  *usmulhisi3_call  [length = 2]
11
  ldi r16,0   ;  12  *movsi/5  [length = 4]
12
  ldi r17,0
13
  ldi r18,lo8(-127)
14
  ldi r19,0
15
  sub r16,r22   ;  13  subsi3  [length = 4]
16
  sbc r17,r23
17
  sbc r18,r24
18
  sbc r19,r25
19
  mov r24,r18   ;  20  movqi_insn/1  [length = 1]
20
  pop r17   ;  40  popqi  [length = 1]
21
  pop r16   ;  41  popqi  [length = 1]
22
  ret   ;  42  return_from_epilogue  [length = 1]
23
24
25
main:
26
  ldi r24,lo8(-127)   ;  5  movqi_insn/2  [length = 1]
27
  call rot   ;  6  call_value_insn/2  [length = 2]
28
  cpi r24,lo8(1)   ;  8  *cmpqi/3  [length = 1]
29
  breq .L3   ;  9  branch  [length = 1]
30
  call abort   ;  11  call_insn/2  [length = 2]
31
.L3:
32
  ldi r24,0   ;  15  *movhi/2  [length = 2]
33
  ldi r25,0
34
  call exit   ;  16  call_insn/2  [length = 2]

von Daniel C. (cecky)


Lesenswert?

Erst mal ein großes dankeschön, das du dich dem Problem weiterhin 
annimmst. So weit hätte ich das auf die schnelle jedenfalls nicht 
reduzieren können.

Also wenn ich dich jetzt richtig verstanden habe, dann verwendet der 
4.7.2 (um beim s-dump zu bleiben) fälschlicherweise die Funktion 
__usmulhisi3?
Bliebe noch die Frage, is it a bug or a feature?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es ist ein Bug: http://gcc.gnu.org/PR57503

von Daniel C. (cecky)


Lesenswert?

Alles klar :-) Und vielen Dank für die großzügige Unterstützung

Cecky

von W.S. (Gast)


Lesenswert?

Daniel C. schrieb:
> Und da meine Assembler und Compilerkentnisse annährend 0 sind, bin ich..

aber du versuchst dich trotzdem am Programmeschreiben. Wäre es nicht 
besser, zunächst die nötigen Kenntnisse zu erwerben?

Johann L. schrieb:
> rot (uint8_t v)
> {
>     uint16_t vs = v * 255;
>
>     return (0x810000 - (uint32_t) vs*254) >> 16;
> }

Jaja. Wenn man sowas mal heraus-seziert anschaut, dann kommt einem schon 
die Galle hoch. Immer wieder die besonders sparsamen C-Programmierer, 
die mit jeder Zeile sparen. C wurde offensichtlich von Schwaben 
schottischer Abstammung im Exil entworfen. Immer feste die 
Variablendeklaration mit der Wertzuweisung zusammenschmeißen und dann 
auch noch ne 8 Bit Variable dabei mit 255 multiplizieren.

int rot (unsigned char v)
{ long vs;
  vs = v;
  vs = (vs<<8) - vs;
  return (0x810000 - ((vs*254)) >> 16; // was das auch immer ergeben 
soll..
}

Typecasts sind m.E. keine Typumwandlungen!
Abgesehen davon frag ich mich, was
(0x810000 - argument  254  255)/65536
ergeben soll.
129 - argument - (argument>>6) - (argument>>7) würde es doch auch tun - 
oder?

W.S.

von Le X. (lex_91)


Lesenswert?

W.S. schrieb:
> aber du versuchst dich trotzdem am Programmeschreiben. Wäre es nicht
> besser, zunächst die nötigen Kenntnisse zu erwerben?

Hochsprachen wurden entwickelt, damit man sich eben genau damit nicht 
herumplagen muss.


>...und dann
> auch noch ne 8 Bit Variable dabei mit 255 multiplizieren.

Zugegeben unsauber, aber hier egal. Die Rechnung wird in int (hier 16 
Bit) durchgeführt, das Ergebniss mit 16 Bit gespeichert.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

W.S. schrieb:

> blahhh ....

Und was hat dieses dein Rumgemäkel mit dem Compiler-Bug zu tun???

von apr (Gast)


Lesenswert?

Insbesondere, weil endlich mal einer der "Compiler Bug" Threads wirklich 
einer war :)

von Daniel C. (cecky)


Lesenswert?

W.S. schrieb:
> aber du versuchst dich trotzdem am Programmeschreiben.
Yupp, und das funktioniert auch wunderbar.
Ich fahre sogar Auto ohne eine abgeschlossene Ausbildung als 
KFZ-Mechaniker.

Du bist offensichtlich kein Freund von C -> Es sei dir gegönnt. Du bist 
also der große Assembler-Guru -> Glückwunsch. Du weißt mehr als andere 
-> 100 Gummipunkte. Du programmierst besser, schneller, schöner, 
effektiver (weitere Adjektive sind frei zu ergänzen).. -> 1 mit 
Sternchen.

Ich konnte jedenfalls der Community einen kleinen Anstoß geben, der im 
Endeffekt zur Aufdeckung eines Bugs geführt hat, und damit bin ich 
persönlich sehr zufrieden. Und mehr will und werde ich dazu auch nicht 
sagen.

Cecky

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Daniel C. schrieb:
> Du bist offensichtlich kein Freund von C

Nein, er wollte einfach nur auch mal was anmerken.  Natürlich, ohne
sich dabei die Mühe zu machen, vorher noch den Rest des Threads zu
lesen.

von Karsten W. (lsmod)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin auch erst dabei C zu lernen und werde gerade ebenfalls mit einem 
Problem konfrontiert das nach einem GCC 4.7.2 Bug aussieht.

Das angehängte C-Programm kompiliert unvollständig!

Wie man in dem Objektdump sehen kann werden die Subroutinen 
"check_inputs" und "print_inputs" überhaupt nicht richtig kompiliert !?

1
 **********************************************************/
2
void check_inputs (void) {
3
  int8_t i, iport;
4
  
5
  iport = PORTINPUT & 0b11100000;
6
 150:  80 b3         in  r24, 0x10  ; 16
7
 152:  08 95         ret
8
9
00000154 <print_inputs>:
10
      uart_char('1');
11
    } else {
12
      uart_char('0');
13
    }
14
  }
15
  uart_string(CR);
16
 154:  80 e6         ldi  r24, 0x60  ; 96
17
 156:  90 e0         ldi  r25, 0x00  ; 0
18
 158:  8a cf         rjmp  .-236      ; 0x6e <uart_string>


Das kompilieren selber verläuft aber ohne Fehler !?

1
$ make
2
avr-gcc -c -mmcu=atmega8 -I. -gstabs   -Os -Wall -Wstrict-prototypes -std=gnu99  main.c -o main.o 
3
4
main.c:4:3: warning: #warning "F_CPU war noch nicht definiert, wird nun mit 11.059.200 definiert" [-Wcpp]
5
avr-gcc -mmcu=atmega8 -I. -gstabs   -Os -Wall -Wstrict-prototypes -std=gnu99  main.o   --output main.elf     -lm
6
7
avr-objcopy -j .text -j .data -O binary main.elf main.bin
8
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
9
avr-objdump -h -S main.elf > main.lst
10
du -b main.bin
11
374     main.bin

Ist in dem Quellcode noch ein DAU-Fehler enthalten oder ist dies 
tatsächlich ein Bug?

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Kein Wunder:
1
for(i = 0; i >= 2; i ++) {
2
   ...
3
}

Was meinst Du, wie oft diese Schleife durchlaufen wird und was der 
Compiler damit macht?

von (prx) A. K. (prx)


Lesenswert?

Was sollte diese Zeile deiner Ansicht nach machen?
 for(i = 2; i == 0; i --) {
also
 i = 2;
 while (i == 0) [

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Da ist jemand Anhänger von Schleifen mit Null-Effekt ;-)

von (prx) A. K. (prx)


Lesenswert?

> das nach einem GCC 4.7.2 Bug aussieht.

99% aller Compiler-Fehler sitzen vor dem Bildschirm.

von Peter II (Gast)


Lesenswert?

Karsten M. schrieb:
> Wie man in dem Objektdump sehen kann werden die Subroutinen
> "check_inputs" und "print_inputs" überhaupt nicht richtig kompiliert !?

sie werden weg optimiert, der code ist doch noch vorhanden.

Wo ist denn dein Problem überhaupt?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Wo ist denn dein Problem überhaupt?

Sein Problem ist offenbar, meinen zu müssen, eine ABBRUCH-Bedingung als 
2. Statement im for() schreiben zu müssen - genau das umgekehrte ist der 
Fall.

Also:

  Statt:   i >= 2
  Korrekt: i < 2

Und:

  Statt:   i == 0
  Korrekt: i != 0

von Karsten W. (lsmod)


Lesenswert?

O.K. schon überzeugt - DAU Fehler! :-)

Kaum macht man es richtig und schon funktionierts!
Ist immer wieder erstaunlich ...

Trotzdem sieht man den Wald vor lauter Bäumen nicht.
Das schlimme ist das der Compiler sonst über jede Sinnlosigkeit meckert.
Aber bei einer sinnlosen Schleife nicht.
Dann kompiliert er frecher Weise aus sinnlosem Quellcode auch noch 
sinnlosen Output. :-)

Danke für das öffnen der geschlossenen Augen.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karsten M. schrieb:
> das nach einem GCC 4.7.2 Bug aussieht.

Das ist kein Grund, einen alten Thread auszubuddeln.

von Karsten W. (lsmod)


Lesenswert?

Jörg Wunsch schrieb:
> Das ist kein Grund, einen alten Thread auszubuddeln.

Der Titel passte perfekt - also warum nicht?

von (prx) A. K. (prx)


Lesenswert?

Karsten M. schrieb:
> Der Titel passte perfekt - also warum nicht?

Weil davon letztlich überhaupt nichts passte.

Insbesondere wenn der ursprüngliche Inhalt tatsächlich ein Bug ist (habs 
nicht gelesen), dann ist das garantiert nicht genau der, den du bei dir 
erwartest.

: Bearbeitet durch User
von Karsten W. (lsmod)


Lesenswert?

A. K. schrieb:
> Karsten M. schrieb:
>> Der Titel passte perfekt - also warum nicht?
>
> Weil davon letztlich überhaupt nichts passte.

Wie konnte ich das vorher wissen?

> Insbesondere wenn der ursprüngliche Inhalt tatsächlich ein Bug ist (habs
> nicht gelesen), dann ist das garantiert nicht genau der, den du bei dir
> erwartest.

Gutes Argument - aber ganz schön kleinlich ...

Versprochen - nächstes Mal mache ich einen neuen Thread auf.

von (prx) A. K. (prx)


Lesenswert?

Karsten M. schrieb:
> Wie konnte ich das vorher wissen?

Eben deshalb. ;-)

von Karsten W. (lsmod)


Lesenswert?

Dann lösche doch einfach alle Beiträge vom heutigen Tag.
Diese sind sowieso nicht besonders lehrreich für andere Leser.

Ausser vielleicht das man zuerst nach dem einfachsten Fehler suchen 
sollte ...

von Kaj (Gast)


Lesenswert?

Karsten M. schrieb:
> Wie konnte ich das vorher wissen?
Einfach ein C-Buch lesen...

von Karsten W. (lsmod)


Lesenswert?

Kaj schrieb:
>> Wie konnte ich das vorher wissen?
> Einfach ein C-Buch lesen...

Das hilft nicht gegen Denkfehler.
Und es schafft keine Erfahrung ...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.