Forum: Compiler & IDEs AVR-GCC: Variable wir leider weg optimiert


von ChrisMicro (Gast)


Lesenswert?

Vielleicht kann mir jemand helfen.

Ich habe folgendes, kleines Programm:
1
#include <stdint.h>
2
3
uint16_t  boot_reset __attribute__((section(".bootreset")))= 0xCBFF;
4
5
int main()
6
{
7
  while(1);
8
}

Aber leider wird die Variable "boot_reset" einfach weg optimiert.

Wie kann ich das ändern?

von Peter II (Gast)


Lesenswert?

ChrisMicro schrieb:
> Wie kann ich das ändern?

verwende sie doch einfach, dann wird sie nicht wegoptimiert.

von Benji (Gast)


Lesenswert?

volatile davor packen.

von ffggsd (Gast)


Lesenswert?

1. attribute used verwenden, siehe
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Variable-Attributes.html#Variable-Attributes
2. im Linkerscript schauen, was mit der section bootreset passiert

von ChrisMicro (Gast)


Lesenswert?

Autor: Peter II (Gast)
>verwende sie doch einfach, dann wird sie nicht wegoptimiert.

Das habe ich schon probiert.
Wenn ich in der "Main" folgendes hinzu füge:
1
  uint16_t x=boot_reset;

wird sie nicht weg optimiert. Es ist allerdings nicht so richtig schön, 
weil ich die Variable gar nicht brauche sondern den Boot-Vektor, den sie 
an der Adresse 0 erzeugt ( memory section .bootreset=0 ).

>Autor: Benji (Gast)
>volatile davor packen.
Das habe ich schon probiert. Bringt nichts, wird trotzdem weg optimiert.

>2. im Linkerscript schauen, was mit der section bootreset passiert
Das linker command, welches Atmel Studio 7 erzeugt, sieht so aus:

-Wl,-Map="$(OutputFileName).map" -Wl,--start-group -Wl,-lm 
-Wl,--end-group -Wl,--gc-sections -Wl,-section-start=.text=0x1800 
-Wl,-section-start=.bootreset=0  -mmcu=attiny85 -B "D:\Program Files 
(x86)\Atmel\Studio\7.0\Packs\atmel\ATtiny_DFP\1.1.102\gcc\dev\attiny85"

.bootreset ist vorhanden, wie es aussieht. Da scheint also kein Fehler 
zu sein.

von Rolf M. (rmagnus)


Lesenswert?

ChrisMicro schrieb:
>>Autor: Benji (Gast)
>>volatile davor packen.
> Das habe ich schon probiert. Bringt nichts, wird trotzdem weg optimiert.

volatile sorgt dafür, dass Zugriffe auf die Variable nicht 
wegoptimiert, sondern so durchgeführt werden, wie sie im Code stehen. Es 
gibt aber keine Zugriffe. Deshalb bringt volatile hier nichts.

von ChrisMicro (Gast)


Lesenswert?

Autor: ffggsd (Gast)
>1. attribute used verwenden, siehe
>https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Varia...
Habe ich gerade mal probiert:
1
uint16_t  boot_reset __attribute__((section(".bootreset"))) __attribute__((used))= 0xCBFF;

Wirt trotzdem weg optimiert.

von Peter II (Gast)


Lesenswert?

ChrisMicro schrieb:
> wird sie nicht weg optimiert. Es ist allerdings nicht so richtig schön,
> weil ich die Variable gar nicht brauche sondern den Boot-Vektor, den sie
> an der Adresse 0 erzeugt ( memory section .bootreset=0 ).

ich versteht immer noch nicht was du damit machst. Irgendwie musst du 
sie doch mal verwenden, sonst macht das doch alles keinen sinn.

von ChrisMicro (Gast)


Lesenswert?

>ich versteht immer noch nicht was du damit machst. Irgendwie musst du
>sie doch mal verwenden, sonst macht das doch alles keinen sinn.

Sie wird als Reset Vector für einen Bootloader verwendet, genau wie hier 
im Abschnitt Speicherlayout beschrieben:

http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C

Man greift also nicht auf die Variable zu, sondern nur wenn der 
Prozessor einen Reset bekommt wird der Variablenwert als Code 
interpretiert ( RJMP ) und als Sprung zum eigentlichen Programm benutzt.

