Forum: Compiler & IDEs In C-Code auf Variable des Linker Scripts zugreifen


von AVRuser (Gast)


Lesenswert?

Hallo zusammen,

mein Hinderniss ist folgendes:

Ich hab in einer C-Datei eine Konstante definiert die ins Flash kommt.
Etwa so:
const unsigned int TotalCodeLength;

Jetzt möchte ich diesen Wert mit dem Wert 'etext' aus dem Linker
Script versehen so das ich im C-Code weiss wie weit quasi mein
gesamter Flash befüllt ist. In assembler mache ich das wie gewohnt
über eine PROVIDE derective im linker script und eine .global
deklaration im assembler file. dann kann ich auf den wert 'etext' in
der assembler datei zugreifen. ähnlich wie beim startup mit den
'data' und 'bss_start' werten etc. Nur wie komm ich in der c-datei
an den wert dran?

die anderen sachen funktionieren auch nicht:
const unsigned int TotalCodeLength = _etext;

oder:
extern const unsigned int _etext;
const unsigned int TotalCodeLength = _etext;

kann man auf provided variablen des linker scripts überhaupt
in c zugreifen?

Grüße und danke für eure hilfe
AVRuser

von Juergen B. (jbeisert)


Lesenswert?

Beispielsweise im Linker-Script sowas:

[....]
.doTheWrapper 0x00000:
{
 startOfRealWrapper = LOADADDR(.realWrapper) + 0xFFFF0000;
 endOfRealWrapper = LOADADDR(.realWrapper)+SIZEOF (.realWrapper) + 
0xFFFF0000;
}
[....]

Was da zugewiesen wird, ist erst mal egal.

Im C-Text dann sowas:

[...]
extern unsigned char *startOfRealWrapper;
extern unsigned char *endOfRealWrapper;
[...]

Hier gibst Du dann den Variablen eine Bedeutung. bei mir eben Zeiger, 
weil ich die Adressen darin (die dann vom Linker eingesetzt werden) zum 
Kopieren benutzen will.
Und nicht wundern: Die gesamten C-Quellen enthalten nirgends ein 
"unsigned char *startOfRealWrapper;" (also ohne "extern"). Das 
funktioniert dann aber nur, wenn man am Ende mit dem Scrip-Schnipsel von 
oben binden läßt. Ansonsten meckert der Linker über die fehlenden 
Symbole.

JB

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du kannst mit PROVIDE im Linkerskript ein Symbol exportieren.

Der Haken ist, dass du ein eigenes, modifiziertes Linkerskript brauchst, 
die du ggf. bei Updates der offiziellen avr-libc updaten musst.

Welches Linkerskript du ändern kannst, hängt von deinem AVR ab. Im 
folgenden habe ich es mit einem ATmega8 dargestellt, d.h. es ist das 
Linkerskript der avr4 Architektur zu ändern.

Die Architektur bekommst du über die Doku raus oder über das Anzeigen 
der ausführlichen GCC Kommandozeile oder über einen Blick in die 
MAP-Datei.

Nun gibt es für je eine Architektur fünf Linkerskripte. Das "normale", 
d.h. ohne spezielle Linkeroptionen, ist das avr4.x

Wenn du die Sache im simulator/Debugger per Memory View, Watch und 
Single Step nachvollziehen willst, schau dir den folgenden Democode an.

Zum Demonstrieren wird die Adresse ab _etext ermittelt und dann eine 
dort "geschickt" platzierte Stringvariable kopiert. Geschickt heisst, es 
ist die erste Variable im Programm und die ist extra einfach lesbar 
gestaltet.
1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
4
extern char PROGMEM _etext;
5
char s_rom[] = "<-Ende von .text = Anfang von Romdata";
6
char s_ram[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
7
void * watch_me;
8
uint8_t i;
9
10
int main(void)
11
{
12
  watch_me = &_etext;
13
  
14
  for (i = 0; s_ram[i]; i++)
15
    s_ram[i] = pgm_read_byte(watch_me + i * sizeof(uint8_t));
16
17
  return 42;
18
}

und der Ausschnitt aus avr4.x
1
...
2
    KEEP (*(.fini1))
3
    *(.fini0)  /* Infinite loop after program termination.  */
4
    KEEP (*(.fini0))
5
/*    _etext = . ; */
6
    PROVIDE (_etext = .) ;  /* <====================== */
7
  }  > text
