Wie finde ich zur Kompilierzeit heraus, wie viel Flash-Speicher und dynamischer Speicher (SRAM) eines STM32 verbraucht sind?

Ich habe die Antwort für Flash-Speicher, aber die RAM-Frage entzieht sich mir immer noch.

Arduino hat diese super nette Funktion, die die Flash- und RAM-Nutzung direkt zur Kompilierzeit anzeigt. Ex. In der Abbildung unten sehen Sie, dass dieses Arduino-Programm 2084 Byte Flash (6 %) verwendet und dass globale und statische Variablen 188 Byte (9 %) des dynamischen Speichers oder SRAM verwenden.

Geben Sie hier die Bildbeschreibung ein

Wenn ich ein einfaches Blinkprogramm auf einem STM32F103RB Nucleo-Entwicklungsboard in der System Workbench IDE kompiliere, möchte ich dasselbe wissen: Wie viel Flash und RAM wird verwendet und wie viel bleibt übrig?

Wenn der Bau abgeschlossen ist, zeigt System Workbench Folgendes an:

Generating binary and Printing size information:
arm-none-eabi-objcopy -O binary "STM32F103RB_Nucleo.elf" "STM32F103RB_Nucleo.bin"
arm-none-eabi-size "STM32F103RB_Nucleo.elf"
   text    data     bss     dec     hex filename
   2896      12    1588    4496    1190 STM32F103RB_Nucleo.elf

Wenn ich mir die binäre Ausgabedatei "SW4STM32/Debug/STM32F103RB_Nucleo.bin" ansehe, sehe ich, dass es 2908 Bytes sind, was die Summe von text+ ist data. Daher muss das meine Flash-Nutzung sein! Da ich 128 KB Flash habe, bedeutet das, dass ich 2908/(128*1024) = 2 % des gesamten Flash-Speicherplatzes verwende.

Aber wie finde ich heraus, wie viel SRAM meine globalen und statischen Variablen verwenden und wie viel für lokale Variablen verfügbar ist (wie Arduino zeigt)?

Ich habe noch keine Ahnung, was diese Dinge bedeuten, aber wenn dies hilfreich ist, um Ihnen zu helfen, mir zu helfen , hier ist die Ausgabe von objdump -h STM32F103RB_Nucleo.elf:

$ objdump -h STM32F103RB_Nucleo.elf

STM32F103RB_Nucleo.elf:     file format elf32-little

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .isr_vector   0000010c  08000000  08000000  00010000  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text         00000a1c  0800010c  0800010c  0001010c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       00000028  08000b28  08000b28  00010b28  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .init_array   00000004  08000b50  08000b50  00010b50  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .fini_array   00000004  08000b54  08000b54  00010b54  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  5 .data         00000004  20000000  08000b58  00020000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  6 .bss          00000030  20000004  08000b5c  00020004  2**2
                  ALLOC
  7 ._user_heap_stack 00000604  20000034  08000b5c  00020034  2**0
                  ALLOC
  8 .ARM.attributes 00000029  00000000  00000000  00020004  2**0
                  CONTENTS, READONLY
  9 .debug_info   00006795  00000000  00000000  0002002d  2**0
                  CONTENTS, READONLY, DEBUGGING
 10 .debug_abbrev 000013b2  00000000  00000000  000267c2  2**0
                  CONTENTS, READONLY, DEBUGGING
 11 .debug_loc    00000d0f  00000000  00000000  00027b74  2**0
                  CONTENTS, READONLY, DEBUGGING
 12 .debug_aranges 000002e0  00000000  00000000  00028888  2**3
                  CONTENTS, READONLY, DEBUGGING
 13 .debug_ranges 00000378  00000000  00000000  00028b68  2**3
                  CONTENTS, READONLY, DEBUGGING
 14 .debug_macro  00001488  00000000  00000000  00028ee0  2**0
                  CONTENTS, READONLY, DEBUGGING
 15 .debug_line   00003dcc  00000000  00000000  0002a368  2**0
                  CONTENTS, READONLY, DEBUGGING
 16 .debug_str    00066766  00000000  00000000  0002e134  2**0
                  CONTENTS, READONLY, DEBUGGING
 17 .comment      0000007f  00000000  00000000  0009489a  2**0
                  CONTENTS, READONLY
 18 .debug_frame  00000610  00000000  00000000  0009491c  2**2
                  CONTENTS, READONLY, DEBUGGING