Scheinbar funktioniert es aber nicht mehr so wie in dem Artikel 
beschrieben. Vielleicht hat sich in den neueren GCC Versionen etwas 
verändert, so dass das Prinzip nicht mehr funktioniert.

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


Lesenswert?

ChrisMicro schrieb:
> uint16_t  boot_reset __attribute__((section(".bootreset")))= 0xCBFF;

Wie soll denn der Wert 0xCBFF überhaupt in deine Variable reinkommen?

Der normale .data-Loader im Startup-Code hat keine Ahnung, dass er
das mit tun sollte.

von ChrisMicro (Gast)


Lesenswert?

Hallo Jörg,

das ganze Prinzip habe ich aus dem Bootloader Artikel übernommen und 
habe gehofft, dass es recht unproblematisch funktioniert:

http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C

In Atmel-Studio 7 habe ich folgendes gemacht
und in Atmeo Studio 7 => Toolchain/AVR_GNU_Linker/Memory 
Settings/Flash-Segment

.bootreset=0

Ich nehme an, dass die von Atmel-Studio erstellten Linker Parameter hier
Beitrag "Re: AVR-GCC: Variable wir leider weg optimiert"

-Wl,-section-start=.bootreset=0

die Variable ins richtige Segment schieben.

Wenn ich in der Main den Code für den Variablenzugriff einfüge, steht 
auch im Flash an der richtigen Stelle der gewünschte Wert.
Insofern löst der Variablenzugriff das Problem, aber es ist meiner 
Ansicht nach ein wenig Murks.

Besser wäre, wenn man im C-Code gleich den RJMP an die richtige Stelle 
assemblieren könnte, anstatt eine Variable zu missbrauchen.

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


Lesenswert?

ChrisMicro schrieb:
> das ganze Prinzip habe ich aus dem Bootloader Artikel übernommen und
> habe gehofft, dass es recht unproblematisch funktioniert

Bei denen sind es aber Flash-Daten.  Ich habe den Eindruck, dass
du versuchst, das im RAM anzulegen (also wirklich als Variable).

Da musst du dir schon die Frage stellen, auf welche Weise die Werte
dann auch ins RAM gelangen.

von Yalu X. (yalu) (Moderator)


Lesenswert?

ChrisMicro schrieb:
>>ich versteht immer noch nicht was du damit machst. Irgendwie musst du
>>sie doch mal verwenden, sonst macht das doch alles keinen sinn.
>
> Sie wird als Reset Vector für einen Bootloader verwendet, genau wie hier
> im Abschnitt Speicherlayout beschrieben:

Das erscheint mir aber extrem hackish. Ich könnte mir vorstellen, dass
dieser Trick mit irgendeiner alten Toolchain-Version funktioniert hat,
aber nicht mehr mit der aktuellen.

Warum nutzt du dafür nicht den Inline-Assembler? Dann musst du auch
nicht den Hexcode für den RJMP-Befehl explizit in dein Programm
schreiben.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

ChrisMicro schrieb:

> Wie kann ich das ändern?

Ich habe gerade ein Ähnliches Problem bei einem nrf52 gelöst, in dem ich 
den Wert einfach im linker script beschrieben habe:
1
MEMORY
2
{
3
    FLASH (rx) : ORIGIN = BOOTLOADER_CODE_BASE, LENGTH = BOOTLOADER_CODE_SIZE
4
    RAM (rwx)  : ORIGIN = BOOTLOADER_RAM_BASE, LENGTH = BOOTLOADER_RAM_SIZE
5
    UICR (r)   : ORIGIN = 0x10001000, LENGTH = 0x400
6
}
7
8
...
9
10
SECTIONS {
11
    .bootloader_addr 0x10001014 :
12
    {
13
        LONG(BOOTLOADER_CODE_BASE)
14
    } > UICR
15
}

von ChrisMicro (Gast)


Angehängte Dateien:

Lesenswert?

>Bei denen sind es aber Flash-Daten.  Ich habe den Eindruck, dass
>du versuchst, das im RAM anzulegen (also wirklich als Variable).
Was mache ich im Vergleich zu denen falsch? Ich dachte, ich habe die 
"section" für die Variable ins Flash gelegt.
Debug mit Debug-Wire zeigt, dass der Wert im Flash steht ( siehe Bild ).

