Forum: Mikrocontroller und Digitale Elektronik AVR-gcc kennt keine Adresslimits?


von batman (Gast)


Lesenswert?

Ähm gerade fällt mir zum ersten Mal auf, daß mein avr-gcc munter 
Fantasieadressen über die RAM-Grenzen hinaus produziert. Man merkts nur 
daran, daß das Programm dann nicht so toll läuft.

Blöde Frage aber ist das normal, daß man da selbst aufpassen muß, daß 
die data+bss-sections nicht größer als der vorhandene RAM des AVR 
werden?

Ich meine bei Überschreiten der text-section meckern ja sowohl avr-gcc 
wie auch avrdude aber beim RAM nix? Jetzt bin ich leicht verwirrt.

Aus dem .sym beim ATmega328p:
00800100 D __data_start
...
00800923 B __bss_end
00800923 B _end

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

batman schrieb:
> Blöde Frage aber ist das normal,

Ja, ist es: der Linker kennt praktisch nur Device-Klassen, daher
kann er die Limits des konkreten Devices nicht kennen.  Er würde
dir allerdings meckern, wenn du mehr als 64 KiB versuchst zu
allozieren.

von batman (Gast)


Lesenswert?

Achso na dann. Der Stack kommt ja sowieso noch darüber am RAM-Ende mit 
unbekannter Größe oder? Ist das Mist, wenn man ans RAM-Limit kommt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

batman schrieb:
> Der Stack kommt ja sowieso noch darüber am RAM-Ende mit unbekannter
> Größe oder?

Ja, der Stack wächst (per default) vom Ende des SRAMs nach unten,
die Variablen dagegen vom Anfang nach oben.  Irgendwann „treffen“ sie
sich dann also.

von batman (Gast)


Lesenswert?

Das alte Dilemma. Kann ich im C-Programm einen Test-String als letzte 
globale Variable, also quasi als Puffer anlegen oder läßt sich der 
Linker bei der Adressvergabe nicht reinreden?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

batman schrieb:
> oder läßt sich der Linker bei der Adressvergabe nicht reinreden?

Weder Compiler noch Linker lassen sich durch irgendeine Anordnung
von irgendwas innerhalb deines Quelltextes beeindrucken.

Du kannst natürlich im Linker eine Guard-Variable explizit hinter dem
Rest platzieren, indem du sie im Compiler in eine eigene Section
packst und im Linkerscript dann arrangierst, dass genau diese Section
am Ende des statisch allozierten RAMs liegt.

von eagle user (Gast)


Lesenswert?

Kann man die RAM-Größe nicht im Linker-Script angeben? Genau wie die 
Größe des Flash? Mit dem arm-gcc geht's hier ungefähr so:
1
MEMORY
2
{  
3
   flash_boot    (rx) : ORIGIN = 0x08000000, LENGTH = 16K
4
   flash_display (rx) : ORIGIN = 0x08008000, LENGTH = 24K
5
   
6
   ram_boot      (rw) : ORIGIN = 0x2001c000, LENGTH = 1K
7
   ram_display   (rw) : ORIGIN = 0x2001f000, LENGTH = 2K
8
}
9
10
SECTIONS
11
{
12
  .text : ALIGN(16) SUBALIGN(16) {
13
     FILL (0xff)
14
     *(.text)
15
     *(.text.*)
16
     *(.rodata)
17
     *(.rodata.*)
18
     *(.gcc*)
19
     . = ALIGN(4);
20
text_end = .;
21
  } > flash_display
22
23
  .stack : {
24
stack = .;
25
    . += 768;
26
tos = .;
27
  } > ram_display
28
29
  .data : ALIGN(4) SUBALIGN(4) {
30
data_start = .;
31
     *(.data)
32
     *(.data*)
33
data_end = .;
34
  } > ram_display AT > flash_display
35
36
  .bss : ALIGN(4) SUBALIGN(4) {
37
bss_start = .;
38
     *(COMMON)
39
     *(.bss)
40
     *(.bss*)
41
bss_end = .;
42
  } > ram_display
43
}

Vielleicht funktioniert es deshalb, weil ich den Stack an den Anfang 
lege?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

eagle user schrieb:
> Kann man die RAM-Größe nicht im Linker-Script angeben?

