¿Cómo averiguo en tiempo de compilación qué cantidad de memoria Flash y memoria dinámica (SRAM) de un STM32 se utiliza?

Tengo la respuesta para la memoria Flash, pero la pregunta sobre la memoria RAM aún se me escapa.

Arduino tiene esta característica súper agradable que muestra el uso de flash y RAM justo en el momento de la compilación. Ex. en la imagen de abajo puedes ver que este programa Arduino usa 2084 bytes de flash (6%) y que las variables globales y estáticas usan 188 bytes (9%) de memoria dinámica o SRAM.

ingrese la descripción de la imagen aquí

Cuando compilo un programa de parpadeo simple en una placa de desarrollo Nucleo STM32F103RB en el IDE de System Workbench, me gustaría saber lo mismo: ¿cuánto Flash y RAM se usan y cuánto queda?

Cuando finaliza la construcción, System Workbench muestra:

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

Cuando miro el archivo de salida binario, "SW4STM32/Debug/STM32F103RB_Nucleo.bin", veo que tiene 2908 bytes, que es la suma de text+ data. Por lo tanto, ¡ese debe ser mi uso de Flash! Dado que tengo 128 KB de Flash, eso significa que estoy usando 2908/(128*1024) = 2 % del espacio total de Flash.

Pero, ¿cómo averiguo cuánta SRAM están usando mis variables globales y estáticas, y cuánto está disponible para las variables locales (como muestra Arduino)?

Todavía no tengo ni idea de lo que significa nada de esto, pero si esto es útil para ayudarlo a ayudarme , aquí está el resultado de 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

(Agregado más tarde) Ver también:

  1. Mi propia respuesta a mi propia pregunta aquí: convertir sizela salida de binutils del formato "sysv" ( size --format=sysv my_executable) al formato "berkeley" ( size --format=berkeley my_executable)
El uso de la memoria dinámica no se puede determinar sin simular todas las rutas posibles de ejecución. Puede determinar las asignaciones de RAM estáticas, pero eso excluye tanto el uso de la pila como el uso dinámico del tipo malloc().
Sí, las asignaciones de RAM estática es todo lo que estoy tratando de averiguar. Eso es lo que Arduino también está generando, y aunque no le dice cómo se ve su RAM en todos los puntos en el tiempo (en tiempo de ejecución), sí le dice cómo se ve su asignación de RAM estática, que todavía le da una buena idea de cuán grande es su aplicación en relación con el microcontrolador en el que se ejecuta. Entonces, a pesar de sus limitaciones, entiendo que eso es lo que obtengo y eso es lo que quiero. Sin embargo, gracias por señalar esto explícitamente. Vale la pena entender.

Respuestas (3)

La información que necesita está toda en la salida de size(aka arm-none-eabi-size):

   text    data     bss     dec     hex filename
   2896      12    1588    4496    1190 STM32F103RB_Nucleo.elf
  • textes el tamaño de todo el código en su aplicación.

  • dataes el tamaño de las variables globales inicializadas. Cuenta contra la memoria flash y la RAM, ya que se copia de la memoria flash a la RAM durante el inicio.

  • bsses el tamaño de las variables globales que se inicializan en cero (o no se inicializan y, por lo tanto, el valor predeterminado es cero). Se almacenan solo en RAM.

  • decy hexson la suma de text + data + bssen decimal y hexadecimal. Este valor realmente no significa mucho en un microcontrolador, por lo que debe ignorarse. (En entornos donde un programa debe cargarse en la memoria antes de ejecutarse, sería la huella de memoria total del programa).

Para calcular el uso de RAM de su programa, sume las columnas datay bssjuntas.
SRAM = data + bss

Para calcular el uso de FLASH de su programa, agregue texty data.
FLASH = text + data

