mikrocontroller.net

Forum: Compiler & IDEs GCC: Variable wird trotz 'KEEP' im Linkerscript wegoptimiert?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

für die Programmierung eines STM32 verwende ich Atollic Truestudio, also 
GCC drunterliegend und bastle mir gerade die Option Bytes direkt ins ELF 
bzw. HEX File.

Hierfür habe ich das Linkerscript wie folgt modifiziert:
...
MEMORY
{
  ...
  OPT_BYTES (r)   : ORIGIN = 0x1FF80000, LENGTH = 32
}

/* Define output sections */
SECTIONS
{
  /* user option bytes */
  .opt_bytes :
  {
    . = ALIGN(4);
    KEEP(*(.FLASH_OPTR_L*)) /* FLASH_OPTR register */
    KEEP(*(.FLASH_OPTR_H*))
    KEEP(*(.FLASH_WRPROT1_L*)) /* FLASH_WRPROT1 register */
    KEEP(*(.FLASH_WRPROT1_H*))
    KEEP(*(.FLASH_WRPROT2_L*)) /* FLASH_WRPROT2 register */
  } >OPT_BYTES
  ...
Die Variablen hatte ich ursprünglich wie folgt angelegt:
const uint32_t FLASH_OPTR_L __attribute__((section(".FLASH_OPTR_L"))) = 0x20DF55AA;
Im Debug-Build taucht's korrekt im ELF/HEX-File auf, im Release ist es 
wohl wegoptimiert.
Abhilfe schafft das Attribut 'used':
const uint32_t FLASH_OPTR_L __attribute__((section(".FLASH_OPTR_L"))) __attribute__((used)) = 0x20DF55AA;
Ob das ganze nun denn auch so die gewünschte Wirkung erzielt muss ich 
noch ausprobieren, was mich gerade interessiert ist, warum ich die 
Variablen zusätzlich mit dem Attribut 'used' belegen muss, wenn ich doch 
im Linkerscript die Sektionen schon mit KEEP markiert habe - ich bin da 
nun einfach neugierig :)
Kann's mir jemand erklären?

Gruß Ralf

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Ralf schrieb:
> was mich gerade interessiert ist, warum ich die Variablen
> zusätzlich mit dem Attribut 'used' belegen muss, wenn ich doch
> im Linkerscript die Sektionen schon mit KEEP markiert habe

Davon weiß GCC aber nix.

"used" wirkt auf Compiler-Ebene.

"KEEP" wirkt auf Linker-Ebene.

Wenn globale Optimierungen aktiviert sind, dann kann GCC nicht 
referenzierte Objekte / Funktionen entsorgen.  Gleiches gilt auch auf 
Ebene einer Compilation Unit, wenn der Compiler die Nichtreferenzierung 
auf dieser Ebene nachweisen kann.

Der Linker arbeitet nur mit Symbolen und Input- und Output-Sections. 
Wenn aus einer bestimmten Input-Section keine Symbole referenziert 
werden, dann kann der Linker diese Section mit --gc-sections entsorgen 
falls nicht mit KEEP markiert.  Dabei gilt des Entry-Symbol als 
referenziert.

In deinem Falle braucht's auf Linker-Ebene ein KEEP und auf 
Compiler-Ebene
__attribute__((__used__,__externally_visible__))

: Bearbeitet durch User
Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, okay. Dann hab ich ja die richtige Lösung verwendet.

>> In deinem Falle braucht's auf Linker-Ebene ein KEEP und auf
>> Compiler-Ebene
>> __attribute__((_used_,__externally_visible__))
Das muss ich mal probieren, ob ich das zweimalige _attribute_ 
wegbekomme.

Besten Dank.

Ralf