>Das erscheint mir aber extrem hackish.
Das finde ich auch, es ist aber der Weg wie im Artikel beschrieben. Der 
Artikel selbst ist sehr gut gemacht, finde ich. ( Ein Lob an denjenigen, 
der sich die Arbeit gemacht hat )

>Warum nutzt du dafür nicht den Inline-Assembler?
Ich weiß leider nicht, wie es geht.

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


Lesenswert?

ChrisMicro schrieb:
> Debug mit Debug-Wire zeigt, dass der Wert im Flash steht ( siehe Bild ).

Dann verstehe ich deine Aussage („wird wegoptimiert“) nicht.  Wenn
der Wert im Flash liegt, dann ist er doch nicht „wegoptimiert“.

Aber ehrlich gesagt, ist mir auch das gesamte Anliegen nicht so recht
klar.

von ChrisMicro (Gast)


Lesenswert?

>Ich habe gerade ein Ähnliches Problem bei einem nrf52 gelöst, in dem ich
>den Wert einfach im linker script beschrieben habe:

Danke für den Hinweis.
Es scheint also kein so einfaches Problem zu sein.
Tendenziell würde ich es lieber im Code haben und das Linker-Script eher 
weniger verändern.

von ChrisMicro (Gast)


Lesenswert?

>Dann verstehe ich deine Aussage („wird wegoptimiert“) nicht.  Wenn
>der Wert im Flash liegt, dann ist er doch nicht „wegoptimiert“.

Er wird nur dann nicht "wegoptimiert" wenn in der "main" dieser nicht 
benutzte Hilfszugriff steht:
1
 uint16_t x=boot_reset;

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


Lesenswert?

ChrisMicro schrieb:
> Er wird nur dann nicht "wegoptimiert" wenn in der "main" dieser nicht
> benutzte Hilfszugriff steht:

Dann wurde dir aber schon genannt:
1
__attribute__((used))

Sag mal, benutzt du beim Linken sowas wie -Wl,--gc-sections?  Dann
müsstest du dich nicht weiter wundern …

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

ChrisMicro schrieb:
> Es scheint also kein so einfaches Problem zu sein.
> Tendenziell würde ich es lieber im Code haben und das Linker-Script eher
> weniger verändern.

Naja, jetzt hast Du die Definition dieser Konstanten im Flash im Code 
und in den Linker-Parametern stehen. Wenn Du es im Linker-Script 
definierst. Aber wir Jörg auch schon festgestellt hat: Die Konstante 
wird nicht weg optimiert. Wenn irgend etwas nicht funktioniert, dann 
scheint es ein anderes Problem zu sein.

von ChrisMicro (Gast)


Lesenswert?

>Dann wurde dir aber schon genannt:
>__attribute__((used))
Ja, das habe ich hier schon so probiert:
Beitrag "Re: AVR-GCC: Variable wir leider weg optimiert"
Es hat aber nicht funktioniert. Ist es syntaktisch richtig? Es wurde 
kein Warning geworfen.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

ChrisMicro schrieb:
>>Dann wurde dir aber schon genannt:
>>__attribute__((used))
> Ja, das habe ich hier schon so probiert:
> Beitrag "Re: AVR-GCC: Variable wir leider weg optimiert"
> Es hat aber nicht funktioniert. Ist es syntaktisch richtig? Es wurde
> kein Warning geworfen.

Guck doch einfach mal ins Hex-File. Wenn es da drinnen steht, dann hat 
"es" funktioniert.

von ChrisMicro (Gast)


Lesenswert?

>Guck doch einfach mal ins Hex-File. Wenn es da drinnen steht, dann hat
>"es" funktioniert.
Hat es nicht.
Soweit ich es verstehe, ist kein Wert an der Stelle 0 sichtbar:

:101800000EC015C014C013C012C011C010C00FC04C
:101810000EC00DC00CC00BC00AC009C008C0112406
:101820001FBECFE5D2E0DEBFCDBF02D006C0E8CFFD
:0E183000CF93DF93CDB7DEB7FFCFF894FFCF95
:0400000300001800E1
:00000001FF

von ChrisMicro (Gast)


Lesenswert?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
>Sag mal, benutzt du beim Linken sowas wie -Wl,--gc-sections?  Dann
>müsstest du dich nicht weiter wundern …

Tja Jörg, das ist es. Danke. Ohne -Wl, --gc-sections wird es nicht mehr 
weg optimiert.
Allerdings würde ich nicht sagen, dass ich "--gc-sections" benutzt habe, 
sondern Atmel-Studio7.
Dort ist nämlich per default ein kleines, leicht zu übersehendes, 
unschuldig aussehendes Häckchen bei

..Toolchain/AVR_GNU_C Compiler/Optimization/Garbage collect unuses 
sections

macht man es weg, bleibt der Code.

Rein vom Verfahren gefällt mir das Ganze nicht so recht, weil eigentlich 
eine Variable als Code missbraucht wird.

Kann mir jemand sagen, wie man den Inline-Assembler dazu bringt, Code in 
eine bestimmte Section zu schreiben und danach den eigentlichen C-Code 
an eine andere Stelle?

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


Lesenswert?

ChrisMicro schrieb:
> Ohne -Wl, --gc-sections wird es nicht mehr weg optimiert.

Dann macht der Linker genau das, was du ihm gesagt hast.

Mich wundert allerdings, warum das "used"-Attribut nicht dagegen
helfen sollte.

> Allerdings würde ich nicht sagen, dass ich "--gc-sections" benutzt habe,
> sondern Atmel-Studio7.

Kann gut sein.  Diese Optionen (zusammen mit -ffunction-sections)
sind der Faulheit der Leute geschuldet, sauberen Code zu schreiben,
bei dem man nur solche Dinge auch tatsächlich in den Quellen hat,
die man am Ende benötigt.

von Jim M. (turboj)


Lesenswert?

ChrisMicro schrieb:
> Aber leider wird die Variable "boot_reset" einfach weg optimiert.
>
> Wie kann ich das ändern?

Du brauchst dann ein passendes Linker Skript mit einem passenden KEEP() 
Statement.

Deig mal dein aktuelles Linker Skript.

von Yalu X. (yalu) (Moderator)


Lesenswert?

ChrisMicro schrieb:
>>Warum nutzt du dafür nicht den Inline-Assembler?
> Ich weiß leider nicht, wie es geht.

Ich habe den von dir velinkten Artikel nicht komplett gelesen, deswegen
weiß ich nicht im Detail, worauf es bei dem Sprung genau ankommt. Es
scheint aber so, dass er

1. an der Adresse 0 liegen muss (Reset-Vektor) und

2. an den Anfang der (in einen höheren Adressbereich verschobenen)
   Vektortabelle springen soll, wo ein von der Toolchain generierter
   Sprung zum eigentlich Programmstart steht.

Beides erreichts du mit folgender Funktion:

1
void boot_reset(void) __attribute__((naked, section(".bootreset")));
2
void boot_reset(void) {
3
  __asm__(" rjmp __vectors");
4
}

Mit

1
$ avr-gcc -mmcu=attiny85 -Wall -Os -Wl,--section-start=.text=0x1800 \
2
  -Wl,--section-start=.bootreset=0 -o bltest  bltest.c
3
$ avr-objdump -d bltest
4
...
5
Disassembly of section .text:
6
7
00001800 <__vectors>:
8
    1800:       0e c0           rjmp    .+28            ; 0x181e <__ctors_end>
9
...
10
Disassembly of section .bootreset:
11
12
00000000 <boot_reset>:
13
   0:   ff cb           rjmp    .-2050          ; 0xfffff800 <__eeprom_end+0xff7ef800>

Mit -Wl,--gc-sections hast du auch hier das Problem, dass der Linker die
Section .bootreset wegoptimiert. Das used-Attribut wirkt sich nur auf
den Compiler, nicht aber auf den Linker aus, weswegen es hier nicht den
gewünschten Effekt hat. Du musst entweder die Option -Wl,--gc-sections
weglassen, oder ins Linkerscript eine entsprechende KEEP-Anweisung
einfügen.

von Steffen R. (steffen_rose)


Lesenswert?