Entonces, a pesar de que dijiste eso decy hexson del tamaño de mi archivo ELF, mi archivo ELF es en realidad 616876 bytes. ¿Alguna idea de por qué?
Además, para aquellos que pueden haber pasado por alto este hecho (incluido yo mismo inicialmente), el comando para ver estos valores de tamaño está justo en la salida de System Workbench:arm-none-eabi-size STM32F103RB_Nucleo.elf
Vaya, pensé que era el tamaño del archivo, pero en realidad es solo la suma de las secciones de texto/datos/bss. Todavía debe ser ignorado. :)
@duskwuff en realidad no es muy preciso. Muchos STM32 uC tienen más de una RAM (la mayoría de F3, muchos F4, todos F4 y H7). No lo toma en consideración. Otro problema: la pila, no lo tiene en cuenta.
@GabrielStaples: elf contiene mucho más sistema, configuración simbólica, etc. Si habilita un alto nivel de información de depuración, su archivo .elf puede tener muchos MB :).
Estoy mirando el manual de usuario del enlazador GNU , por Steve Chamberlain e Ian Lance Taylor, así como mi archivo .ld del script del enlazador. pág. 42 (pdf pg 48) del manual ( captura de pantalla aquí ) muestra "cuatro secciones de salida", a saber, .text, .rodata, .data. y .bss. ¿ Se datamuestra arriba por arm-none-eabi-sizela suma de lo que está en .rodatay .dataen el script del enlazador?
Mi pregunta anterior sigue en pie: ¿dónde está .rodatatodo esto?
Además, con respecto a su declaración: (In environments where a program must be loaded into memory before running, it would be the total memory footprint of the program.).... quiere decir como en una computadora normal, ¿verdad? Estoy tratando de ver estos valores para un programa en una computadora normal ahora, en lugar de en un microcontrolador. Entonces, size name_of_executableparece ser la respuesta. Ej: size a.out.
He publicado una pregunta aquí: stackoverflow.com/q/64073080/4561887 .
Acabo de agregar un análisis detallado en mis nuevas respuestas aquí: electronics.stackexchange.com/a/523439/26234 y aquí: stackoverflow.com/a/64080798/4561887 .

Si desea un script bash de Linux rápido para calcular automáticamente el uso de Flash y SRAM, vea mi otra respuesta aquí .

TLDR

Vaya directamente al "Resumen" en la parte inferior.

Detalles:

@duskwuff -inactive- respondió el quid de mi pregunta en su respuesta aquí , pero me gustaría agregar información adicional y también responder mis propias preguntas de seguimiento que escribí en los comentarios debajo de su respuesta.

En primer lugar, la sección "Conceptos básicos de secuencias de comandos de Linker" del manual de GNU Linker , incluida en su totalidad en mi sección "Referencias" a continuación, fue clave para aprender esta información. Consúltelo en la parte inferior de esta respuesta, a continuación.

Para una mirada más detallada a algunos de los aspectos de esta respuesta, consulte también mi otra respuesta a una pregunta relacionada que hice en Stack Overflow aquí .

Resulta que la información de objdump -h STM32F103RB_Nucleo.elfcontiene las mismas subsecciones de salida más específicas que el arm-none-eabi-size -x --format=sysv "STM32F103RB_Nucleo.elf"comando, que muestra la sizesalida en el sysvformato en lugar del berkeleyformato predeterminado.

Aquí nuevamente está la salida en formato berkeley del comando size( arm-none-eabi-sizepara STM32 mcus):

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

Tenga en cuenta que arm-none-eabi-size "STM32F103RB_Nucleo.elf"es equivalente a arm-none-eabi-size --format=berkeley "STM32F103RB_Nucleo.elf", ya que --format=berkeleyes el valor predeterminado.

En el objdump -h STM32F103RB_Nucleo.elfresultado que publiqué en mi pregunta, se encuentra toda la información que necesitamos para responder mi pregunta, solo que en un formato mucho más detallado.