(später hinzugefügt) Siehe auch:

  1. Meine eigene Antwort auf meine eigene Frage hier: Konvertieren Sie die binutils- sizeAusgabe vom „sysv“-Format ( size --format=sysv my_executable) in das „berkeley“-Format ( size --format=berkeley my_executable)
Die dynamische Speichernutzung kann nicht bestimmt werden, ohne jeden möglichen Ausführungspfad zu simulieren. Sie können statische RAM-Zuweisungen bestimmen, aber das schließt sowohl die Stack-Nutzung als auch die dynamische Nutzung vom Typ malloc() aus.
Ja, statische RAM-Zuweisungen sind alles, was ich herauszufinden versuche. Das ist es, was Arduino auch ausgibt, und obwohl es Ihnen nicht sagt, wie Ihr RAM zu allen Zeitpunkten (in der Laufzeit) aussieht, sagt es Ihnen, wie Ihre statische RAM-Zuweisung aussieht, die Sie immer noch erhalten ein gutes Gefühl dafür, wie groß Ihre Anwendung im Verhältnis zu dem Mikrocontroller ist, auf dem sie läuft. Also trotz seiner Einschränkungen verstehe ich, dass ich das bekomme und das ist, was ich will. Danke aber für den ausdrücklichen Hinweis. Es lohnt sich zu verstehen.

Antworten (3)

Die Informationen, die Sie benötigen, sind alle in der Ausgabe von size(auch bekannt als arm-none-eabi-size):

   text    data     bss     dec     hex filename
   2896      12    1588    4496    1190 STM32F103RB_Nucleo.elf
  • textist die Größe des gesamten Codes in Ihrer Anwendung.

  • dataist die Größe initialisierter globaler Variablen. Es zählt sowohl zum Flash-Speicher als auch zum RAM, da es beim Start vom Flash in den RAM kopiert wird.

  • bssist die Größe globaler Variablen, die auf Null initialisiert werden (oder nicht initialisiert sind und daher standardmäßig auf Null gesetzt sind). Sie werden nur im RAM gespeichert.

  • decund hexsind die Summe von text + data + bssdezimal und hexadezimal. Dieser Wert sagt auf einem Mikrocontroller nicht wirklich viel aus und sollte daher ignoriert werden. (In Umgebungen, in denen ein Programm vor der Ausführung in den Speicher geladen werden muss, wäre dies der gesamte Speicherbedarf des Programms.)

Um die RAM-Nutzung Ihres Programms zu berechnen, addieren Sie die Spalten dataund bsszusammen.
SRAM = data + bss

Um die FLASH-Nutzung Ihres Programms zu berechnen, fügen Sie textund hinzu data.
FLASH = text + data

Also, trotz der Tatsache, dass Sie das gesagt haben decund hexdie Größe meiner ELF-Datei sind, ist meine ELF-Datei tatsächlich 616876 Bytes groß. Irgendeine Idee warum?
Für diejenigen, die diese Tatsache möglicherweise übersehen haben (mich selbst anfangs eingeschlossen), befindet sich der Befehl zum Anzeigen dieser Größenwerte direkt in der Ausgabe der System Workbench:arm-none-eabi-size STM32F103RB_Nucleo.elf
Hoppla, ich dachte, es wäre die Größe der Datei, aber es ist eigentlich nur die Summe der Text-/Daten-/BSS-Abschnitte. Es sollte weiterhin ignoriert werden. :)
@duskwuff es ist eigentlich nicht sehr genau. Viele STM32 uC haben mehr als einen RAM (die meisten F3, viele F4, alle F4 & H7). Sie berücksichtigt es nicht. Ein weiteres Problem - der Stack, berücksichtigt es nicht.
@GabrielStaples - elf enthält viel mehr System-, symbolische usw. Konfiguration. Wenn Sie ein hohes Maß an Debugging-Informationen aktivieren, kann Ihre .elf-Datei viele MB lang sein :).
Ich schaue mir das GNU-Linker- Benutzerhandbuch von Steve Chamberlain und Ian Lance Taylor an und schaue auch in meine .ld-Datei für das Linker-Skript. S. 42 (pdf pg 48) des Handbuchs ( Screenshot hier ) zeigt "vier Ausgabeabschnitte", nämlich , .text, .rodata. .dataund .bss. Wird oben durch die Summe dessen dataangezeigt , was in und im Linker-Skript ist? arm-none-eabi-size.rodata.data
Meine obige Frage steht immer noch: wo ist .rodatadas alles?
Auch zu Ihrer Aussage: (In environments where a program must be loaded into memory before running, it would be the total memory footprint of the program.)... Sie meinen wie auf einem normalen Computer, oder? Ich versuche jetzt, diese Werte für ein Programm auf einem normalen Computer zu sehen, anstatt auf einem Mikrocontroller. Scheint also size name_of_executabledie Antwort zu sein. Bsp.: size a.out.
Ich habe hier eine Frage gepostet: stackoverflow.com/q/64073080/4561887 .
Ich habe gerade eine detaillierte Analyse in meine neuen Antworten hier eingefügt: electronic.stackexchange.com/a/523439/26234 und hier: stackoverflow.com/a/64080798/4561887 .

Wenn Sie möchten, dass ein schnelles Linux-Bash-Skript die Flash- und SRAM-Nutzung automatisch für Sie berechnet, lesen Sie meine andere Antwort hier .

TLDR

Springen Sie direkt nach unten zur "Zusammenfassung" ganz unten.

Einzelheiten:

@duskwuff -inactive- hat den Kern meiner Frage in ihrer/seiner Antwort hier beantwortet , aber ich möchte einige zusätzliche Einblicke hinzufügen und auch meine eigenen Folgefragen beantworten, die ich in den Kommentaren unter seiner Antwort geschrieben habe.

Zunächst einmal war der Abschnitt "Grundlegende Linker-Skriptkonzepte" des GNU Linker-Handbuchs , der vollständig in meinem Abschnitt "Referenzen" unten enthalten ist, der Schlüssel zum Erlernen dieser Informationen. Siehe unten in dieser Antwort unten.

Weitere Informationen zu einigen Aspekten dieser Antwort finden Sie auch in meiner anderen Antwort auf eine verwandte Frage, die ich hier zu Stack Overflow gestellt habe .

Es stellt sich heraus, dass die Informationen von objdump -h STM32F103RB_Nucleo.elfdie gleichen, spezifischeren Ausgabeunterabschnitte enthalten wie der arm-none-eabi-size -x --format=sysv "STM32F103RB_Nucleo.elf"Befehl, der die sizeAusgabe im sysvFormat statt im Standardformat anzeigt berkeley.

Hier ist noch einmal die Ausgabe im Berkeley-Format des Befehls size( arm-none-eabi-sizefür STM32 mcus):

arm-none-eabi-size "STM32F103RB_Nucleo.elf"
   text    data     bss     dec     hex filename
   2896      12    1588    4496    1190 STM32F103RB_Nucleo.elf

Beachten Sie, dass dies arm-none-eabi-size "STM32F103RB_Nucleo.elf"äquivalent zu ist arm-none-eabi-size --format=berkeley "STM32F103RB_Nucleo.elf", da --format=berkeleydies die Standardeinstellung ist.

In der objdump -h STM32F103RB_Nucleo.elfAusgabe, die ich in meiner Frage gepostet habe, finden sich alle Informationen, die wir zur Beantwortung meiner Frage benötigen, nur in einem viel detaillierteren Format.