Autor: Blume (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du kannst auch mal testen ob es reicht deine Variable zusätzlich

extern zu deklarieren:
extern const uint32_t FLASH_OPTR_L;

vielleicht in einem Header File das inkludiert wird.


Das hat bei mir in ähnlichen Situationen geholfen.

- Blume

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab das bei nem Freescale mal so gelöst:

C-Code:
#define SECT_FLASHCONF          __attribute__((section(".kinetis_flash_config_field"), __used__))
SECT_FLASHCONF const long __flash_config[4] = {
    0xffffffff,
    0xffffffff,
    0xffffffff,
    0xfffeffff,
};

Linkerscript:
MEMORY
{
  VECTORS           (rx) : ORIGIN = 0x00000000, LENGTH = 0x00000400
  FLASH_PROTECTION  (rx) : ORIGIN = 0x00000400, LENGTH = 0x00000010
  FLASH             (rx) : ORIGIN = 0x00000410, LENGTH = 8K - 0x00000410
  RAM              (rwx) : ORIGIN = 0x1FFFFF00, LENGTH = 1K
}
    .flash_protect :
    {
        KEEP(*(.kinetis_flash_config_field))
    } > FLASH_PROTECTION

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist das nicht ein prima use case für das (anscheinend in sich 
widersprüchliche)
const volatile
???

Sollte eigentlich den Compiler ("ich habe nicht vor, da was dran zu 
ändern, aber möglicherweise jemand anders") davon abhalten, die Variable 
zu entsorgen.

Autor: A. B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralf schrieb:

> für die Programmierung eines STM32 verwende ich Atollic Truestudio, also
> GCC drunterliegend und bastle mir gerade die Option Bytes direkt ins ELF
> bzw. HEX File.

Das ist zwar an sich eine schöne Idee, es ist schon ärgerlich, dass die 
Option-Bytes immer "nebenher" laufen. Allerdings wird das nicht so 
einfach zum Ziel führen:

Die Option-Bytes werden nicht über die "normale" Flash-Programmierung 
beschrieben, sondern mittels Schreiben in die Flash-Option-**Register**.
Dabei werden die "echten" Flash-Zellen zuerst gelöscht und danach die 
"aufgebohrten" Werte (d .h. zusätzlich auch noch die invertierten Werte) 
in die Flash-Zellen geschrieben.

Das Konzept mit den Option-Bytes im Elf-File würde nur funktionieren, 
wenn der Flash-Programmer die Option-Bytes da herausfischt und sie dann 
in die entsprechenden Register schreibt. Müsste man für jeden Chip 
individuell einbauen ...

Bei der Kinetis-Familie ist das etwas schöner gelöst, hat aber auch 
wieder unschöne Seiteneffekte, da ein Erase dann gleich alle 
Option-Bytes mit löscht.

Autor: Bauform B. (bauformb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. B. schrieb:
> Die Option-Bytes werden nicht über die "normale" Flash-Programmierung
> beschrieben, sondern mittels Schreiben in die Flash-Option-**Register**.

> Das Konzept mit den Option-Bytes im Elf-File würde nur funktionieren,
> wenn der Flash-Programmer die Option-Bytes da herausfischt und sie dann
> in die entsprechenden Register schreibt.

Macht der eingebaute UART-Bootloader in den STM32 nicht genau das?

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. B. schrieb:
> Das Konzept mit den Option-Bytes im Elf-File würde nur funktionieren,
> wenn der Flash-Programmer die Option-Bytes da herausfischt und sie dann
> in die entsprechenden Register schreibt. Müsste man für jeden Chip
> individuell einbauen ...

Eine Alternative (falls er sie nicht wie ein Kinetis beim Reset 
automatisch aus dem Flash liest) ist es am Anfang der Main (oder im 
Startup oder wo auch immer es gut passt) den Zustand der Option-Bytes zu 
prüfen und sie ggf. dann auf die dafür vorgesehene Weise zu setzen. Dann 
muss man sein Gerät halt mindestens einmal einschalten bevor man es 
verkauft. Für den Debugbuild muss man diese Routine halt deaktivieren.

Autor: M.K. B. (mkbit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralf schrieb:
> Ob das ganze nun denn auch so die gewünschte Wirkung erzielt muss ich
> noch ausprobieren, was mich gerade interessiert ist, warum ich die
> Variablen zusätzlich mit dem Attribut 'used' belegen muss, wenn ich doch
> im Linkerscript die Sektionen schon mit KEEP markiert habe - ich bin da
> nun einfach neugierig :)

Ich habe noch nicht ganz verstanden, was du mit der Variable erreichen 
willst. Wenn der Compiler die aber wegoptimiert, dann war sie entweder 
überflüssig (also warum dann erzwingen) oder nicht richtig als volatile 
gekennzeichnet und der Compiler hat es wegoptimiert. Bei zweitem bin ich 
mir nicht sicher, ob das used reicht, wenn der Compiler dann trotzdem 
den Code zum setzen löscht.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M.K. B. schrieb:

> Ich habe noch nicht ganz verstanden, was du mit der Variable erreichen
> willst.

Er will daß diese Konstante genau an der Stelle im Flash zu liegen kommt 
wo diese Werte die gewünschte Wirkung erzielen. Bei einigen Controllern, 
zum Beispiel bei den oben kurz erwähnten Kinetis-Controllern gibts 16 
Bytes im Flash bei Adresse 0x400 kurz hinter der Vektortabelle damit 
werden die Lockbits gesetzt und noch ein paar andere Optionen. Bei jeden 
Einschalten wird das als erstes gelesen und die Flash Security und noch 
ein paar andere Sachen entsprechend gesetzt. So ähnlich wie die Fuses 
beim AVR (die man dort allerdings separat setzen muss), nur liegen sie 
in dem Fall als ganz normale Bits im Programmflash und man kann dann 
direkt ins .bin reinbacken und die werden dann immer gleich in einem 
Rutsch vollautomatisch an die richtige Stelle geflasht.

Allerdings ist der Einwand des anderen Users weiter oben nicht 
unberechtigt, es mag durchaus sein daß das bei STM32 nicht ganz so 
simpel funktioniert wie beim Kinetis, STM32 sind in jeder Hinsicht 
weitaus komplizierter zu handhaben und alles ist intern deutlich 
verschwurbelter organisiert als bei den simplen Kinetis-Controllern wo 
alles ziemlich direkt und geradeaus ist, von STM32 kommt der Mythos daß 
"ARM kompliziert" sei. Wer den ersten Kontakt allerdings mit einem 
Kinetis erlebt hat kann darüber nur den Kopf schütteln, aber lassen wir 
das, ich schweife ab...

> bin ich
> mir nicht sicher, ob das used reicht,

KEEP und used reicht, das funktioniert wie dokumentiert. Auch für andere 
Zwecke ist das verwendbar, zum Beispiel eine Konfiguration des 
Bootloaders die beim Flashen des Bootloaders einmalig eingebrannt wird 
(zum Beispiel für eine I2C-Adresse oder eine Seriennummer oder 
dergleichen) und die später auch von der Anwendung gelesen werden kann 
schon beim Flashen der Bootloader.bin an eine fixe Stelle ins Flash zu 
legen.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.