Forum: Mikrocontroller und Digitale Elektronik Linker-Fehlermeldung unklar


von Rudi (rudils)


Lesenswert?

Hallo
Mein Programm soll für PiPico in C mit VsCode gebaut werden.
Es besteht aus 9 .c/.h Files. Compilieren einzelner Module ist 
fehlerfrei. Beim erzeugen des Gesmtprojektes kommt die Fehlermeldung:
1
[build] /usr/lib/gcc/arm-none-eabi/10.3.1/../../../arm-none-eabi/bin/ld: CMakeFiles/fbg.dir/File2.c.obj: in function `Getnum':
2
[build] /home/rs/pico/fbg/File2.c:101: undefined reference to `strgCode'

Im File1.c ist definiert:
1
static uint8_t strgCode[50] ={  55,..... }

im File2.c ist das:
1
extern  uint8_t strgCode[50];
2
3
uint8_t readint( size_t cnt ) 
4
{
5
size_t    c = cnt;
6
uint8_t    tnr;
7
int      v = 0;
8
9
while ( true ) {
10
  while ( true ) {                // Auf Num Taste warten
11
    tnr = Taste_get();
12
    if ( tnr < 0 ) return -1;
13
    if (( strgCode[tnr] / 10 ) == 5 ) {
14
      if ( UsbIsOn && tnr > 0 ) putchar( tnr );    // fehler
15
      v = ( v * 10 ) + ( strgCode[tnr] - 50 );
16
      if ( --c == 0 ) return v;
17
      }
18
    else if ( tnr == 42 ) return -1;      // exit | 'z'
19
    }                      
20
  }
21
}
22
23
24
int  Getnum( int cnt, int8_t *lst )
25
{
26
int      t, i, e = 0;
27
bool    f;
28
tprints("  0");
29
RedLed_AB( 1, false );
30
while ( true ) {
31
  t = Taste_get();
32
  if ( t >= 0 ) {
33
    if (( strgCode[t] / 10 ) == 20 ) {              // F?-Taste toggeln für Gerätewahl
34
      e =  e ^ ( strgCode[t] - 200 );
35
      }
36
    else if (( strgCode[t] / 10 ) == 5 ) {            // Dez-Ziffer eingeben
37
      e = ( e * 10 ) + ( strgCode[t] - 50 );
38
      }
39
    if ( e >= cnt ) {
40
      e = 0;
41
      RedLed_F4( 15, false );
42
      RedLed_AB( 3, false );
43
      for ( i=0; i<20; i++ ) { ledblink_job();  sleep_ms( 163 ); }
44
      RedLed_AB( 1, false );
45
      }
46
    if ( ProgState ) { sprintf(tline,"\b\b\b%3d", e );tprint(); }
47
    RedLed_F4( e & 0x0F, false );
48
    if ( t == tExit || t == usbEsc ) { RedLed_AB( 0, false ); return -1; }
49
    if ( t == tBack || t == usbBack ) e = 0;
50
    if ( t == tOk || t == usbRet) { 
51
      if ( lst != 0 ) {                      // Mit Liste eintrag prüfen
52
        i = 0;
53
        f = false;
54
        while ( i < 16 ) if ( lst[i++] == (int8_t)e ) f = true;     // ist eingabe in Liste
55
        if ( f == false ) e = -1;
56
        }
57
      RedLed_AB( 0, false ); 
58
      return e;                 <<<---- dies ist Zeile 101
59
      }
60
    }
61
  sleep_us( LoopTime );
62
  }
63
}

Ich finde in Getnum() keinen Fehler, aber ohne diese Funktion läuft der 
Compiller durch. Und wieso auf Zeile 101, da ist doch kein strgCode. Und 
wo soll der Unterschied zu readint() sein?
Schätze, ich steh auf'n Schlauch!

: Bearbeitet durch User
von Olaf D. (Firma: O.D.I.S.) (dreyero)


Lesenswert?

Hi,

du hast das so definiert:

Im File1.c ist definiert:
static uint8_t strgCode[50] ={  55,..... }

