Forum: Compiler & IDEs linker: symbol referencing errors


von Christian (Gast)


Lesenswert?

Hallo,

ich versuche ein c++-Projekt, das für den TI F240 geschrieben wurde,
für meinen neuen DSP TI F2812 zu konvertieren. Nach dem Durchführen der
nötigen Änderungen, habe ich nun Probleme mit dem Linker des TI Code
Composers v2.12. Wenn ich beim Kompilieren die build option
"preprocessing: preprocessing only (-ppo)" einstelle, erhalte ich die
Fehlermeldung:

[Linking...] "C:\ti\c2000\cgtools\bin\cl2000" -@"Release.lkf"

undefined                        first referenced
 symbol                              in file
---------                        ----------------
_main
C:\ti\c2000\cgtools\lib\rts2800_ml.lib
>>   error: symbol referencing errors -
'./Release/mainapplication.out' not
            built

Wenn ich preprocessing auf none stelle, erhalte ich Fehler vom Typ:

[Linking...] "C:\ti\c2000\cgtools\bin\cl2000" -@"Release.lkf"
>>   error: symbol _tx_buffer_in is defined multiple times:
            C:\ti\Labs\Release\scheduler.obj and
            C:\ti\Labs\Release\uart.obj

Warum der Fehler des mehrfachen Definierens auftritt, kann ich nicht
nachvollziehen, da jede header-Datei das ifndef-Konstrukt nach dem
Muster :

#ifndef SCHEDULER_H
#define SCHEDULER_H
[snip]
#endif

enthält.
Es scheint, dass der Compiler Probleme mit der Verarbeitung des
Preporcessing hat.

Hat jemand eine Idee, wie ich das Problem in den Griff bekomme?

Vielen Dank

Christian

von Rufus T. Firefly (Gast)


Lesenswert?

Die erste Fehlermeldung ist doch recht eindeutig: Der Linker versucht
den Startupcode mit der Funktion main zu linken - und die scheint in
Deinem Projekt zu fehlen ...

Das zweite Problem hat wohl damit zu tun, daß Du tx_buffer in der
Headerdatei definierst (und nicht deklarierst) und die sowohl von
scheduler.c(pp) und uart.c(pp) eingebunden werden.

Damit ist ein auf linkage-Ebene sichtbares Symbol doppelt definiert.

Eine Möglichkeit wäre es, tx_buffer static zu deklarieren (dann kann
das Teil nur innerhalb des jeweiligen Moduls angefasst werden) oder
aber, wenn das eine globale Variable sein soll, die von mehreren
Modulen manipuliert werden soll, deren Deklaration in Ordnung zu
bringen.
In der Headerdatei sollte dann ein "extern" vor der Deklaration
stehen, die Definition gehört in ein (und nur ein) Sourcefile.

Mehr kann ich, ohne Deinen Quelltext zu sehen, dazu nicht sagen.

von Christian (Gast)


Lesenswert?

Vielen Dank für Deine Antwort.

Zu meinem ersten Problem:
Das Projekt enthält eine Datei namens main.c, die in das Projekt
eingebunden ist. Darin ist auch eine Funktion zu finden:
void main()
{ [snip] }

Meiner Meinunng nach sollte das alles stimmen. Oder habe ich hier was
übersehen bzw. nicht beachtet?

Zum zweiten Problem:
Bisher sah in der uart.h die Deklaration folgendermaßen aus:
volatile char  tx_buffer_in;
Durch das Hinzufügen des "extern" konnten die Fehler beseitigt
werden. Vielen Dank für den Tipp ;)
Verstehe ich das richtig, dass durch das "extern" ein sog. "external
linkage" erfolgt, also die auf diese Weise definierten
Variablen/Funktionen auch von anderen Dateien beim Linken gelesen
werden können?

Die oben genannten Fehler scheinen behoben zu sein. Der Linker schmeißt
jetz aber folgende Meldung raus:

[Linking...] "C:\ti\c2000\cgtools\bin\cl2000" -@"Debug.lkf"
>>   error: can't allocate .text (sz: 00002868 page: 0) in PROG
(avail: 00001d72)
>>   error: errors in input - ./Debug/mainapplication.out not built