Como explica el manual del enlazador GNU (ver más abajo), VMA significa "Dirección de memoria virtual" y LMA significa "Dirección de memoria de carga". Las direcciones VMA son donde se ubican los datos en tiempo de ejecución (que podría estar en SRAM volátil, ya que algunos datos se copian de Flash a SRAM en el arranque), y LMA es donde se ubican los datos cuando el dispositivo está apagado, y también antes de cargar en el arranque (por lo que debe estar solo en la memoria Flash no volátil ). Algunos datos se copiarán de Flash (dirección LMA) a SRAM (dirección VMA) en el arranque.

Para este microcontrolador STM32, la memoria Flash comienza en la dirección 0x08000000y la SRAM comienza en la dirección 0x20000000. Por lo tanto, cualquier sección de salida en la objdump -hsalida que tenga un VMA (dirección de tiempo de ejecución) de 0, por lo tanto, no se utiliza (ni siquiera en el microcontrolador) y se puede descartar de inmediato. Eso elimina la segunda mitad de la objdump -hsalida, la mayor parte de la cual es información de depuración, desde la .ARM.attributessección de salida hasta la .debug_framesección de salida, inclusive, dejándonos solo con estas secciones de salida de sysv que nos interesan :

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

Cualquier sección marcada READONLY, como puede ver, se almacena solo en la memoria Flash en las 0x08000000direcciones de nivel y tiene la misma dirección LMA y VMA. Esto tiene sentido, ya que no es necesario copiarlo en SRAM si es de solo lectura. Las secciones marcadas READONLYconforman la textsección de formato berkeley. Incluyen:

.isr_vector
.text
.rodata

Entonces, sabemos que:

.isr_vector + .text + .rodata = text

Esto se puede verificar sumando sus tamaños hexadecimales:

10c + a1c + 28 = b50

¡0xb50 es el decimal 2896, que coincide con la salida del tamaño de berkeley para la textsección! Y, nuevamente, como lo muestran las 0x08000000direcciones de nivel tanto para LMA como para VMA, ¡esto significa que todas estas secciones están solo en la memoria Flash !

Aquí está mi descripción de lo que son estas secciones:

SECCIONES SYSV QUE COMPONEN LA textSECCIÓN BERKELEY Y QUE ESTÁN EN LA MEMORIA FLASH SOLAMENTE:

  1. .isr_vector= la tabla de vectores ISR (rutina de servicio de interrupción). Simplemente apunta a todas las funciones de devolución de llamada ISR para todas las posibles interrupciones que el microcontrolador puede manejar.
  2. .text= lógica del programa; es decir: el código real.
  3. .rodata= Datos de solo lectura; es decir: consty constexprvariables estáticas y globales que son de solo lectura.

A continuación, podemos ver que las READONLYsecciones NO que también son ALLOCy LOADsecciones incluyen:

.init_array
.fini_array
.data

Entonces, sabemos que conforman la datasección de berkeley:

.init_array + .fini_array + .data = data

Esto se puede verificar sumando sus tamaños hexadecimales:

4 + 4 + 4 = c

0xc es el decimal 12, que coincide con la salida de tamaño berkeley para la datasección.

No sé qué significan las secciones .init_arrayo .fini_array(si lo sabe, responda o publique un comentario), y estoy confundido sobre su ubicación, ya que sus direcciones LMA y VMA son idénticas, lo que indica que ambas están en Flash y solo en Flash. . Sin embargo, está claro por las direcciones de la .datasección, que ocupa tanto la memoria Flash (en LMA [dirección de carga] = 0x08000b58) como la memoria SRAM (en VMA [dirección de tiempo de ejecución] = 0x20000000). Esto significa que estos datos se copian de Flash al comienzo de SRAM. Esto sucede durante la rutina de inicio. .datacontiene variables estáticas y globales no inicializadas en cero (es decir, inicializadas con algo distinto de cero). En resumen:

SECCIONES SYSV QUE COMPONEN LA dataSECCIÓN BERKELEY Y QUE ESTÁN TANTO EN FLASH COMO SRAM, Y QUE SE COPIAN DE FLASH A SRAM DURANTE EL INICIO:

  1. .data= NON-zero-inicializado (es decir: inicializado con algo distinto de cero) variables estáticas y globales

¿SECCIONES SYSV QUE COMPONEN LA dataSECCIÓN BERKELEY Y QUE APARENTEMENTE ESTÁN SÓLO EN LA MEMORIA FLASH?:

  1. .init_array= desconocido
  2. .fini_array= desconocido

Eso nos deja solo con estas secciones marcadas con ALLOCy nada más restante:

.bss
._user_heap_stack

Entonces, sabemos que conforman la bsssección de berkeley:

.bss + ._user_heap_stack = bss

Esto se puede verificar sumando sus tamaños hexadecimales:

30 + 604 = 634

0x634 es el decimal 1588, que coincide con la salida de tamaño berkeley para la bsssección.

¡Esto es realmente interesante! , ya que muestra que la bsssección berkeley no solo incluye la .bsssección de salida (variables estáticas y globales inicializadas en cero), sino que también incluye la ._user_heap_stacksección de salida, que es quizás (o más bien, me parece ser) el tamaño del montón especificamos dentro del software de configuración STM32Cube. En cualquier caso, parece ser la SRAM reservada tanto para la pila de tiempo de ejecución (para las variables locales) como para el almacenamiento dinámico (para la memoria asignada dinámicamente). En resumen:

SECCIONES SYSV QUE COMPONEN LA bssSECCIÓN BERKELEY Y QUE OCUPAN ESPACIO SOLO EN SRAM, PERO NO EN FLASH:

  1. .bss= variables estáticas y globales inicializadas en cero; esta SRAM se establece en ceros al inicio del programa.
  2. ._user_heap_stack= (Creo) SRAM completamente sin inicializar que se reserva para la pila de tiempo de ejecución (para variables locales) y el montón (para memoria asignada dinámicamente).

Resumen:

Aquí está el desglose de las secciones de salida de sysv de la objdump -h STM32F103RB_Nucleo.elfsalida (que también se muestran con menos detalles en la arm-none-eabi-size -x --format=sysv "STM32F103RB_Nucleo.elf"salida) que componen las secciones de salida de berkeley.

En la imagen a continuación, puede ver las 3 secciones de salida de berkely enmarcadas en diferentes colores:

  1. [AMARILLO] Las secciones de salida en formato berkeley text(solo lectura, lógica de programa y variables estáticas y globales constantes) están enmarcadas en amarillo .

     .isr_vector + .text + .rodata = text
    
    1. .isr_vector[SOLO EN FLASH] = la tabla de vectores ISR (rutina de servicio de interrupción). Simplemente apunta a todas las funciones de devolución de llamada ISR para todas las posibles interrupciones que el microcontrolador puede manejar.
    2. .text[SOLO EN FLASH] = lógica del programa; es decir: el código real.
    3. .rodata[SOLO EN FLASH] = datos de solo lectura; es decir: consty constexprvariables estáticas y globales que son de solo lectura.
  2. [AZUL] Las secciones de salida en formato berkeley data(variables estáticas y globales inicializadas distintas de cero [es decir, inicializadas con valores distintos de cero]) están encuadradas en azul .

     .init_array + .fini_array + .data = data
    
    1. .init_array[Aparece SOLO FLASH] = desconocido.
    2. .fini_array[Aparece SOLO FLASH] = desconocido.
    3. .data[EN AMBOS FLASH Y SRAM] = Variables estáticas y globales inicializadas distintas de cero (es decir, inicializadas con algo distinto de cero). Estos valores deben copiarse de Flash a SRAM al inicio, para inicializar sus correspondientes variables estáticas o globales en SRAM.
  3. [ROJO] Las secciones de salida en formato berkeley bss(variables estáticas y globales inicializadas en cero, y también, aparentemente, espacio de pila y pila no inicializado) están enmarcadas en rojo .

     .bss + ._user_heap_stack = bss
    
    1. .bss[SOLO SRAM] = variables estáticas y globales inicializadas en cero; esta SRAM se establece en ceros al inicio del programa.
    2. ._user_heap_stack[SOLO SRAM] = SRAM completamente sin inicializar (creo) que se reserva para la pila de tiempo de ejecución (para variables locales) y el montón (para memoria asignada dinámicamente).
  4. [GRIS] Las secciones de salida de sysv desechadas que no contribuyen a ninguna de las 3 secciones de salida de berkeley están encuadradas en gris .