Natürlich kann man.  AVR-GCC ist aber deutlich mehr „out of the box“
als ARM-GCC; einen Linkerscript gibt man dort daher normalerweise
nicht selbst an.  Die generischen Linkerscripts funktionieren gut
genug im Zusammenspiel mit dem Startup-Code der avr-libc, als dass
man das alles direkt benutzen kann.  Diese generischen Linkerscripts
sind aber eben, wie ich eingangs schrieb, nicht pro Device vorhanden,
sondern nur grob klassifiziert für jede eigene AVR-Klasse.

Gegen das genannte Problem der Kollision des Stacks mit den statisch
zugewiesenen Daten würde der Linkerscript ohnehin nicht helfen.  Es
bleibt damit immer beim Programmierer abzuschätzen, ob der nach dem
Linken vorhandene freie RAM aller Wahrscheinlichkeit nach ausreichend
für den Stack sein wird.

von batman (Gast)


Lesenswert?

Absolut richtig. Ich hätte das Problem nur einen Tag früher erkannt, 
wenn es eine RAM-Overflow-Warnung gegeben hätte. Einen Overflow des (wg. 
RTOS) minimalen main-Stacks hatte ich nicht auf dem Schirm.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

batman schrieb:
> wenn es eine RAM-Overflow-Warnung gegeben hätte

Daher gab's bei WinAVR immer noch so einen Script, der nach dem
Compilieren den Füllstand der Speicher in % ausgegeben hat.  Hat
Eric Weddington dann als schrägen Hack ins "size"-Programm hinein
gelegt, aber es war von vornherein klar, dass dieser rein
AVR-spezifische Hack es niemals hätte (in dieser Form) in die Binutils
zurück gemacht.

Die Shellscript-Variante bliebe natürlich nach wie vor.

Vorteil ist, dass man auch die Sache mit dem Stack dann schnell
abschätzen lernt.

: Bearbeitet durch Moderator
von stack-heap collider (Gast)


Lesenswert?

gcc -fstack-usage benutzen und dann immer schön die *.su Dateien lesen?

Oder -Wstack-usage=200 fürs gröbste..

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg W. schrieb:

Und wozu ist das ganze Geraffel dann gut, dass crt.o nach .note.gnu.avr 
packt?
1
    .section .note.gnu.avr.deviceinfo, "", @note
2
#define NOTE_NAME "AVR"
3
#ifdef __AVR_DEVICE_NAME__
4
    #define DEVICE_NAME STR(__AVR_DEVICE_NAME__)
5
#else
6
    #define DEVICE_NAME ""
7
#endif
8
9
    .long .L__note_name_end - .L__note_name_start
10
    .long .L__desc_end - .L__desc_start
11
    .long 1 ; Type 1 - this is the only known note type for AVR.
12
.L__note_name_start:
13
    .asciz NOTE_NAME
14
    .balign 4
15
.L__note_name_end:
16
.L__desc_start:
17
#ifdef FLASHSTART
18
    .long FLASHSTART
19
#else
20
    .long 0
21
#endif
22
#ifdef PROGMEM_SIZE
23
    .long PROGMEM_SIZE
24
#elif FLASHEND > 0
25
    .long FLASHEND + 1
26
#else
27
    .long FLASHEND
28
#endif
29
    .long RAMSTART
30
#ifdef RAMSIZE
31
    .long RAMSIZE
32
#elif RAMEND > 0
33
    .long RAMEND - RAMSTART + 1
34
#else
35
    .long RAMEND
36
#endif
37
#ifdef E2START
38
    .long E2START
39
#else
40
    .long 0
41
#endif
42
#ifdef EEPROM_SIZE
43
    .long EEPROM_SIZE
44
#elif E2END > 0
45
    .long E2END + 1
46
#else
47
    .long E2END
48
#endif
49
    /* String offsets table.
50
    Index 0 - Size of offset table in bytes
51
    Index 1 - Device name byte offset
52
    */
53
.L__stroffsettab_start:
54
.long .L__stroffsettab_end - .L__stroffsettab_start /* Size of index table in bytes */
55
.long .L__device_name_start - .L__strtab_start /* Byte offset of device name */
56
.L__stroffsettab_end:
57
    /* String table for storing arbitrary strings.
58
    Offsets are stored in the string offset table above */