Die cmd-Datei sieht folgendermassen aus:

MEMORY
{
   PAGE 0 : BOOT(R)     : origin = 0x3f8000, length = 0x80
   PAGE 0 : PROG(R)     : origin = 0x3f8080, length = 0x1f80
   PAGE 0 : RESET(R)    : origin = 0x3fffc0, length = 0x2

   PAGE 1 : M0RAM(RW)   : origin = 0x000000, length = 0x400
   PAGE 1 : M1RAM(RW)   : origin = 0x000400, length = 0x400
   PAGE 1 : L0L1RAM(RW) : origin = 0x008000, length = 0x2000
}

SECTIONS
{
   /* 22-bit program sections */
   .reset   : > RESET, PAGE = 0, TYPE = DSECT
   .pinit   : > PROG,  PAGE = 0
   .cinit   : > PROG,  PAGE = 0
   .text    : > PROG,  PAGE = 0

   /* 16-Bit data sections */
   .const   : > M0RAM, PAGE = 1
   .bss     : > M1RAM, PAGE = 1
   .stack   : > M1RAM, PAGE = 1
   .sysmem  : > M0RAM, PAGE = 1

   /* 32-bit data sections */
   .ebss    : > L0L1RAM, PAGE = 1
   .econst  : > L0L1RAM, PAGE = 1
   .esysmem : > L0L1RAM, PAGE = 1

   .boot > BOOT
   {
      -lrts2800_ml.lib<boot.obj> (.text)
   }
}

Ich werde selbst bei google versuchen, eine Lösung zu finden. Für
Lösungvorschläge wäre ich trotzdem dankbar.

Gruß
Christian

von Rufus T. Firefly (Gast)


Lesenswert?

Du hast

  volatile char  tx_buffer_in;

