mikrocontroller.net

Forum: Compiler & IDEs WinAVR bekannter Linker Fehler?


Autor: Ingo Stahl (ingo-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

wie ich beim debuggen feststellen musste packt der Linker Variablen, die 
in getrennten Modulen liegen (nur Modul intern) zu einer Variablen 
zusammen wenn sie den gleichen Namen haben.

Auszug der Deklarationen:

in Main.c
volatile uint16_t impwidth_limit;

in impuls.c
volatile uint16_t impwidth_limit  _attribute_ ((section (".noinit")));

wenn man bei einer der beiden Variablen den Namen ändert sieht man bei 
der Angabe des belegten RAM's sofort, das unterschiedliche Namen zu 
2byte Mehrbelegung führen.
Ich habe jetzt nicht ausprobiert, ob das nur in Verbindung mit ".noinit" 
passiert.

Gruß Ingo

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist die gleiche Variable in diesem Falle.

Schau dir das C-Schlüselwort static an.

Autor: Ingo Stahl (ingo-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

das verstehe ich nicht, denn das würde ja heißen, das man alle Variablen 
in Modulen als static deklarieren müsste, selbst wenn sie nicht 
exportiert werden um bei zufälligen gleichen Variablen Namen in anderen 
Modulen diesen Effekt zu verhindern.
Sollte das in "C" oder gcc wirklich so gewollt sein, da doch die export 
Funktion ausreichend sein sollte.

Gruß Ingo

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wovon redest du? Es gibt in C kein explizites "export".

Wenn du kein static davor setzt, ist es eine globale (modulübergreifend) 
Variable, wird also quasi automatisch exportiert.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ingo Stahl schrieb:
> Hi,
>
> das verstehe ich nicht, denn das würde ja heißen, das man alle Variablen
> in Modulen als static deklarieren müsste, selbst wenn sie nicht
> exportiert werden um bei zufälligen gleichen Variablen Namen in anderen
> Modulen diesen Effekt zu verhindern.

Ja, so ist es.

> Sollte das in "C" oder gcc wirklich so gewollt sein, da doch die export
> Funktion ausreichend sein sollte.

Das hat nichts mit GCC zu tun. Das ist in der Sprache 'C' so definiert. 
Eine Funktion oder Schlüsselwort 'export' gibt es in 'C' erstmal nicht. 
Da haben manche Leute ein '#define export extern' gebaut. So wird 
'export' häufig verwendet.
Ich persönlich finde es sehr unglücklich da es verwirrt, wie sich hier 
gerade zeigt.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
900ss D. schrieb:
> Da haben manche Leute ein '#define export extern' gebaut. So wird
> 'export' häufig verwendet.
> Ich persönlich finde es sehr unglücklich da es verwirrt, wie sich hier
> gerade zeigt.

Außerdem ist das doch auch von der Bedeutung her völlig verquer. Ein 
'#define import extern' wäre da ja schon sinnvoller.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genaugenommen kommt hier noch eine lästige GCC-Gewohnheit zum Tragen: 
Werden in zwei Modulen nichtstatische Variablen gleichen Namens 
angelegt, so gibt der Linker keine Fehlermeldung aus, sondern fasst 
alle doppelt definierten Symbole zusammen.
Andere Linker machen das nicht und geben entsprechende Fehlermeldungen 
aus. Dem GCC lässt sich dieses Verhalten mit -fno-common auch 
abgewöhnen.

Autor: Ingo Stahl (ingo-s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

danke für die Antworten.

Es ist also ein Feature, das ich mir Merken muss um nicht noch einmal 
darauf reinzufallen.

Mit export meinte ich übrigens das "extern" Schlüsselwort, da ich das 
mit exportieren einer Variablen nach außen verinnerlicht habe. Daher 
habe ich das "static" als "Ausfuhrstop" wohl nicht mehr im Sinn gehabt.

Gruß Ingo

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. Firefly schrieb:
> so gibt der Linker keine Fehlermeldung aus

Wie? Da bin ich bisher nicht drüber gestolpert. Das ist schon ziemlich 
dumm. Da sucht man sich ja tot, wenn einem das passiert.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ingo Stahl schrieb:

> mit exportieren einer Variablen nach außen verinnerlicht habe. Daher
> habe ich das "static" als "Ausfuhrstop" wohl nicht mehr im Sinn gehabt.

Du sollst sogar static verwenden, wo du nur kannst.
Denn surch static baust du eine Barriere rund um deine Compilation Unit 
auf. Du sagst dem Compiler explizit: Diese Variable oder diese Funktion 
KANN nicht von ausserhalb referenziert werden. Sie ist ausserhalb nicht 
sichtbar.
Das wiederrum ermöglicht dem Compiler so manche Optimierung, bis hin zu: 
Funktionen können geinlined werden, ohne dass ein klassische aufrufbare 
Implementierung der Funktion existieren muss.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist mir auch schon aufgefallen, daß der GCC stillschweigend 
Mehrfachdefinitionen als eine Variable zusammenfast.

Der Keil C51, zeigt mir bei sowas sofort die rote Karte.

Wenn -fno-common diesen Fehler behebt, sollte man das als default in 
jedes Make mit aufnehmen.


Peter

Autor: Jürgen L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zum Nachlesen hier die Info aus der GCC Doku:
-fno-common
In C code, controls the placement of uninitialized global variables. 
Unix C compilers have traditionally permitted multiple definitions of 
such variables in different compilation units by placing the variables 
in a common block. This is the behavior specified by -fcommon, and is 
the default for GCC on most targets. On the other hand, this behavior is 
not required by ISO C, and on some targets may carry a speed or code 
size penalty on variable references. The -fno-common option specifies 
that the compiler should place uninitialized global variables in the 
data section of the object file, rather than generating them as common 
blocks. This has the effect that if the same variable is declared 
(without extern) in two different compilations, you will get a 
multiple-definition error when you link them. In this case, you must 
compile with -fcommon instead. Compiling with -fno-common is useful on 
targets for which it provides better performance, or if you wish to 
verify that the program will work on other systems which always treat 
uninitialized variable declarations this way.

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

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Ist mir auch schon aufgefallen, daß der GCC stillschweigend
> Mehrfachdefinitionen als eine Variable zusammenfast.

Historisches Unix-Compiler-Verhalten, ist durch den Standard explizit
gedeckt (als eine Möglichkeit).

Meine Vermutung ist, dass das "Ur-C" das Schlüsselwort "extern" noch
nicht kannte.  Durch die Implementierung globaler Variablen als ein
common block (FORTRAN lässt grüßen ;-) konnte man dann den gleichen
Effekt erreichen.

Das "static" nicht das default-Verhalten einer Deklaration/Definition
ist, ist eigentlich ein Designfehler von C.  Kann man aber nicht mehr
beheben, ohne dass die gesamte C-Welt zusammenbrechen würde.  Man kann
sich nur angewöhnen, prinzipiell überall "static" davor zu schreiben.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Historisches Unix-Compiler-Verhalten, ist durch den Standard explizit
> gedeckt (als eine Möglichkeit).

Mag ja sein. Aber es spricht nichts dagegen, die Möglichkeit nur auf 
Wunsch und nicht per Default zu aktivieren, denn sie verschleiert 
Programmierfehler, wie die Definition von globalen Variablen in 
Headerdateien.

Zumal diejenigen, die gccavr verwenden, das ziemlich sicher nicht tun, 
um irgendwelche alten K&R-C-Fragmente aus alten Unix-Zeiten zu 
übersetzen.

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

Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. Firefly schrieb:

> Mag ja sein. Aber es spricht nichts dagegen, die Möglichkeit nur auf
> Wunsch und nicht per Default zu aktivieren, denn sie verschleiert
> Programmierfehler, wie die Definition von globalen Variablen in
> Headerdateien.

Vermutlich muss man nur eine Konfigurationsanweisung umschalten
irgendwo in den Untiefen der AVR-Anpassung.  Zumindest suggeriert
die Doku ja, dass es Plattformen gibt, auf denen -fno-common die
Voreinstellung ist.

Da auf dem AVR dem -fcommon als Default sicher keiner hinterher weinen
wird, bliebe es also nur, diese Stelle zu finden und einen Bugreport
mitsamt Patch zu schreiben und den dann auch durchzuboxen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weiß man eigentlich, wo im AVR-Studio die Projekt-Default Einstellung 
abgelegt ist?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:

> Vermutlich muss man nur eine Konfigurationsanweisung umschalten
> irgendwo in den Untiefen der AVR-Anpassung.  Zumindest suggeriert
> die Doku ja, dass es Plattformen gibt, auf denen -fno-common die
> Voreinstellung ist.
>
> Da auf dem AVR dem -fcommon als Default sicher keiner hinterher weinen
> wird, bliebe es also nur, diese Stelle zu finden und einen Bugreport
> mitsamt Patch zu schreiben und den dann auch durchzuboxen.

In ./gcc/config/avr/avr.c
/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
 static const struct default_options avr_option_optimization_table[] =
 {
   { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+  { OPT_LEVELS_ALL, OPT_fcommon, NULL, 1 },
   { OPT_LEVELS_NONE, 0, NULL, 0 }
 }; 

Falls fcommon anders abgehandelt wird (keine implizited Erzeugen von 
OPT_fcommon), funktioniert auf jeden Fall in Target Hook 
TARGET_OPTIMIZATION_OPTIONS flag_no_common = 1 zu setzen, ebenfalls in 
avr.c.

Bei beiden Möglichkeiten hat dann ein -fcommon auf Kommandozeile höhere 
Priorität und überschreibt den Default.

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn ich mit meiner Bemerkung etwas nacheile:

Common Blocks sind durchaus eine recht brauchbare Einrichtung, wenn man 
z.B. mehrere unabhängige Programm-Module hat, die zur Übersetzungszeit 
die Größe eines gemeinsamen Puffers festlegen sollen.

Man definiert einfach in jedem Modul den Puffer mit der notwendigen 
Größe. Der Linker kombiniert dann alle Versionen zu einer Variablen mit 
der maximalen Größe.

Dieser Trick ist vor allem in hierarchisch aufgebauten Libs sehr 
praktisch.

Dem Problem mit unerwünschten Variablen-Kolisionen im Commonblock 
begegnet man am besten dadurch, daß man öffentlichen Variablen einen 
Modulspezifischen Präfix verpaßt - so haben das schon die Altvorderen im 
Assemblerzeitalter auch gemacht.

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.