ingrese la descripción de la imagen aquí

Conclusiones de la memoria:

  1. Memoria flash:
    1. Uso de memoria flash = berkeley text+ berkeley data.
      1. Memoria flash utilizada solo por la tabla de vectores de funciones ISR = .isr_vector.
      2. Memoria flash utilizada solo por la lógica del programa = .text.
      3. Memoria flash utilizada por las variables estáticas y globales de solo lectura solamente = .rodata.
  2. Memoria SRAM:
    1. Uso de SRAM de variables estáticas y globales Y asignado para uso de pila y almacenamiento dinámico = berkeley bss+ berkeley data.
      1. SRAM utilizada solo por variables estáticas y globales = sysv (.bss + .data). Observe los puntos ( .) antes de cada uno de estos nombres aquí, a diferencia de la falta de puntos arriba.
      2. SRAM asignado específicamente para pila (variables locales) y montón (asignación de memoria dinámica) = (aparentemente) ._user_heap_stack.
      3. SRAM no asignada para nada = SRAM_total - (berkeley bss + berkeley data).

Referencias:

  1. Manual de GNU Linker ( ld), sección "3.1 Conceptos básicos del script del vinculador": https://sourceware.org/binutils/docs/ld/Basic-Script-Concepts.html#Basic-Script-Concepts :

    3.1 Conceptos básicos de la secuencia de comandos del enlazador

    Necesitamos definir algunos conceptos básicos y vocabulario para describir el lenguaje de script del enlazador.

    El enlazador combina archivos de entrada en un único archivo de salida. El archivo de salida y cada archivo de entrada están en un formato de datos especial conocido como formato de archivo de objeto . Cada archivo se denomina archivo de objeto . El archivo de salida a menudo se denomina ejecutable , pero para nuestros propósitos también lo llamaremos archivo de objeto. Cada archivo de objeto tiene, entre otras cosas, una lista de secciones . A veces nos referimos a una sección en un archivo de entrada como una sección de entrada ; De manera similar, una sección en el archivo de salida es una sección de salida .

    Cada sección en un archivo de objeto tiene un nombre y un tamaño. La mayoría de las secciones también tienen un bloque de datos asociado, conocido como contenido de la sección . Una sección puede marcarse como cargable , lo que significa que el contenido debe cargarse en la memoria cuando se ejecuta el archivo de salida. Una sección sin contenido puede ser asignable , lo que significa que se debe reservar un área en la memoria, pero no se debe cargar nada en particular allí (en algunos casos, esta memoria debe ponerse a cero). Una sección que no se puede cargar ni asignar normalmente contiene algún tipo de información de depuración.

    Cada sección de salida cargable o asignable tiene dos direcciones. El primero es el VMA , o dirección de memoria virtual. Esta es la dirección que tendrá la sección cuando se ejecute el archivo de salida. La segunda es la LMA , o dirección de memoria de carga. Esta es la dirección en la que se cargará la sección. En la mayoría de los casos, las dos direcciones serán las mismas. Un ejemplo de cuándo pueden ser diferentes es cuando una sección de datos se carga en la ROM y luego se copia en la RAM cuando se inicia el programa (esta técnica se usa a menudo para inicializar variables globales en un sistema basado en ROM). En este caso, la dirección de la ROM sería la LMA y la dirección de la RAM sería la VMA.

    Puede ver las secciones en un archivo de objeto utilizando el objdumpprograma con la opción '-h'.

    Cada archivo de objeto también tiene una lista de símbolos , conocida como la tabla de símbolos . Un símbolo puede estar definido o no definido. Cada símbolo tiene un nombre, y cada símbolo definido tiene una dirección, entre otra información. Si compila un programa C o C++ en un archivo de objeto, obtendrá un símbolo definido para cada función definida y variable estática o global. Cada función indefinida o variable global a la que se hace referencia en el archivo de entrada se convertirá en un símbolo indefinido.

    Puede ver los símbolos en un archivo de objeto usando el nmprograma, o usando el objdumpprograma con la opción '-t'.

  2. Mi propia respuesta a mi propia pregunta aquí: convertir sizela salida de binutils del formato "sysv" ( size --format=sysv my_executable) al formato "berkeley" ( size --format=berkeley my_executable)

