Linker-Fehlermeldung unklar

OP #7682258
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!

(Firma: O.D.I.S.) #7682283
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 $

OP #7682292
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.

(Firma: O.D.I.S.) #7682301
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

#7682305
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

#7682310
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.

#7682552
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.

Persönliche Seite #7682565
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.

#7682583
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

OP #7682688
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.

OP #7683256
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?

(Firma: L-E-A) #7683318
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

OP #7683475
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.

OP #7683638
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren