mikrocontroller.net

Forum: Compiler & IDEs Compilerfehler in avr-gcc 4.8.2?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Uhu U. (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Quellcode:
#define SWAPB(x)    (x)

void initWatchdog(uint8_t timeout) {
    uint8_t sreg = SREG;
    cli();

    if (mcusr & (1 << PORF))                  // on power on reset
        WdtTrapAddress = 0;

    // scan wdt isr for return address offset
    const uint16_t __flash *pushPtr = (const uint16_t __flash *)
       (*((const uint16_t __flash *) 0x1a) << 1) + 5;
    uint16_t code;

    isrStackOffset = 3;
    code = SWAPB(*pushPtr);
    while (0x0f92u == (code & 0x0ffeu)) {
        pushPtr++;
        code = SWAPB(*pushPtr);
        isrStackOffset++;
    }

    wdt_enable(timeout);
    WDTCSR |= (1 << WDIE);              // Enable WDT interrupt

    SREG = sreg;
}

Der daraus erzeugte asm-Code:
void initWatchdog(uint8_t timeout) {
    uint8_t sreg = SREG;
    176e:  6f b7         in  r22, 0x3f  ; 63
    cli();
    1770:  f8 94         cli

    if (mcusr & (1 << PORF))                             // on power on reset
    1772:  90 91 f5 01   lds  r25, 0x01F5
    1776:  90 ff         sbrs  r25, 0
    1778:  04 c0         rjmp  .+8        ; 0x1782 <initWatchdog+0x14>
        WdtTrapAddress = 0;
    177a:  10 92 f7 01   sts  0x01F7, r1
    177e:  10 92 f6 01   sts  0x01F6, r1

    // scan wdt isr for return address offset
    const uint16_t __flash *pushPtr = (const uint16_t __flash *) 
        (*((const uint16_t __flash *) 0x1a) << 1) + 5;
    1782:  ea e1         ldi  r30, 0x1A  ; 26
    1784:  f0 e0         ldi  r31, 0x00  ; 0
    1786:  25 91         lpm  r18, Z+
    1788:  35 91         lpm  r19, Z+
    178a:  22 0f         add  r18, r18
    178c:  33 1f         adc  r19, r19
    uint16_t code;

    isrStackOffset = 3;
    code = SWAPB(*pushPtr);
    178e:  f9 01         movw  r30, r18
    1790:  3a 96         adiw  r30, 0x0a  ; 10
#1  1792:  45 91         lpm  r20, Z+
#1  1794:  55 91         lpm  r21, Z+
    1796:  54 27         eor  r21, r20
    1798:  45 27         eor  r20, r21
    179a:  54 27         eor  r21, r20
    179c:  f9 01         movw  r30, r18
    179e:  3c 96         adiw  r30, 0x0c  ; 12
    while (0x0f92u == (code & 0x0ffeu)) {
    17a0:  93 e0         ldi  r25, 0x03  ; 3
    17a2:  21 e0         ldi  r18, 0x01  ; 1
    17a4:  29 0f         add  r18, r25
    17a6:  4e 7f         andi  r20, 0xFE  ; 254
    17a8:  5f 70         andi  r21, 0x0F  ; 15
    17aa:  42 39         cpi  r20, 0x92  ; 146
    17ac:  5f 40         sbci  r21, 0x0F  ; 15
    17ae:  39 f4         brne  .+14       ; 0x17be <initWatchdog+0x50>
        pushPtr++;
        code = SWAPB(*pushPtr);
#2  17b0:  41 91         ld  r20, Z+
#2  17b2:  51 91         ld  r21, Z+
    17b4:  54 27         eor  r21, r20
    17b6:  45 27         eor  r20, r21
    17b8:  54 27         eor  r21, r20
    17ba:  92 2f         mov  r25, r18
    17bc:  f2 cf         rjmp  .-28       ; 0x17a2 <initWatchdog+0x34>
    17be:  90 93 f4 01   sts  0x01F4, r25
        isrStackOffset++;
    }

    wdt_enable(timeout);
    17c2:  83 ff         sbrs  r24, 3
    17c4:  02 c0         rjmp  .+4        ; 0x17ca <initWatchdog+0x5c>
    17c6:  98 e2         ldi  r25, 0x28  ; 40
    17c8:  01 c0         rjmp  .+2        ; 0x17cc <initWatchdog+0x5e>
    17ca:  98 e0         ldi  r25, 0x08  ; 8
    17cc:  87 70         andi  r24, 0x07  ; 7
    17ce:  89 2b         or  r24, r25
    17d0:  28 e1         ldi  r18, 0x18  ; 24
    17d2:  30 e0         ldi  r19, 0x00  ; 0
    17d4:  0f b6         in  r0, 0x3f  ; 63
    17d6:  f8 94         cli
    17d8:  a8 95         wdr
    17da:  20 93 60 00   sts  0x0060, r18
    17de:  0f be         out  0x3f, r0  ; 63
    17e0:  80 93 60 00   sts  0x0060, r24
    WDTCSR |= (1 << WDIE);                              // Enable WDT interrupt
    17e4:  80 91 60 00   lds  r24, 0x0060
    17e8:  80 64         ori  r24, 0x40  ; 64
    17ea:  80 93 60 00   sts  0x0060, r24

    SREG = sreg;
    17ee:  6f bf         out  0x3f, r22  ; 63
    17f0:  08 95         ret
}

Bei Adresse 1792 (Markierung #1) wird *pushPtr korrekt per lpm geladen.

In der While-Schleife auf Adresse 17b0 (Markierung #2) wird der nächste 
code geladen - diesmal nicht per lpm sondern mit ld. Der Compiler hat 
also den Modifier __flash am pushPtr verloren und liest jetzt aus dem 
RAM.


Wenn ich die Deklaration für pushPtr ändere in
const __flash uint16_t *pushPtr = 

verschwinden die 3 seltsamen eor ab Adressen 1796 und 17b4. Am 
Ladefehler in der while-Schleife ändert sich nichts.

: Bearbeitet durch User
Beitrag #5707726 wurde vom Autor gelöscht.
Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ändere testweise die Initialisierung so, dass dem Compiler nichts über 
die Flash-Adresse bekannt ist, auch kein Wertebereich, und kein Cast 
darin vorkommt. Beispielsweise per Parameter von ebendiesem Typ. Es geht 
dabei nur um den erzeugten Code, das Programm muss nicht funktionieren.

Die 3 EORs sind ein Byte-Swap. Du bist ganz sicher, dass der 
präsentierte Quellcode und der Asm-Code zusammen gehören?

: Bearbeitet durch User
Autor: Uhu U. (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meinst du so:
const __flash uint16_t *pushPtr = (*((const uint16_t *) 0x1a) << 1) + 5;

Das gibt eine Warnung, aber an dem vermurksten Code ändert sich nichts. 
(Außer die eor sind weg - aber das hatte ich oben schon angemerkt.)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
typedef ... ptr_t;
void initWatchdog(uint8_t timeout, ptr_t init_p) {
    ...
    ptr_t pushPtr = init_p;
    ...

Aber bitte so, dass der Compiler den Aufruf der Funktion nicht sieht.

Schau jedoch erst einmal, ob das SWAPB genau das ist oder war, was du 
oben reingeschrieben hast. Notfalls im Preprocessor-Output. Ich tippe 
drauf, dass die EORs etwas mit SWAPB zu tun hatten.

: Bearbeitet durch User
Autor: Uhu U. (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Aber schau erst einmal, ob das SWAPB genau das ist, was du oben
> reingeschrieben hast. Notfalls im Preprocessor-Output.

Das SWAPB habe ich wegdefiniert:

//#define SWAPB(x)    (uint16_t) (0xffffu & ((((x) & 0xff00u) >> 8) | (((x) & 0xffu) << 8)))
#define SWAPB(x)    (x)

void initWatchdog(uint8_t timeout) {
    uint8_t sreg = SREG;
    cli();

    if (mcusr & (1 << PORF))                             // on power on reset
        WdtTrapAddress = 0;

    // scan wdt isr for return address offset
    //const __flash uint16_t *pushPtr = (const __flash uint16_t *) (*((const __flash uint16_t *) 0x1a) << 1) + 5;
    const __flash uint16_t *pushPtr = 0x1a;
    uint16_t code;

    isrStackOffset = 3;
    code = SWAPB(*pushPtr);
    while (0x0f92u == (code & 0x0ffeu)) {
        pushPtr++;
        code = SWAPB(*pushPtr);
        isrStackOffset++;
    }

    wdt_enable(timeout);
    WDTCSR |= (1 << WDIE);                              // Enable WDT interrupt

    SREG = sreg;
}

Die Initialisierung für pushPtr mit 0x1a ändert auch nichts.

A. K. schrieb:
> Die 3 EORs sind ein Byte-Swap. Du bist ganz sicher, dass der
> präsentierte Quellcode und der Asm-Code zusammen gehören?

Die eor kommen vom SWAPB in der ursprünglichen Definition - etwas 
umständlich, wenn man einfach nur die Register beim Laden vertauschen 
müsste…

: Bearbeitet durch User
Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Ändere testweise die Initialisierung so, dass dem Compiler nichts über
> die Flash-Adresse bekannt ist,

Uhu U. schrieb:
> const __flash uint16_t *pushPtr = 0x1a;

Hier kennt der Compiler die Adresse.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Uhu U. schrieb:
> Die eor kommen vom SWAPB in der ursprünglichen Definition - etwas
> umständlich, wenn man einfach nur die Register beim Laden vertauschen
> müsste…

Die beiden Ladebefehle bilden eine Einheit bei der Umsetzung der 16-Bit 
Operation auf die 8-Bit Maschine.

Autor: Uhu U. (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> typedef ... ptr_t;
> void initWatchdog(uint8_t timeout, ptr_t init_p) {
>     ...
>     ptr_t pushPtr = init_p;
>     ...
>
> Aber bitte so, dass der Compiler den Aufruf der Funktion nicht sieht.

Der Aufruf steht in einem anderen Quellfile.

Wenn man es so macht, wie du vorgeschlagen hast, ist der Fehler weg (mit 
wegdefiniertem SWAPB):
    code = SWAPB(*pushPtr);
    1782:  fb 01         movw  r30, r22
    1784:  25 91         lpm  r18, Z+
    1786:  35 91         lpm  r19, Z+
    while (0x0f92u == (code & 0x0ffeu)) {
    1788:  93 e0         ldi  r25, 0x03  ; 3
    178a:  51 e0         ldi  r21, 0x01  ; 1
    178c:  59 0f         add  r21, r25
    178e:  2e 7f         andi  r18, 0xFE  ; 254
    1790:  3f 70         andi  r19, 0x0F  ; 15
    1792:  22 39         cpi  r18, 0x92  ; 146
    1794:  3f 40         sbci  r19, 0x0F  ; 15
    1796:  21 f4         brne  .+8        ; 0x17a0 <initWatchdog+0x32>
        pushPtr++;
        code = SWAPB(*pushPtr);
    1798:  25 91         lpm  r18, Z+
    179a:  35 91         lpm  r19, Z+
    179c:  95 2f         mov  r25, r21
    179e:  f5 cf         rjmp  .-22       ; 0x178a <initWatchdog+0x1c>
    17a0:  90 93 f4 01   sts  0x01F4, r25
        isrStackOffset++;
    }

: Bearbeitet durch User
Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Uhu U. schrieb:
> Der Quellcode:

Wozu soll dieser Code denn gut sein?

Wofür auch immer, mit neueren Compilerversionen wird er nicht mehr 
funktionieren.

Falls in der ISR kein Frame gebraucht wird, dann kann die Anzahl der 
PUSHes im Prolog ganz einfach und unabhängig von der Compilerversion 
erhalten werden, zum Beispiel:
#include <avr/interrupt.h>

uint8_t isrStackOffset;

ISR (__vector_1)
{
    __asm ("ldi %0, .L__stack_usage" : "=d" (isrStackOffset));
}

Falls der Wert in einer anderen Funktion als der ISR benötigt wird, dann 
ist es etwas komplizierter und hässlicher, aber immer noch portabel 
zwischen unterschiedlichen Versionen von avr-gcc machbar:
// !!!
// !!! Muss mit -fno-toplevel-reorder compiliert werden
// !!! und unmittelbar auf die ISR folgen!
// !!!

extern const uint8_t n_pushed;

__asm (".global n_pushed"                           "\n\t"
       ".section .rodata.n_pushed,\"a\",@progbits"  "\n"
"n_pushed:"                                         "\n\t"
       ".byte .L__stack_usage");

Auch die return-Adresse einer Funktion kann man bekommen, und zwar mit 
__builtin_return_address(0).

http://gcc.gnu.org/onlinedocs/gcc/Return-Address.html

An die Speicheradresse der return-Adresse auf dem Stack kommt man aber 
leider nicht per Built-in heran.

Was v4.8 angeht, die ist ja schon was älter — ob es da ein Problem mit 
Address-Spaces gab weiß ich jetzt nicht mehr.  Auf die Schnelle find ich 
zumindets kein passenden PR.  Ne neuere Version wäre jedenfalls kein 
Luxus.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.