Wie das GNU-Linker-Handbuch erklärt (siehe unten), bedeutet VMA "Virtual Memory Address" und LMA bedeutet "Load Memory Address". Die VMA-Adressen befinden sich dort, wo sich die Daten zur Laufzeit befinden (was sich im flüchtigen SRAM befinden könnte, da einige Daten beim Booten vom Flash in den SRAM kopiert werden), und in der LMA befinden sich die Daten, wenn das Gerät ausgeschaltet ist, und auch vor dem Laden beim Booten (also darf es nur im nichtflüchtigen Flash-Speicher sein ). Einige Daten werden beim Booten vom Flash (LMA-Adresse) zum SRAM (VMA-Adresse) kopiert.

Bei diesem STM32-Mikrocontroller beginnt der Flash-Speicher bei der Adresse 0x08000000und der SRAM bei der Adresse 0x20000000. Alle Ausgabeabschnitte in der objdump -hAusgabe, die eine VMA (Laufzeitadresse) von 0 haben, sind daher unbenutzt (auch nicht auf dem Mikrocontroller) und können sofort verworfen werden. Dadurch wird die zweite Hälfte der objdump -hAusgabe, von der die meisten Debug-Informationen sind, aus dem .ARM.attributesAusgabeabschnitt bis .debug_frameeinschließlich Ausgabeabschnitt eliminiert, sodass wir nur diese sysv-Ausgabeabschnitte haben, die uns interessieren :

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .isr_vector   0000010c  08000000  08000000  00010000  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .text         00000a1c  0800010c  0800010c  0001010c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .rodata       00000028  08000b28  08000b28  00010b28  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .init_array   00000004  08000b50  08000b50  00010b50  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  4 .fini_array   00000004  08000b54  08000b54  00010b54  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  5 .data         00000004  20000000  08000b58  00020000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  6 .bss          00000030  20000004  08000b5c  00020004  2**2
                  ALLOC
  7 ._user_heap_stack 00000604  20000034  08000b5c  00020034  2**0
                  ALLOC

Wie Sie sehen können, wird jeder mit gekennzeichnete Abschnitt READONLYnur im Flash-Speicher an den 0x08000000Adressen auf -Ebene gespeichert und hat dieselbe LMA- und VMA-Adresse. Dies ist sinnvoll, da es nicht erforderlich ist, es in den SRAM zu kopieren, wenn es schreibgeschützt ist. Die markierten Abschnitte READONLYbilden den textAbschnitt im Berkeley-Format. Sie beinhalten:

.isr_vector
.text
.rodata

Wir wissen also:

.isr_vector + .text + .rodata = text

Dies kann durch Summieren ihrer Hex-Größen überprüft werden:

10c + a1c + 28 = b50

0xb50 ist dezimal 2896, was der Berkeley-Size-Ausgabe für den Abschnitt entspricht text! Und wiederum, wie durch die 0x08000000-Level-Adressen für LMA und VMA gezeigt, bedeutet dies, dass sich alle diese Abschnitte nur im Flash-Speicher befinden !

Hier ist meine Beschreibung dessen, was diese Abschnitte sind:

SYSV-ABSCHNITTE, DIE DEN BERKELEY-ABSCHNITT BILDEN textUND DIE NUR IM FLASH-SPEICHER SIND:

  1. .isr_vector= die ISR (Interrupt Service Routine)-Vektortabelle. Es zeigt einfach auf alle ISR-Callback-Funktionen für alle möglichen Interrupts, die der Mikrocontroller verarbeiten kann.
  2. .text= Programmlogik; dh: der eigentliche Code.
  3. .rodata= Nur-Lese-Daten; dh: constund constexprstatische und globale Variablen, die schreibgeschützt sind.

Als nächstes können wir sehen, dass die NON- READONLYAbschnitte, die auch ALLOCund LOADAbschnitte sind, Folgendes enthalten:

.init_array
.fini_array
.data

Wir wissen also, dass sie die Berkeley-Sektion bilden data:

.init_array + .fini_array + .data = data