59
.L__strtab_start:
60
    .byte 0
61
.L__device_name_start:
62
    .asciz DEVICE_NAME
63
.L__device_name_end:
64
    .byte 0

Aus: 
http://svn.savannah.nongnu.org/viewvc/avr-libc/trunk/avr-libc/crt1/gcrt1.S?view=markup

Ich hätte gedacht, dass dass ganau dafür eingeführt wurde?  Immerhin ist 
nie erforderliche Info da.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jo, könnte sein, dass das dafür mal da war – dann aber nicht richtig
zu Ende geführt worden ist.  Könnte man sich wohl zumindest hinsetzen
und es darauf basierend korrekt machen, anders als der schräge, hart
codierte Hack von Eric dazumals.

von Root (Gast)


Lesenswert?

Die aktuelleln Versionen vom AtmelStudio geben immer noch einen Meldung 
aus:
1
        Program Memory Usage   :  140188 bytes   13,4 % Full
2
        Data Memory Usage     :  74200 bytes   56,6 % Full

Im automatisch genereierten Makefile kann man aber keinen Aufruf dafür 
erkennen.
Weiß jemand wie das funktioniert? Ich würde die Ausgabe gerne in meinen 
manuellen MakeFiles einbauen

von Oliver S. (oliverso)


Lesenswert?

avr-size

Oliver

von Stefan F. (Gast)


Lesenswert?

Aber immer schon dran denken, dass avr-size nur den Speicherbedarf für 
statische Variablen berücksichtigt. Der Stack und dynamischer Speicher 
sind nicht mit drin. Ich würde daher stets dafür sorgen, dass mindestens 
64 Bytes frei bleiben. Wenn man printf benutzt, dann mindestens 100 
Bytes.

von adkfsgksadf@gmx.de (Gast)


Lesenswert?

Hi,

aber man kann sich doch beliebige neue Speicherklassen im Linkerfile 
erzeugen, explizit seine Variablem lokatieren und diese Klassen auf 
Grösse überwachen. Dann spukt der Linker die entsprechenden Fehler 
aus...
1
  .calram (NOLOAD) :
2
  {
3
     PROVIDE (__calram_start = .) ;
4
    *(.calram*)
5
     PROVIDE (__calram_end = .) ;
6
  } > data
7
  .data    : AT (ADDR (.text) + SIZEOF (.text))
8
  {
9
     PROVIDE (__data_start = .) ;
10
    *(.data)
11
    *(.data*)
12
    *(.rodata)  /* We need to include .rodata here if gcc is used */
13
    *(.rodata*) /* with -fdata-sections.  */
14
    *(.gnu.linkonce.d*)
15
    . = ALIGN(2);
16
     _edata = . ;
17
     PROVIDE (__data_end = .) ;
18
  }  > data
19
  ASSERT((ADDR(.calram) + SIZEOF(.calram)) <= ADDR(.data), ".calram exceeds page size")

Grüße

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

adkfsgksadf@gmx.de schrieb:

> aber man kann sich doch beliebige neue Speicherklassen im Linkerfile
> erzeugen,

Klar kann man das.  Aber nochmal: „normale“ AVR-Nutzer mögen sich
eher nicht um den Linkerscript kümmern, denn der, der mit der
Toolchain mitkommt, deckt einen Großteil der Bedürfnisse ab.

Wie schon ausreichend dargelegt worden ist, muss man sowieso extern
den Speicherfüllstand im Blick behalten, damit man ausreichend
Reserve für den Stack hat.  (Der Heap gibt sich selbst Mühe, immer
noch genügend Abstand zum Stack als Reserve zu haben.)

> Dann spukt der Linker die entsprechenden Fehler
> aus...

Na, hoffentlich spukt er nicht … Halloween ist ja schon vorbei. :)

Beitrag #5220899 wurde von einem Moderator gelöscht.
von batman (Gast)


Lesenswert?

Ich hab das Feature auch jahrelang nicht vermißt, also ist das schon zu 
verschmerzen, wenns der Einfachheit dient.

von Stefan (Gast)


Lesenswert?

es gab da mal avrStackView der bekommt das erstaunlich gut hin.
Stefan

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.