Static bedeutet für den Linker, linken aus anderen Modulen nicht 
erlaubt.
Also, "static" und "extern" widersprechen sich.

Gruß
Olaf

von Rudi (rudils)


Lesenswert?

Olaf D. schrieb:
> Also, "static" und "extern" widersprechen sich.

Das wundert mich aber. Denn ich habe noch einige static Daten mehr im 
Projekt, die ich auf die gleiche Weise gebrauche und mit denen allen 
funktioniert alles problemlos.
Und zur Beachtung: in Funktion readint() funtioniert es, obwohl im 
selben File!

: Bearbeitet durch User
von Olaf D. (Firma: O.D.I.S.) (dreyero)


Lesenswert?

olaf@nb04 ~/tmp/c $ cat file1.c
#include <stdint.h>

static uint8_t strgCode[50] ={ 55 };


olaf@nb04 ~/tmp/c $ cat file2.c
#include <stdint.h>
#include <stdio.h>

extern  uint8_t strgCode[50];

int main(int argc, char ** argv)
{
for(int i = 0; i < 50; i++)
{
printf("strgCode(%i)=%i\n", i, strgCode[i]);
}
}

olaf@nb04 ~/tmp/c $ gcc -o test file1.c file2.c
/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ 
ld:  /tmp/cc4PGPoJ.o: warning: relocation against `strgCode' in 
read-only section `.text'
/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ 
ld:  /tmp/cc4PGPoJ.o: in function `main':
file2.c:(.text+0x24): undefined reference to `strgCode'
/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ 
ld:  warning: creating DT_TEXTREL in a PIE
collect2: Fehler: ld gab 1 als Ende-Status zurück
olaf@nb04 ~/tmp/c $
olaf@nb04 ~/tmp/c $
olaf@nb04 ~/tmp/c $ vi file1.c (remove static keyword)
olaf@nb04 ~/tmp/c $ cat file1.c
#include <stdint.h>

uint8_t strgCode[50] ={ 55 };


olaf@nb04 ~/tmp/c $ gcc -o test file1.c file2.c
olaf@nb04 ~/tmp/c $

: Bearbeitet durch User
von Olaf D. (Firma: O.D.I.S.) (dreyero)


Lesenswert?


von Rudi (rudils)


Lesenswert?

Ja, ok. Vieleicht liegt weil dur für einen PC compiliert hast. Der hat 
sein Programm im RAM und nicht im Flash, wie beim PiPico. Ich will diese 
Daten, weil sie nicht geändert werden, einfach im Flash haben. Wenn das 
anders programmiert werden kann, dann tue ich es.

von Olaf D. (Firma: O.D.I.S.) (dreyero)


Lesenswert?

Hi Rudi,

für welche Plattform du das compilierst ist erstmal egal.
Der Linker muss die Adresse der Variablen auflösen.
Wenn du ihm verbietest von einem File auf das andere zuzugreifen,
kann er das nicht durchführen.
Ob diese Variable im (nur) im Flash landet hängt in erste Linie
von der Architektur, der Variablen-Definition und dem Linker-Script ab.
Dort kannst du alle Variablen erfassen, die nur im Flash stehen sollen.

Bei dem Pico kann ich leider nicht weiterhelfen.
Aber der Linker-Fehler sollte nach entfernen von "static" weg sein.

Gruß
Olaf

von Rolf (rolf22)


Lesenswert?

Rudi schrieb:
>> Also, "static" und "extern" widersprechen sich.

> Das wundert mich aber. Denn ich habe noch einige static Daten mehr im
> Projekt, die ich auf die gleiche Weise gebrauche und mit denen allen
> funktioniert alles problemlos.

Da wir nicht deine komplette Source-Dateien haben, wundern wir uns 
zunächst auch nicht.
Was bedeutet überhaupt "problemlos"? Das Programm läuft doch mit dem 
Linker-Fehler gar nicht, oder?

Zumindest ist es denkbar, dass der Linker das Problem mit der 
undefinierten Variable 'strgCode' nur einmal und nicht mehrfach meldet. 
Das könnte erklären, warum es in 'readint()' nicht auftritt.