Dies kann durch Summieren ihrer Hex-Größen überprüft werden:

4 + 4 + 4 = c

0xc ist dezimal 12, was der Berkeley-Size-Ausgabe für den Abschnitt entspricht data.

Ich weiß nicht, was die Abschnitte .init_arrayoder .fini_arraybedeuten (wenn Sie es wissen, antworten Sie bitte oder posten Sie einen Kommentar), und ich bin verwirrt über ihren Standort, da ihre LMA- und VMA-Adressen identisch sind, was darauf hinweist, dass sie sich sowohl in Flash als auch in Flash befinden . Anhand der Adressen des .dataAbschnitts wird jedoch deutlich, dass er sowohl Flash-Speicher (bei LMA [Ladeadresse] = 0x08000b58) als auch SRAM-Speicher (bei VMA [Laufzeitadresse] = 0x20000000) belegt. Dies bedeutet, dass diese Daten vom Flash an den Anfang des SRAM kopiert werden. Dies geschieht während der Startroutine. .dataenthält NICHT-Null-initialisierte (dh mit etwas anderem als Null initialisierte) statische und globale Variablen. In Summe:

SYSV-ABSCHNITTE, DIE DEN BERKELEY- dataABSCHNITT BILDEN UND DIE SOWOHL IN FLASH ALS AUCH IN SRAM SIND UND WÄHREND DES STARTS VON FLASH NACH SRAM KOPIERT WERDEN:

  1. .data= NICHT-Null-initialisierte (dh: mit etwas anderem als Null initialisierte) statische und globale Variablen

SYSV-ABSCHNITTE, DIE DEN BERKELEY- dataABSCHNITT BILDEN UND DIE ANSCHEINEND NUR IM FLASH-SPEICHER SIND?:

  1. .init_array= unbekannt
  2. .fini_array= unbekannt

Damit bleiben uns nur diese mit markierten Abschnitte ALLOCund nichts anderes übrig:

.bss
._user_heap_stack

Wir wissen also, dass sie die Berkeley-Sektion bilden bss:

.bss + ._user_heap_stack = bss

Dies kann durch Summieren ihrer Hex-Größen überprüft werden:

30 + 604 = 634

0x634 ist dezimal 1588, was der Berkeley-Size-Ausgabe für den Abschnitt entspricht bss.

Das ist wirklich interessant! , da es zeigt, dass der Berkeley- bssAbschnitt nicht nur den .bssAusgabeabschnitt (nullinitialisierte statische und globale Variablen) enthält, sondern auch den Ausgabeabschnitt ._user_heap_stack, der vielleicht die Heap-Größe ist (oder mir eher so erscheint). Wir spezifizieren innerhalb der STM32Cube-Konfigurationssoftware. In beiden Fällen scheint es der SRAM zu sein, der sowohl für den Laufzeitstapel (für lokale Variablen) als auch für den Heap (für dynamisch zugewiesenen Speicher) vorgesehen ist. In Summe:

SYSV-ABSCHNITTE, DIE DEN BERKELEY-ABSCHNITT bssBILDEN UND DIE NUR IN SRAM, ABER NICHT IN FLASH, PLATZ BEGINNEN:

  1. .bss= Null-initialisierte statische und globale Variablen; dieses SRAM wird beim Programmstart auf alle Nullen gesetzt.
  2. ._user_heap_stack= (glaube ich) vollständig nicht initialisierter SRAM, der für den Laufzeitstapel (für lokale Variablen) und Heap (für dynamisch zugewiesenen Speicher) vorgesehen ist.

Zusammenfassung:

Hier ist die Aufschlüsselung, welche sysv-Ausgabeabschnitte aus der objdump -h STM32F103RB_Nucleo.elfAusgabe (ebenfalls mit weniger Details in der arm-none-eabi-size -x --format=sysv "STM32F103RB_Nucleo.elf"Ausgabe dargestellt) welche Berkeley-Ausgabeabschnitte bilden.

In der folgenden Abbildung sehen Sie alle 3 Berkely-Ausgabeabschnitte, die in verschiedenen Farben eingerahmt sind:

  1. [GELB] Die Ausgabeabschnitte im Berkeley-Format text(schreibgeschützt, Programmlogik und konstante statische und globale Variablen) sind gelb umrandet .

     .isr_vector + .text + .rodata = text
    
    1. .isr_vector[IN FLASH ONLY] = die ISR (Interrupt Service Routine)-Vektortabelle. Es zeigt einfach auf alle ISR-Callback-Funktionen für alle möglichen Interrupts, die der Mikrocontroller verarbeiten kann.
    2. .text[NUR IN FLASH] = Programmlogik; dh: der eigentliche Code.
    3. .rodata[IN FLASH ONLY] = Nur-Lese-Daten; dh: constund constexprstatische und globale Variablen, die schreibgeschützt sind.
  2. data[BLAU] Die Ausgabeabschnitte im Berkeley-Format (Nicht-Null-initialisierte [dh: mit anderen Werten als Null initialisierte] statische und globale Variablen) sind blau umrandet .

     .init_array + .fini_array + .data = data
    
    1. .init_array[NUR FLASH erscheint] = unbekannt.
    2. .fini_array[NUR FLASH erscheint] = unbekannt.
    3. .data[IN SOWOHL FLASH ALS AUCH SRAM] = NICHT-Null-initialisierte (dh: mit etwas anderem als Null initialisierte) statische und globale Variablen. Diese Werte müssen beim Start vom Flash in den SRAM kopiert werden, um ihre entsprechenden statischen oder globalen Variablen im SRAM zu initialisieren.
  3. bss[ROT] Die Ausgabeabschnitte im Berkeley-Format (mit Null initialisierte statische und globale Variablen und anscheinend auch nicht initialisierter Stack- und Heap-Speicherplatz) sind rot umrandet .

     .bss + ._user_heap_stack = bss
    
    1. .bss[NUR SRAM] = Null-initialisierte statische und globale Variablen; dieses SRAM wird beim Programmstart auf alle Nullen gesetzt.
    2. ._user_heap_stack[NUR SRAM] = vollständig nicht initialisierter (glaube ich) SRAM, der für den Laufzeitstapel (für lokale Variablen) und Heap (für dynamisch zugewiesenen Speicher) vorgesehen ist.
  4. [GRAU] Verworfene Sysv-Ausgabeabschnitte, die zu keinem der 3 Berkeley-Ausgabeabschnitte beitragen, sind grau umrandet .

Geben Sie hier die Bildbeschreibung ein

Speicher Schlussfolgerungen:

  1. Flash-Speicher:
    1. Flash-Speichernutzung = berkeley text+ berkeley data.
      1. Flash-Speicher, der nur von der ISR-Funktionsvektortabelle verwendet wird = .isr_vector.
      2. Nur von der Programmlogik verwendeter Flash-Speicher = .text.
      3. Nur von den schreibgeschützten statischen und globalen Variablen verwendeter Flash-Speicher = .rodata.
  2. SRAM-Speicher:
    1. SRAM-Nutzung aus statischen und globalen Variablen UND zugewiesen für Stack- und Heap-Nutzung = berkeley bss+ berkeley data.
      1. SRAM wird nur von statischen und globalen Variablen verwendet = sysv (.bss + .data). Beachten Sie die Punkte ( .) vor jedem dieser Namen hier, im Gegensatz zu den fehlenden Punkten oben.
      2. SRAM speziell für Stack (lokale Variablen) und Heap (dynamische Speicherzuweisung) = (anscheinend) zugewiesen ._user_heap_stack.
      3. SRAM für nichts zugeteilt = SRAM_total - (berkeley bss + berkeley data).