8
  .data    : AT (ADDR (.text) + SIZEOF (.text))
9
  {
10
     PROVIDE (__data_start = .) ;
11
    *(.data)
12
    *(.data*)
13
    *(.rodata)  /* We need to include .rodata here if gcc is used */
14
...

von AVRuser (Gast)


Lesenswert?

Ich hab nochmal das ganze genauer betrachtet. Ich glaub mein 
Basisproblem ist erst mal noch ein anderes. Das ganze ist für einen 
LPC2129 Controller mit WinARM. Ich habe eine Softwareaufteilung gemacht 
in einen Bootloader und die eigentliche Applikation. Im Flash gibt es 
einen Bereich in dem Firmware-Infos abelegt sind. Also Datum, Version 
etc. und die Länge der Firmware. Diese verwendet der Bootloader um einen 
CRC Check zu machen. In der Firmware habe ich eine Struktur etwa so:

typedef struct {
u8_t  VersionMain;
u8_t  VersionSub;
u16_t Build;
u32_t CRCLength;
} FirmwareInfo_t;

In einer C-Datei meiner Firmware lege ich nun im Flash eine Instanz der 
Struktur an einer bestimmten Adresse an. So das auch der Bootloader die 
Version etc. der Firmware auslesen kann. Das ist etwa so:

const FirmwareInfo_t FwInfo = { 1, 5, 12, 2520};

Das funktioniert auch so weit. Nun ersetze ich die manuell eingetragene 
Länge durch das Label _etext das er zur compilierzeit aber noch nicht 
kennt. Also so:

const FirmwareInfo_t FwInfo = { 1, 5, 12, _etext};

Als Fehler bekomme ich erst mal noch den das der Compiler beim parsen 
des Codes sieht das die Struktur 'const' ist, jedoch das Symbol bzw. der 
Wert _etext zur Parse-Zeit nicht bekannt ist. Denn dieser ist ja erst 
zur Link-Zeit bekannt. Kann ich den Wert auch in einer anderen Art ins 
Flash an eine bestimmte Adresse bringen ?? Vielleicht im LinkerScript 
selbst ?

von Juergen B. (jbeisert)


Lesenswert?

Sieh' Dir mal das Manual vom LD an. Die Rubrik "linker scripts" ist sehr 
umfangreich und - meiner Meinung nach - auch sehr verständlich.
Wenn Du das im Linker-Script unterbringen willst, such' Dir die 
"schönste" Stelle raus und füge dort ein:

BYTE(<zahl>); /* ver major */
BYTE(<zahl>); /* ver minor */
SHORT(<zahl>); /* build */
LONG( SIZEOF(<.text>) ); /* oder wovon die Groesse gebraucht wird */

Du mußt dabei nur beachten, daß es nicht möglich ist, hier Variablen zu 
verwenden. Der Linker will nur echte Zahlen. Allerdings könntest Du das 
Linkerscript vorher durch den Precompiler schieben, um das Script selber 
parametrisieren zu können, bevor es der Linker zu sehen bekommt.

von AVRuser (Gast)


Lesenswert?

hallo nochmal zusammen,
also ich habs hinbekommen aber auf ne gemischte art. meine struktur im 
c-code enthält nun nur noch die daten zur firmware selbst quasi 
versionen, datum etc. dann hab ich im linker script die section in die 
die struktur rein soll etwas abgeändert zu:

....

.FwInfo 0x3DF00 :
{
  *(.FwInfo)

  LONG ( 0x2000);                             /* Begin of Firmware */
  LONG ( _etext + SIZEOF ( .data) - 0x2000);  /* Length of Firmware for 
CRC */
  SHORT ( 0);                                /* Placeholder for CRC */
}

....


danke für eure anregungen besonders mit den direktiven zum einfügen von 
daten ins image mit BYTE, LONG etc. ich hab in der doku bestimmt 
mehrmals die stelle überschlagen aber nie genau gelesen. hab mehr nach 
direktiven wie EXPORT oder der art gesucht. auch nach pragmas für den 
code. bin nur nie fündig geworden :-)

grüße

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.