mikrocontroller.net

Forum: Compiler & IDEs undefined references bei static initialization order fiasco


Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,

in meinem code bin ich wohl in das "static initialization order
fiasco"
gestolpert. ganz gemeine sache dies :( ok, ich weiß immer noch nicht
genau, warum, aber sei's erstmal drum. die lösungen dazu in der
c++-faq sehen dazu vor, eine statische variable in einer function zu
halten.

soweit so gut. nun beschwert sich aber der avr-c++ mit undefinierten
referenzen auf "__cxa_guard_acquire" bzw. "__cxa_guard_release". im
moment habe ich diese erst einmal leer definiert. ist das korrekt so?
oder muss dort etwas getan werden, wenn ja, was? falls noch zeit ist:
was bedeuten diese funktionen, im netz wird man da nicht gerade mit
info's überhäuft.

vielen dank, schönen sonntag,
bye kosmo

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist zwar sicherlich der falsche Prozessor, aber darauf kommt's nicht
an: http://www.codesourcery.com/cxx-abi/abi.html, Sektion 3.3.2.

(google groups, hit #2)

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oha.
den link habe ich nicht gefunden, sorry.
danke vielmals.

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm, das problem scheint wo anders zu liegen.

wird jetzt OT: wie legt man globale objekte in einem programm in der
bootloader-area an?
bisher habe ich immer

static Objecttype __object;

und gut ist. im normalen flash funktioniert das auch, aber seit ich in
der bootloader-area arbeite, funktioniert nichts mehr. verschieben
tue ich den ganzen code mittels --section-start=.text=0xXXXXX

hat jemand einen vorschlag und kann mir helfen? mir gehen nach mehreren
stunden leider langsam die ideen aus :(

thx!

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
einfaches beispiel:

extern "C" {
  #include <avr/io.h>
}

class A {
 public:
  A(){
  /* Set the baud rate */
  UBRR0H = (unsigned char) (51>>8);
  UBRR0L = (unsigned char) 51;
  /* Enable UART receiver and transmitter */
  UCSR0B = ( ( 1 << RXEN0 ) | ( 1 << TXEN0 ) );
  /* Set frame format: 8N1 */
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
  /* send .. something */
  while ( !(UCSR0A & (1<<UDRE0)) );
  UDR0 = 'D';
  while ( !(UCSR0A & (1<<UDRE0)) );
  UDR0 = '\r';
  }
};



mache ich

static A __a;

und in der main nichts, passiert auch nichts, die kiste hängt.

kein globales, sondern einlokales objekt in der main ala

int
main(int argc, char** args)
{
 A __a;
 return 0;
}

und es funktioniert :(

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitte benutze keine Bezeichner, die mit zwei Unterstrichen
beginnen.  Das wird zwar an deinem Problem jetzt nichts ändern,
aber diese Bezeichner sind für Compiler und Bibliothek
reserviert.

> extern "C" {
>   #include <avr/io.h>
> }

Erstens steht auch bei C++ das # immer in Spalte 1, zweitens
sollte das extern "C" nicht nötig sein.  Wenn doch, dann schreibe
bitte einen detaillierten Bugreport.  Alle avr-libc-Headerdateien
sollte mittlerweile C++-sicher sein.

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
keine zwei unterstriche, ok.
include in erster spalte, ok.

beim "extern" richte ich mich nach der avr-libc- doku. da steht zwar
drin, das wird behoben (in der art jdf.), aber gut, nun weiß ich
bescheid.

bitte den anderen thread dann einfach ignorieren, hat sich zeitlich
leider überschnitten.
bug-report mache ich nach einholen einer weiteren meinung.

danke.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> beim "extern" richte ich mich nach der avr-libc- doku. da steht
zwar
> drin, das wird behoben (in der art jdf.), aber gut, nun weiß ich
> bescheid.

Hmm, das müsste man wohl mal überarbeiten...

Bezüglich des Präprozessors:

#  include ...

ist OK.  Nur das # muss ganz vorn stehen (so will's der Standard).

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
ich habe nun das obige beispiel noch einmal vereinfacht, indem statt
usart-ausgabe verschiedene pins gestzt werden. im detail so:

#include <avr/io.h>
class A {
 public:
  A(){
    PORTE |= (1 << 7);
  }
};

A test_a;

int
main(int argc, char** args)
{
  PORTE |= (1 << 2);
  while(1);
  return 0;
}

auf Port E kann ich an dem Board nach außen geführte Pins auf High
setzen.
das problem ist unverändert. im bootloader ausgeführt, bleiben beide
Pins (durch 7 bzw. 2 angesprochen) auf null.
meine konfiguration: at90can128, fusebits auf D8, text-section
entsprechend nach 1E000 verschoben. gcc version 4.1.1.

@Jörg: was würde Dir noch für den bug-report fehlen? habe derartiges
noch nicht so oft getan.

Autor: Karsten Brandt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Joe,

ich hatte auch schon einmal ein ähnliches Problem.
Leider kann ich mich jetzt nicht mehr an die Details erinnern,
aber soweit ich weiß, war es bei mir ein Fehler im Makefile.

Wenn Du willst, kannst Du Dein Makefile mal hier reinstellen.
Vielleicht erinnere ich mich wieder an Details, wenn ich Dein Makefile
einsehe.

Karsten

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> im bootloader ausgeführt, bleiben beide
> Pins (durch 7 bzw. 2 angesprochen) auf null.

Was erst einmal nicht verwundert, da du DDRE nicht auf Ausgang
setzt. ;-)

Im Ernst: ich würde das gern mal selbst nachvollziehen.  Schreib
mir bitte nochmal die genauen Compiler-Kommandozeilen auf.
Zumindest ein kurzer Blick zeigt mir erst einmal keine
Auffälligkeiten, der statische Konstruktor ist auch im Bootloader-
Fall vorhanden.  Ob er wirklich gerufen wird, ist im Disassembler
schwer zu erkennen.

Autor: Joe Die (kosmonaut_pirx)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
jörg, mit dem DDRE hast du wie immer recht :)

anbei das Makefile, falls notwendig.

die compileraufrufe im einzelnen:

/localapp/cross-gcc/avr/bin/avr-c++ -c -mmcu=at90can128 -I. -D
GCC_MEGA_AVR -I. -I../../Source/include -I../Common/include -g -Os
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wextra -Wshadow -Wpointer-arith -Wcast-align -Wsign-compare
-Waggregate-return -Wunused -Wa,-adhlns=a_test.lst  -fno-exceptions
a_test.cpp -o a_test.o

/localapp/cross-gcc/avr/bin/avr-c++ -mmcu=at90can128 -I. -D
GCC_MEGA_AVR -I. -I../../Source/include -I../Common/include -g -Os
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wextra -Wshadow -Wpointer-arith -Wcast-align -Wsign-compare
-Waggregate-return -Wunused -Wa,-adhlns=a_test.o  -fno-exceptions
a_test.o    --output a_test.elf
-Wl,-Map=a_test.map,--cref,--section-start=.text=0x1E000

/localapp/cross-gcc/avr/bin/avr-objcopy -O ihex -R .eeprom a_test.elf
a_test.hex

das wars (das eeprom-geplapper des makefiles spare ich aus, weil nicht
gebraucht, ebenso die warnungen)

nach dem hinweis von karsten werde ich noch ein wenig mit den
compiler-options probieren.

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich kann es etwas weiter eingrenzen.

die meisten compiler-options raus
-c -mmcu=at90can128 -I. -I. -g -O0 -Wall -Wextra -Wshadow
-Wpointer-arith -Wcast-align -Wsign-compare -Waggregate-return -Wunused
 -fno-exceptions  a_test.cpp -o a_test.o

den linker nur noch
-Wl,-Map=a_test.map,--cref,--section-start=.text=0x1F000
tun und ende.

wie schon zu sehen, auch mal eine andere bootloader-size ausprobiert,
man weiß ja nie.

und im Konstruktor der globalen Klasse eine while-true angefügt, um ein
mögliches reset und löschen der Pins zu verhindern.

leider alles ohne veränderung bisher.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das via Simulation und Einzelschritt mal runterbrechen
können.

Das Problem ist im GCC bzw. in dessen libgcc.S.  Damit kannst du
den Bugreport für den GCC schreiben (http://gcc.gnu.org/ , dort
zum Bugzilla weitergehen).  Ich würde dir empfehlen, dich bei
avr-gcc-list at nongnu.org anzumelden und das dort ebenfalls noch
einmal zum Besten zu geben.  Wir haben jetzt ja fast einen C++-
Maintainer ;-), Rolf Magnus (auch hier gelegentlich aktiv) wollte
sich dieser Dinge annehmen.

Folgendes Stück aus libgcc.S wird zum Verhängnis (du darfst das
im Bugreport zitieren):

#ifdef L_ctors
        .section .init6,"ax",@progbits
        .global __do_global_ctors
__do_global_ctors:
        ldi     r17, hi8(__ctors_start)
        ldi     r28, lo8(__ctors_end)
        ldi     r29, hi8(__ctors_end)
        rjmp    .do_global_ctors_start
.do_global_ctors_loop:
        sbiw    r28, 2
        mov_h   r31, r29
        mov_l   r30, r28
        XCALL   _tablejump_
.do_global_ctors_start:
        cpi     r28, lo8(__ctors_start)
        cpc     r29, r17
        brne    .do_global_ctors_loop
#endif /* L_ctors */

Die Initialisierung von r28/r29 funktioniert nur für Daten, die
sich unterhalb 64 KiB befinden, da der 16 bits überschreitende
Teil der Adressen (__ctors_start, __ctors_end) nicht beachtet
wird.  Damit werden r30/r31 nicht mit den eigentlichen Daten
für den Konstruktor geladen sondern mit Daten, die 64 KiB weiter
unten stehen, also letztlich mit 0xffff.  Der Code bei
_tablejump_ springt dann die Adresse an, die von dieser Stelle
geladen wird...  Damit ist das Fiasko komplett.

Fazit: C++ im Bootloader ist derzeit nur für AVRs <= 64 KiB ROM
möglich, wenn statische Konstruktoren oder Destruktoren im Spiel
sind.

Autor: Joe Die (kosmonaut_pirx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, das werde ich machen.

Vielen Dank!

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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