Hier und an anderen Stellen finde ich immer nur diese Erklärung:
https://stackoverflow.com/questions/4576607/what-does-static-mean-in-ansi-c

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Rudi schrieb:
> Ich will diese
> Daten, weil sie nicht geändert werden, einfach im Flash haben. Wenn das
> anders programmiert werden kann, dann tue ich es.

Hat genau dafür der Liebe Gott nicht den Qualifier "const" erschaffen?

Grüßle,
Volker

: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

Es gibt im Pico SDK eine Header Datei:
src/rp2_common/pico_platform/include/pico/platform.h

Dort befindet sich ein:
#define __in_flash(group) __attribute__((section(".flashdata." group)))

von Rolf (rolf22)


Lesenswert?

Olaf D. schrieb:
> Der Linker muss die Adresse der Variablen auflösen.

Richtig.

> Wenn du ihm verbietest von einem File auf das andere zuzugreifen,
> kann er das nicht durchführen.

Es wird ihm nicht verboten.
Das Compilat der Datei mit dem 'static' enthält einfach gar keine 
Link-Information für den betreffenden Namen, also weiß der Linker nicht, 
dass es diesen Namen gibt.

von Sebastian W. (wangnick)


Lesenswert?

Rudi schrieb:
> Ich will diese Daten, weil sie nicht geändert werden, einfach im Flash
> haben.

Das scheint ein Mißverständnis zu sein. Das Schlüsselwort static hat mit 
Flash versus RAM nichts zu tun.

LG, Sebastian

von Rudi (rudils)


Lesenswert?

Volker B. schrieb:
> Hat genau dafür der Liebe Gott nicht den Qualifier "const" erschaffen?

Hallo, danke, das war's. Aber warum hat mir Gott das nicht selbst 
erklärt?
Zumindest linkt es nun. Austesten fängt jetzt an und dauert noch.

Gruß Rudi

von Norbert (der_norbert)


Lesenswert?

Rudi schrieb:
> Volker B. schrieb:
>> Hat genau dafür der Liebe Gott nicht den Qualifier "const" erschaffen?
>
> Hallo, danke, das war's. Aber warum hat mir Gott das nicht selbst
> erklärt?
> Zumindest linkt es nun. Austesten fängt jetzt an und dauert noch.
>
> Gruß Rudi

Dennoch liegt's noch im RAM. Abhilfe:

Beitrag "Re: Linker-Fehlermeldung unklar"

von Rudi (rudils)


Lesenswert?

Norbert schrieb:
> #define __in_flash(group) __attribute__((section(".flashdata." group)))

Dann schmeiß mir doch nicht nur diesen Brocken hin. Ich seh' schon das 
könnte was bewirken. Aber wie ich sowas anwende, da hab ich zuwenig 
Erfahrung. Also konkrete Frage: wie baue ich das in mein Projekt ein?

von Norbert (der_norbert)


Lesenswert?

Rudi schrieb:
> Aber wie ich sowas anwende, da hab ich zuwenig
> Erfahrung.

Das konnte ich bis jetzt nicht erraten. Hier die offizielle 
Dokumentation deines benutzten SDK.

https://www.raspberrypi.com/documentation/pico-sdk/runtime.html#pico_platform

Speziell:
https://www.raspberrypi.com/documentation/pico-sdk/runtime.html#rpip2ae1d32a8ff2487c24b7
1
uint32_t __in_flash("my_group_name") foo = 23;

Sollte möglicherweise auch ohne Nennung eines eigenen group name 
funktionieren.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Rudi schrieb:
> Das wundert mich aber. Denn ich habe noch einige static Daten mehr im
> Projekt, die ich auf die gleiche Weise gebrauche und mit denen allen
> funktioniert alles problemlos

Kann nicht sein. Hast du vielleicht die static Variable im Header 
definiert sodass sie dann letztendlich mehrfach im Executable auftaucht?

Der SINN von "static" ist es schließlich, dass man die Variable eben 
NICHT aus anderen Dateien nutzen kann - da ist es kein Wunder, dass es 
hier nicht geht, aber sehr verwunderlich, wenn es an anderer Stelle doch 
geht.

von Harald K. (kirnbichler)


Lesenswert?

Niklas G. schrieb:
> Der SINN von "static" ist es schließlich, dass man die Variable eben
> NICHT aus anderen Dateien nutzen kann

Der Vollständigkeit halber:

Das ist die eine der Bedeutungen von static, die Sichtbarkeit von 
Symbolen für den Linker.

Für jede translation unit (plump: jedes übersetzte Sourcefile) legt 
der Compiler zwei Listen von Symbolnamen an, die der Linker verarbeitet. 
Die eine führt alle von der translation unit exportierten Symbolnamen 
auf (d.h. alle enthaltenen Funktionen und Variablen, auf die von "außen" 
zugegriffen werden kann), und die andere führt alle importierten 
Symbolnamen auf, d.h. Funktonen und Variablen, die anderswo definiert 
sind, auf die die translation unit aber zugreift.

Der Linker ist bestrebt, alle importierten Symbolnamen aufzulösen, 
gelingt ihm das nicht anhand der verschiedenen translation units, 
greift er auf etwaige ihm angegebene Libraries* zurück. So funktioniert 
z.B. der Aufruf von Funktionen wie printf.

Die andere Bedeutung von static gibt es bei der Definition von 
Variablen innerhalb einer Funktion. Da behält die Variable ihren Wert 
auch nach Verlassen der Funktion, so daß sie beim näächsten Aufruf der 
funktion weiterverwendet werden kann. Die Initialisierung der Variablen 
erfolgt nur einmal, auch wenn sie im Funktionsrumpf untergebracht ist.


*) nicht im "Arduino"-Sinne

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Harald K. schrieb:
> Die andere Bedeutung von static gibt es bei der Definition von
> Variablen innerhalb einer Funktion.

Das hat aber nichts mit der anderen Bedeutung von "static" zu tun, das 
Keyword wird hier nur recycelt. Die in C++ hinzugekommene Bedeutung von 
"static" bei Klassen-Membern ist ebenfalls davon unabhängig.

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Niklas G. schrieb:
> Das hat aber nichts mit der anderen Bedeutung von "static" zu tun

Was könnte ich nur mit "der einen Bedeutung" und "der anderen Bedeutung" 
gemeint haben?

von Rahul D. (rahul)


Lesenswert?

Harald K. schrieb:
> Was könnte ich nur mit "der einen Bedeutung" und "der anderen Bedeutung"
> gemeint haben?

Dass es sich bei "static" um ein Homonym handelt...
Die selbe Bezeichnung für unterschiedliche Dinge.

von Martin H. (horo)


Lesenswert?

Rahul D. schrieb:
> Die selbe Bezeichnung für unterschiedliche Dinge.

Da hätten K&R besser ein weiteres Keyword "intern" spendiert, das dann 
als Gegenpart zu "extern" fungierte und auch die Nicht-Sichtbarkeit 
besser benannt hätte. Ich weiß, Konjunktiv und Fahrradkette :)

von Rudi (rudils)


Lesenswert?

Norbert schrieb:
> 
https://www.raspberrypi.com/documentation/pico-sdk/runtime.html#rpip2ae1d32a8ff2487c24b7
>
>
1
> uint32_t __in_flash("my_group_name") foo = 23;
2
>

Hallo, jetzt ist mir die Bedeutung von noch Group unklar. Ich hab halt 
mal irgentwas genommen. War ok.
Es hat bei uint8_t funktioniert. Mit der selben Group hat es auch mit 
char[] funktioniert.
Aber für *char[] hab ich eine anderen Groupnamen gebraucht.
In CppReference habe ich nichts gefunden.

von Rahul D. (rahul)


Lesenswert?

Martin H. schrieb:
> Ich weiß, Konjunktiv und Fahrradkette :)
Laut Loddar heißt das "Fahrradsattel". ;)

von Axel S. (a-za-z0-9)


Lesenswert?

