Forum: Compiler & IDEs WinAVR bekannter Linker Fehler?


von Ingo S. (ingo-s)


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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Es ist die gleiche Variable in diesem Falle.

Schau dir das C-Schlüselwort static an.

von Ingo S. (ingo-s)


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

von Stefan E. (sternst)


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.

von 900ss (900ss)


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.

von Stefan E. (sternst)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

von Ingo S. (ingo-s)


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

von 900ss (900ss)


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.

von Karl H. (kbuchegg)


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.

von Peter D. (peda)


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

von Jürgen L. (Gast)


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.

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


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

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


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.

von Karl H. (kbuchegg)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


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
1
/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
2
 static const struct default_options avr_option_optimization_table[] =
3
 {
4
   { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
5
+  { OPT_LEVELS_ALL, OPT_fcommon, NULL, 1 },
6
   { OPT_LEVELS_NONE, 0, NULL, 0 }
7
 };

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.

von Uhu U. (uhu)


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.

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.