Verweise:

  1. GNU Linker ( ld) Handbuch, Abschnitt "3.1 Basic Linker Script Concepts": https://sourceware.org/binutils/docs/ld/Basic-Script-Concepts.html#Basic-Script-Concepts :

    3.1 Grundlegende Linker-Skript-Konzepte

    Wir müssen einige grundlegende Konzepte und Vokabeln definieren, um die Linker-Skriptsprache zu beschreiben.

    Der Linker kombiniert Eingabedateien zu einer einzigen Ausgabedatei. Die Ausgabedatei und jede Eingabedatei haben ein spezielles Datenformat, das als Objektdateiformat bekannt ist . Jede Datei wird Objektdatei genannt . Die Ausgabedatei wird oft als ausführbare Datei bezeichnet , aber für unsere Zwecke nennen wir sie auch Objektdatei. Jede Objektdatei hat unter anderem eine Liste von Abschnitten . Wir beziehen uns manchmal auf einen Abschnitt in einer Eingabedatei als Eingabeabschnitt ; ebenso ist ein Abschnitt in der Ausgabedatei ein Ausgabeabschnitt .

    Jeder Abschnitt in einer Objektdatei hat einen Namen und eine Größe. Die meisten Abschnitte haben auch einen zugeordneten Datenblock, der als Abschnittsinhalt bekannt ist . Ein Abschnitt kann als ladbar markiert sein , was bedeutet, dass der Inhalt in den Speicher geladen werden sollte, wenn die Ausgabedatei ausgeführt wird. Ein Abschnitt ohne Inhalt kann allokierbar sein, was bedeutet, dass ein Bereich im Speicher reserviert, aber nichts Besonderes dort geladen werden sollte (in einigen Fällen muss dieser Speicher auf Null gesetzt werden). Ein Abschnitt, der weder ladbar noch zuweisbar ist, enthält typischerweise irgendeine Art von Debugging-Informationen.

    Jeder ladbare oder belegbare Ausgangsabschnitt hat zwei Adressen. Die erste ist die VMA oder virtuelle Speicheradresse. Dies ist die Adresse, die der Abschnitt haben wird, wenn die Ausgabedatei ausgeführt wird. Die zweite ist die LMA oder Ladespeicheradresse. Dies ist die Adresse, an der der Abschnitt geladen wird. In den meisten Fällen sind die beiden Adressen identisch. Ein Beispiel dafür, wann sie unterschiedlich sein könnten, ist, wenn ein Datenabschnitt in den ROM geladen und dann beim Programmstart in den RAM kopiert wird (diese Technik wird häufig verwendet, um globale Variablen in einem ROM-basierten System zu initialisieren). In diesem Fall wäre die ROM-Adresse der LMA und die RAM-Adresse der VMA.

    Sie können die Abschnitte in einer Objektdatei anzeigen, indem Sie das objdumpProgramm mit der Option „-h“ verwenden.

    Jede Objektdatei hat auch eine Liste von Symbolen , die als Symboltabelle bekannt ist . Ein Symbol kann definiert oder undefiniert sein. Jedes Symbol hat neben anderen Informationen einen Namen und jedes definierte Symbol hat eine Adresse. Wenn Sie ein C- oder C++-Programm in eine Objektdatei kompilieren, erhalten Sie ein definiertes Symbol für jede definierte Funktion und globale oder statische Variable. Jede undefinierte Funktion oder globale Variable, auf die in der Eingabedatei verwiesen wird, wird zu einem undefinierten Symbol.

    Sie können die Symbole in einer Objektdatei sehen nm, indem Sie das Programm verwenden oder indem Sie das objdumpProgramm mit der Option „-t“ verwenden.

  2. Meine eigene Antwort auf meine eigene Frage hier: Konvertieren Sie die binutils- sizeAusgabe vom „sysv“-Format ( size --format=sysv my_executable) in das „berkeley“-Format ( size --format=berkeley my_executable)