.init_arrayy .fini_array-- las variables globales en C++ tendrán su constructor y destructores ejecutándose antes de que main comience a ejecutarse y después de que main salga, respectivamente. Estas dos secciones contienen (punteros a) funciones de construcción y destrucción que deben ser invocadas por la biblioteca de soporte de tiempo de ejecución. Pure ISO Standard C no tiene tal cosa (no puede inicializar una variable global C con una expresión dinámica), pero gcc lo agrega a C como una extensión usando __attribute((constructor))__y __attribute__((destructor)).

Script/comando para calcular automáticamente el uso de Flash y SRAM por usted

Como una extensión de las otras dos respuestas, incluida la mía , aquí hay un script bash de Linux de 1 línea que puede usar para calcular FLASHy SRAMusar automáticamente.

Esto supone que su comando para ver la información de tamaño de Berkeley de su archivo .elf es arm-none-eabi-size "STM32F103RB_Nucleo.elf". Actualice esa ruta a su archivo .elf de interés. Si busca archivos .elf de Linux o archivos ejecutables normales en lugar de archivos .elf de STM32, use sizeen lugar de arm-none-eabi-size. Ej: size path/to/my_program.elf.

De todos modos, aquí está el guión:

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"

Suponiendo que arm-none-eabi-size "STM32F103RB_Nucleo.elf"muestra esto:

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

... aquí hay un resultado de muestra de ejecutar el script anterior:

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

Desglose de Flash, SRAM y las 3 secciones de Berkely

  • Flash y SRAM:
    • FLASH = text + data
    • SRAM = bss + data
  • Las 3 secciones de Berkeley:
    • text= datos del programa + vector ISR + rodata (datos de solo lectura: consty constexprvariables estáticas y globales de solo lectura)
    • data= NON-zero-inicializado (es decir: inicializado con un número distinto de cero) variables estáticas y globales, + .init_array + .fini_array
    • bss= variables estáticas y globales inicializadas en cero + espacio de pila y montón reservado por la secuencia de comandos del enlazador

Para obtener más detalles, vea mi otra respuesta, muy detallada, aquí: ¿Cómo averiguo en tiempo de compilación qué cantidad de memoria Flash y memoria dinámica (SRAM) de un STM32 se utiliza?

Referencias:

  1. la respuesta principal: ¿Cómo averiguo en tiempo de compilación qué cantidad de memoria Flash y memoria dinámica (SRAM) de un STM32 se utiliza?
  2. mi otra respuesta: ¿Cómo averiguo en tiempo de compilación cuánta memoria Flash y memoria dinámica (SRAM) de un STM32 se utiliza?
  3. cómo agregar números en bash: https://stackoverflow.com/questions/6348902/how-can-i-add-numbers-in-a-bash-script/6348941#6348941
  4. cómo usar awkpara eliminar la primera línea de un blob de texto: https://superuser.com/questions/284258/remove-first-line-in-bash/284270#284270
  5. awkejemplo general de mis propias notas para recordarme cómo usarlo:du -h | tail -n 1 | awk '{print $1}'