Jörg W. schrieb:
> ChrisMicro schrieb:
>> Ohne -Wl, --gc-sections wird es nicht mehr weg optimiert.
>
> Dann macht der Linker genau das, was du ihm gesagt hast.
>
> Mich wundert allerdings, warum das "used"-Attribut nicht dagegen
> helfen sollte.

Wirkt das used-Attribut nicht nur auf den Compiler und dessen 
Optimierer?
Der Linker weiß doch davon garnichts. Oder?

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


Lesenswert?

Steffen R. schrieb:
> Wirkt das used-Attribut nicht nur auf den Compiler und dessen
> Optimierer?

Stimmt.  Ich nahm an, dass er das auch dem Linker weiterreichen würde,
aber das ist nicht der Fall.

Damit ist klar, warum der Linker das bei --gc-sections rauskickt.

von Amateur (Gast)


Lesenswert?

Dein Ansatz, auf diese Weise eine Referenz auf den Speicher zu bekommen 
ist nur mit Vorsicht zu genießen.
Die spätere, tatsächliche Adresse kann sich ändern, wenn der Linker ein 
paar Variablen (aus Bibliotheken) davor packt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> ChrisMicro schrieb:
>> Ohne -Wl, --gc-sections wird es nicht mehr weg optimiert.
>
> Dann macht der Linker genau das, was du ihm gesagt hast.
>
> Mich wundert allerdings, warum das "used"-Attribut nicht dagegen
> helfen sollte.

Weil "used" nur auf den Compiler wirkt: Das Objekt wird nicht verwendet, 
wegen "used" aber dennoch angelegt — eine used-Direktive für gas gibt es 
nicht.  Da es nicht referenziert wird und nicht KEEP ist, wird es vom 
Linker entsorgt.

Referenzieren bringt auch nur dann was, wenn es wirklich eine "Senke" 
für die Verwendung gibt, die der Compiler nicht wegoptimieren kann. 
Eine zu simple Verwendung kann durchaus ebenfalls vom Compiler als 
solche erkannt und somit entsorgt werden.

von ChrisMicro (Gast)


Lesenswert?

Autor: Yalu X. (yalu) (Moderator)
>Beides erreichts du mit folgender Funktion: ..

Hallo Yalu, danke dafür. Das scheint mir sehr geeignet. Ich werde es mal 
auf die Art probieren.

Autor: Amateur (Gast)
>Dein Ansatz, auf diese Weise eine Referenz auf den Speicher zu bekommen
>ist nur mit Vorsicht zu genießen.

Der Bootloader sitzt mit

.text=0x1800

an einer fixen Adresse. Das einzige worauf man achten muss, ist dass der 
Wert im Code und die Adresse der "section" Definition für den Linker 
konsistent sind.

Die Zieladresse für den Programmstart muss sich der Bootloader irgendwo 
merken, da immer zuerst der Bootloader angesprungen wird.

von Bernd K. (prof7bit)


Lesenswert?

deklarier es als const (oder diese progmem Sache bei avr), sonst landet 
es nicht im Flash sondern irgendwo im RAM.


Hier ist ein funktionierender  Beispielschnipsel (aus nem ARM Startup 
code), es gibt keinen Grund warum das nicht auch bei AVR funktionieren 
sollte wenn man den Compiler davon überzeugen kann daß er die Konstante 
in den Flash legen soll:
1
#define SECT_FLASHCONF          __attribute__((section(".kinetis_flash_config_field"), __used__))
2
3
4
5
SECT_FLASHCONF const long __flash_config[4] = {
6
    0xffffffff,
7
    0xffffffff,
8
    0xffffffff,
9
    0xfffeffff,
10
};

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


Lesenswert?

Bernd K. schrieb:
> deklarier es als const (oder diese progmem Sache bei avr), sonst landet
> es nicht im Flash sondern irgendwo im RAM.

"const" ist dafür völlig belanglos.  Bei einem AVR landen auch
"const" deklarierte Variable keineswegs automatisch im Flash.

Aber das mit der Flash-Section hat er ja an sich hinbekommen, das
unterscheidet sich bei ihm nicht großartig von deinem Vorschlag.  Der
Dreh- und Angelpunkt war halt die linker section garbage collection.

: Bearbeitet durch Moderator
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.