.init_arrayund .fini_array-- Bei globalen Variablen in C++ werden der Konstruktor und der Destruktor ausgeführt, bevor die Ausführung von main beginnt bzw. nach dem Beenden von main. Diese beiden Abschnitte enthalten (Zeiger auf) Konstruktions- und Zerstörungsfunktionen, die von der Laufzeitunterstützungsbibliothek aufgerufen werden müssen. Reiner ISO-Standard C hat so etwas nicht (Sie können eine globale C-Variable nicht mit einem dynamischen Ausdruck initialisieren), aber gcc fügt sie als Erweiterung zu C hinzu, indem Sie __attribute((constructor))__and verwenden __attribute__((destructor)).

Skript/Befehl zur automatischen Berechnung der Flash- und SRAM-Nutzung für Sie

Als Erweiterung der beiden anderen Antworten, einschließlich meiner eigenen , ist hier ein 1-zeiliges Linux-Bash-Skript, mit dem Sie automatisch berechnen FLASHund verwenden können SRAM.

Dies setzt voraus, dass Ihr Befehl zum Anzeigen der Berkeley-Größeninformationen Ihrer .elf-Datei arm-none-eabi-size "STM32F103RB_Nucleo.elf". Aktualisieren Sie diesen Pfad zu Ihrer gewünschten .elf-Datei. Wenn Sie Linux-.elf-Dateien oder reguläre ausführbare Dateien anstelle von STM32-.elf-Dateien betrachten, verwenden Sie sizeanstelle von arm-none-eabi-size. Bsp.: size path/to/my_program.elf.

Wie auch immer, hier ist das Skript:

size_info=$(arm-none-eabi-size "STM32F103RB_Nucleo.elf" | awk NR\>1); \
text=$(echo "$size_info" | awk '{print $1}'); \
data=$(echo "$size_info" | awk '{print $2}'); \
bss=$(echo "$size_info" | awk '{print $3}'); \
flash=$(($text + $data)); \
sram=$(($bss + $data)); \
echo "FLASH used                    = $flash bytes"; \
echo "SRAM used by global variables = $sram bytes"

Angenommen, das arm-none-eabi-size "STM32F103RB_Nucleo.elf"zeigt dies:

text    data     bss     dec     hex filename
2896      12    1588    4496    1190 STM32F103RB_Nucleo.elf

...hier ist eine Beispielausgabe der Ausführung des obigen Skripts:

FLASH used                    = 2908 bytes
SRAM used by global variables = 1600 bytes

Aufschlüsselung von Flash, SRAM und den 3 Berkely-Abschnitten

  • Flash und SRAM:
    • FLASH = text + data
    • SRAM = bss + data
  • Die 3 Berkeley-Sektionen:
    • text= Programmdaten + ISR-Vektor + Rodata (Nur-Lese-Daten: constund constexprstatische und globale Nur-Lese-Variablen)
    • data= NICHT-Null-initialisierte (dh: mit einer anderen Zahl als Null initialisierte) statische und globale Variablen, + .init_array + .fini_array
    • bss= Null-initialisierte statische und globale Variablen + Stack- und Heap-Platz, der vom Linker-Skript reserviert wird

Weitere Details finden Sie in meiner anderen, sehr detaillierten Antwort hier: Wie finde ich zur Kompilierzeit heraus, wie viel Flash-Speicher und dynamischer Speicher (SRAM) eines STM32 verbraucht sind?

Verweise:

  1. Die Hauptantwort: Wie finde ich zur Kompilierzeit heraus, wie viel Flash-Speicher und dynamischer Speicher (SRAM) eines STM32 verbraucht sind?
  2. meine andere Antwort: Wie finde ich zur Kompilierzeit heraus, wie viel Flash-Speicher und dynamischer Speicher (SRAM) eines STM32 verbraucht sind?
  3. wie man Zahlen in Bash hinzufügt: https://stackoverflow.com/questions/6348902/how-can-i-add-numbers-in-a-bash-script/6348941#6348941
  4. Anleitung awkzum Entfernen der ersten Zeile eines Text-Blobs: https://superuser.com/questions/284258/remove-first-line-in-bash/284270#284270
  5. allgemeines awkBeispiel aus meinen eigenen Notizen , um mich daran zu erinnern, wie man es benutzt:du -h | tail -n 1 | awk '{print $1}'