Rahul D. schrieb:
> Harald K. schrieb:
>> Was könnte ich nur mit "der einen Bedeutung" und "der anderen Bedeutung"
>> gemeint haben?
>
> Dass es sich bei "static" um ein Homonym handelt...
> Die selbe Bezeichnung für unterschiedliche Dinge.

Was ist eigentlich eine rhetorische Frage?

von Rahul D. (rahul)


Lesenswert?

Axel S. schrieb:
> Was ist eigentlich eine rhetorische Frage?
Eine, auf die man keine Antwort erwartet.
Es ist aber auch nicht verboten, darauf zu "antworten".

von Rudi (rudils)


Lesenswert?

>>
1
>> uint32_t __in_flash("my_group_name") foo = 23;
2
>>
>
> Hallo, jetzt ist mir die Bedeutung von noch Group unklar. Ich hab halt
> mal irgentwas genommen. War ok.
> Es hat bei uint8_t funktioniert. Mit der selben Group hat es auch mit
> char[] funktioniert.
> Aber für *char[] hab ich eine anderen Groupnamen gebraucht.
> In CppReference habe ich nichts gefunden.

Hallo, ich warte noch immer auf ne Erklärung, oder gibt es keine?

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Rudi schrieb:

> Hallo, ich warte noch immer auf ne Erklärung, oder gibt es keine?

google kaput?
---------------------------------------------------------------
Section attribute macro for placement in flash even in a COPY_TO_RAM 
binary
For example a `uint32_t` variable explicitly placed in flash (it will 
hard fault if you attempt to write it!)

uint32_t __in_flash("my_group_name") foo = 23;

The section attribute is `.flashdata.<group>`
group a string suffix to use in the section name to distinguish groups 
that can be linker garbage-collected independently
----------------------------------------------------------------

Grüßle,
Volker

von Norbert (der_norbert)


Lesenswert?

Rudi schrieb:
> Hallo, ich warte noch immer auf ne Erklärung,

Möglicherweise nachdem sich die Manieren ein wenig verbessert haben.

von Rudi (rudils)


Lesenswert?

Norbert schrieb:
> Rudi schrieb:
>> Hallo, ich warte noch immer auf ne Erklärung,
>
> Möglicherweise nachdem sich die Manieren ein wenig verbessert haben.

Ich wuste noch nicht, dass Warten eine Maniere ist. Und wenn, dann eher 
eine positive. Oder ist dir das norddeutsche Sprichwort "Nun mal Butter 
bei die Fische" lieber?
Und die Mitteilung von Volkers google kannte ich schon längst. Diese 
Mitteilung erklärt aber nicht, warum verschiedene Datentypen 
verschiedene Groups brauchen. Und da mein google keine Erklärung dazu 
ausspuckt, werde ich weiterhin warten.

von Rahul D. (rahul)


Lesenswert?

Volker B. schrieb:
> google kaput?

Das meldet sich nicht von alleine, die Suchmaschine muss man auch erst 
mal fragen ;)

von Norbert (der_norbert)


Lesenswert?

Rudi schrieb:
> Ich wuste noch nicht, dass Warten eine Maniere ist.

Nein, sicher nicht. Aber dein frech forderndes Auftreten.
Im Übrigen machst du wohl etwas falsch, da eine bunte Mischung 
verschiedener Variablentypen im FLASH hier fehlerfrei kompiliert.

von Rudi (rudils)


Lesenswert?

Norbert schrieb:
> Im Übrigen machst du wohl etwas falsch, da eine bunte Mischung
> verschiedener Variablentypen im FLASH hier fehlerfrei kompiliert.

Äh? Ich dachte immer ein Compiler zeigt mir meine Fehler. Wenn das so 
geht, dann wundert es micht nicht mehr, dass er auch Fehler zeigt, wo 
keine sind.
Aber es wundert mich nicht mehr: wenn die man-Page von gcc(1) 20000 
Zeilen lang ist, kann sich kein Mensch mehr durchfinden. Auch wenn ich 
mich hier im Blindflug befinde, die letzte Programmversion lief noch.
Und das mit der "bunten Mischung" verstehe ich auch nicht. Sortierst du 
deine Variablentypen, wobei die hier im Flash gar nicht variabel sind.

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.