AVR-GCC Linker Symbol als Initializer verwenden

#5781232
Lesenswert?

Hallo zusammen,

ich möchte im Flash meines ATMEGA88 Start- und Endadresse eines 
Bereiches ablegen, über den eine CRC berechnet werden soll.
Die Adressinformation erzeuge ich über das Linkerskript mit
__CHECKSUM_START = .;
und
__CHKSUM_END = .;

Nun deklariere ich diese Symbole entsprechend mit
extern const uint32 __CHECKSUM_START;
extern const uint32 __CHKSUM_END;

Definieren möchte ich dann eine Variable mit

const uint32 PROGMEM ChksumStartAddr = &__CHECKSUM_START;

Aber der Compiler macht mir einen Strich durch die Rechnung:
error: initializer element is not computable at load time

Kann mir jemand sagen, was ich verkehrt mache?

Danke und viele Grüße
#5781318
Lesenswert?

Eigentlich müsste es gehen. Zum Vergleich, in meinem Code (ist zwar 
ARM-GCC, aber dafür spielt das ja keine Rolle) sieht das so aus:
1
// first address that follows the rom space used by the linker
2
extern uint32_t _usedromend;  
3
// first address that is used for the .text section by the linker 
4
extern uint32_t _usedromstart; 
5

6
uint32_t sysComputeFlashCRC()
7
{
8
  uint32_t *dp;
9

10
  dp = &_usedromstart;
11
  sysCRCReset();
12
  while (dp != &_usedromend) sysCRCAdd(*dp++);
13
  return sysCRCGet();
14
}

und im Linkerscript:
1
SECTIONS
2
{
3
  .text :
4
  {
5
  _usedromstart = .;
6
    KEEP(*(.isr_vector))
7
    *(.text*)
8
    *(.rodata*)
9
  } > rom 
10
  
11
  .ARM.exidx : 
12
  {
13
    __exidx_start = .;
14
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
15
    __exidx_end = .;
16
  } > rom
17
  
18
  __etext = .;
19
  /* _sidata is used in startup code */
20
  _sidata = __etext;
21
  .data : AT (__etext)
22
  {
23
    __data_start__ = .;
24
    /* _sdata is used in startup code */
25
    _sdata = __data_start__;
26
    
27
    *(vtable)
28
    *(.data*)
29
    . = ALIGN(4);
30
    /* All data end */
31
    __data_end__ = .;
32
    /* _edata is used in startup code */
33
    _edata = __data_end__;
34
  } > ram 
35
  /* _siccmdata is used in startup code to init vars in ccm */
36
  _siccmdata = __etext + SIZEOF (.data);
37
  .ccmdata : AT ( _siccmdata )
38
  {
39
    __ccmdata_start__ = .;
40
    _sccmdata = __ccmdata_start__;
41
    *(.ccmdata*)
42
    . = ALIGN(4);
43
    /* All data end */
44
     __ccmdata_end__ = .;
45
    _eccmdata = __ccmdata_end__;
46
  } > ccm
47
  _usedromend = _siccmdata + SIZEOF (.ccmdata);
48
  .bss :
49
  {
50
...

Vielleicht hilft das ja...

PS: Gerade ausprobiert:
1
const uint32_t *rompointer = &_usedromstart;
im Code compiliert einwandfrei. Also sollte dein Beispiel eigentlich 
auch gehen... Muss wohl eine AVR-Spezialität sein. Kannst du denn eine 
nicht-PROGMEM-Variable damit initialisieren?
#5781338
Lesenswert?

Habe gerade nochmal probiert:

Eine globale variable:
1
const uint32_t romstartadr = (uint32_t)&_usedromstart;
2

3
// uses the built in CRC engine to compute
4
// the CRC of the FLash
5
uint32_t sysComputeFlashCRC()
6
{
7
  uint32_t *dp;
8

9
  //dp = &_usedromstart;
10
  dp = (void*)romstartadr;
11
  sysCRCReset();
12
  while (dp != &_usedromend) sysCRCAdd(*dp++);
13
  return sysCRCGet();
14
}

funktioniert auch. Die liegt auch im Flash und nicht im RAM, da const. 
Wenn der GCC das beim ARM zur Linkzeit eintragen kann, müsste das doch 
beim AVR auch gehen?!
#5781347
Lesenswert?

Also mit einer "nicht-progmem" Variablen geht es auch nicht.
Ich habe nun folgendes probiert:

const uint32_t startaddr = __CHKSUM_START;

Funktioniert auch nicht. Fehlermeldung ist wieder
error: initializer element is not computable at load time

Ich denke wirklich, es ist hier eine AVR-GCC Spezialität

Edit:
Brauch ich noch ein spezielles Compiler-Flag oder einen zusätzlichen 
Link-Run oder so etwas?
#5781365
Lesenswert?

Jay K. schrieb:
> Ich denke wirklich, es ist hier eine AVR-GCC Spezialität

Das ist keine Limitation des Compilers, sondern des Linkers. Ich glaube 
ich hatte mit const auch schon ähnliche Probleme.

Interessanter weise scheint das hier bei mir zu gehen:
1
#include <stdio.h>
2

3
int x __attribute__((section("testsec")));
4
int y __attribute__((section("testsec")));
5

6
extern char __start_testsec[];
7
extern char __stop_testsec[];
8

9
struct my_structure {
10
  void* start;
11
  void* end;
12
};
13

14
const struct my_structure testsec_info = {
15
  .start = __start_testsec,
16
  .end = __stop_testsec
17
};
18

19
int main(){
20
  printf("%p %p\n",testsec_info.start, testsec_info.end);
21
}
Gast #5784072
Lesenswert?

Daniel A. schrieb:
> Interessanter weise scheint das hier bei mir zu gehen:

Na sowas...

Eine andere Möglichkeit wäre, es folgendermaßen komplett übers 
Linkerscript zu machen:
1
.text : {
2
  LONG(__CHECKSUM_START)
3
  LONG(__CHECKSUM_END)
4
  . = ALIGN(4);
5
  __CHECKSUM_START = .;
6
  ...
7
  . = ALIGN(4);
8
  __CHKSUM_END = .;
9
}
Im C-Code braucht man gar nichts mehr zu schreiben. Wenn man die 
Adressen auslesen will kann man wie gehabt extern benutzen:
1
extern const uint32_t __CHECKSUM_START;
2
extern const uint32_t __CHKSUM_END;

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