Das darf so nicht in einer Headerdatei stehen. Damit wird nämlich bei
jedem Einbinden in ein Sourcefile (#include) erneut der für diese
Variable erforderliche Speicher reserviert und auf Linker-ebene ein
Symbol dafür angelegt.
In Headerdateien sollte man Variablen nur deklarieren, nicht
definieren.

Deklaration:

  extern volatile char tx_buffer_in;

Die Definition (die letzlich den Speicher reserviert)

  volatile char tx_buffer_in;

gehört in genau ein Sourcefile *.c(pp).

Das kann man auch mit Funktionsprototypen vergleichen; die Deklaration
einer Funktion sagt nur, daß es eine Funktion dieses Namens gibt, so
daß der Compiler syntaktisch mit Aufrufen klarkommt, während die
Definition die Implementierung der Funktion ist.

Diese Konstruktion ist nur bei globalen Variablen erforderlich, also
bei Variablen, die modulübergreifend verwendet werden. Sowas ist nicht
ganz ohne Grund verpönt, da es eigenwillige Nebeneffekte hervorrufen
kann und die Fehlersuche und Wartung erschwert.


  [Linking...] "C:\ti\c2000\cgtools\bin\cl2000" -@"Debug.lkf"
  >>   error: can't allocate .text (sz: 00002868 page: 0) in PROG
  (avail: 00001d72)

Diese Meldung bedeutet, daß der Speicherplatz für globale und statische
Variablen nicht ausreicht - Dein Programm definiert 0x2868 Bytes
Variablen, es stehen aber nur 0x1d72 Bytes zur Verfügung.
Zu globalen und statischen Variablen zählen auch Stringkonstanten etc.
Je nach verwendetem Compiler (und Prozessor) besteht die Möglichkeit,
Stringkonstanten und const-Variablen im ROM abzulegen, auf welche Art
und Weise dies geschieht, wird sicherlich irgendwo in der Dokumentation
beschrieben sein. Beim AVR ist das aufgrund der Harvard-Architektur
(getrennte Adressräume für Programm und Daten) ziemlich kompliziert und
ein in diesem Forum häufiger auftretendes Problem.

Du wirst Dein Programm nach allen Variablen und Stringkonstanten
durchforsten müssen. Eventuell bietet Dein Compiler auch die Option,
modulweise eine Übersicht über den Speicherbedarf auszugeben.

Viel Glück.

von Christian (Gast)


Lesenswert?

Vielen Dank für die sehr hilfreichen Tipps.
Ich werde mich in den nächsten Tagen mit dem Problem in der
cmd-Datei befassen und komme ggf. nochmals auf Deine Hilfe zurück.

Noch einmal vielen Dank, Du hast mir wirklich weitergeholfen.

Schönen Gruß
Christian

von Christian (Gast)


Lesenswert?

Hallo,

leider habe ich immer noch Probleme, die cmd-Datei anzupassen. Diese
sieht folgendermassen aus:

MEMORY
{
   PAGE 0 : BOOT(R)     : origin = 0x3f8000, length = 0x80
   PAGE 0 : PROG(R)     : origin = 0x3f8080, length = 0x3ff0
/*0x3f00*/
   PAGE 0 : RESET(R)    : origin = 0x3ffc00, length = 0x2

   PAGE 1 : M0RAM(RW)   : origin = 0x000000, length = 0x400
   PAGE 1 : M1RAM(RW)   : origin = 0x000400, length = 0x400
   PAGE 1 : L0L1RAM(RW) : origin = 0x008000, length = 0x2000
}

SECTIONS
{
   /* 22-bit program sections */
   .reset   : > RESET, PAGE = 0, TYPE = DSECT
   .pinit   : > PROG,  PAGE = 0
   .cinit   : > PROG,  PAGE = 0
   .text    : > PROG,  PAGE = 0

   /* 16-Bit data sections */
   .const   : > M0RAM, PAGE = 1
   .bss     : > M1RAM, PAGE = 1
   .stack   : > M1RAM, PAGE = 1
   /*.sysmem  : > M0RAM, PAGE = 1*/
   .sysmem  : > L0L1RAM, PAGE = 1

   /* 32-bit data sections */
   .ebss    : > L0L1RAM, PAGE = 1
   .econst  : > L0L1RAM, PAGE = 1
   .esysmem : > L0L1RAM, PAGE = 1

   .boot > BOOT
   {
      -lrts2800_ml.lib<boot.obj> (.text)
   }
}

Ich kann mein Projekt jetzt erfolgreich compilieren und linken, bekomme
aber beim Laden der out-Datei auf den DSP folgende Meldung:
".text 800 of 21270 at 0x3f82ad" und eine Meldng, dass versucht wird,
auf einen nicht schreibbaren Speicherbereich zu schreiben.

In der Doku von TI http://focus.ti.com/lit/ds/symlink/tms320f2812.pdf
findet man auf Seite 29 die memory map des DSPs.
Laut meiner cmd-Datei versuche ich ja auf den Speicherbereich von H0
SARAM zuzugreifen und kann nicht nachvollziehen, warum es dabei zu
Problemen kommt, da ich IMHO genügend Speicher freigebe.
Wenn ich versuche den ".text"-Teil in einen anderen Teil, wie L0-,
L1- oder den M0-1-SARAM zu packen, meckert der Linker, dass die
Zuordnung ungültig ist. Ist es also nur möglich, den test-Teil ins H0
SARAM zu legen?

Vielen Dank für Eure Antworten.
Gruß
Christian

von Rufus T. Firefly (Gast)


Lesenswert?

Da muss ich passen; habe keinen blassen Schimmer davon, da ich den DSP
nicht kenne.

Allerdings kommt mir die Zeile

  .text    : > PROG,  PAGE = 0

trotzdem seltsam vor; das .text-Segment muss im RAM liegen; bei PROG
muss ich an ROM denken ...

  "Laut meiner cmd-Datei versuche ich ja auf den Speicherbereich
  von H0 SARAM zuzugreifen ..."

Entweder ich bin blind, verstehe es nicht oder Du machst mit oben
zitierter Zuweisung des .text-Segmentes doch was ganz anderes.

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.