Entendiendo el tamaño del programa - ATMega328P

1

Estoy interesado en averiguar el uso de memoria de mi código que se ejecuta en un ATMega328P (16 MHz) usando la utilidad avr-size incluida con WinAVR 20100110. Usando el Makefile incluido en la distribución, obtuve el siguiente uso de memoria para el código abajo:

#include <avr/io.h>
#include <stdint.h>

int main(void)
{  
    while(1)
    { }
    return 0;
}

La salida de la consola es:

make all 

-------- begin --------
avr-gcc (WinAVR 20100110) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Compiling C: src/main.c
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./src/main.lst  -std=gnu99 -MMD -MP -MF .dep/main.o.d src/main.c -o src/main.o 

Linking: src/main.elf
avr-gcc -mmcu=atmega328p -I. -gdwarf-2 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=src/main.o  -std=gnu99 -MMD -MP -MF .dep/main.elf.d src/main.o --output src/main.elf -Wl,-Map=./src/main.map,--cref     -lm

Creating load file for Flash: src/main.hex
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature src/main.elf src/main.hex

Creating load file for EEPROM: src/main.eep
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
    --change-section-lma .eeprom=0 --no-change-warnings -O ihex src/main.elf src/main.eep || exit 0

Creating Extended Listing: src/main.lss
avr-objdump -h -S -z src/main.elf > src/main.lss

Creating Symbol Table: src/main.sym
avr-nm -n src/main.elf > src/main.sym

Size after:
AVR Memory Usage
----------------
Device: atmega328p

Program:     134 bytes (0.4% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)



-------- end --------

Cuando ejecuto el mismo código con la construcción while() eliminada, se informa que el tamaño del programa es 138 bytes . Lo mismo sucede si comento tanto while () como la declaración de retorno. ¿Cómo puede aumentar el tamaño del programa cuando elimino una construcción de bucle? El Makefile usa el optimizador -S para gcc. ¿Tiene algo que ver con eso?

    

1 respuesta

2

El tipo de respuesta corta es que el compilador le está ahorrando espacio al notar que el ciclo while nunca regresa . Saber que la función nunca regresa significa que puede omitir el envío del valor de retorno a la pila, lo que le ahorra dos instrucciones, que son cuatro bytes en el AVR.

La respuesta más larga y más información útil:

El ensamblaje se compila esencialmente siempre hasta el mismo tamaño para cada instrucción (en arquitecturas con solo un tamaño de instrucción, de las cuales AVR es casi la mayoría de las operaciones son de 2 bytes). Eso significa que más código de ensamblaje significa un programa más grande.

Puede ver la razón por la que el que tiene el while() loop es mayor si examina la diferencia en los archivos de listado de ensamblajes.

Listado para main.c con el bucle while:

  ......
  14                    .file 1 "main.c"
   1:main.c        **** #include <avr/io.h>
   2:main.c        **** #include <stdint.h>
   3:main.c        **** 
   4:main.c        **** int main(void)
   5:main.c        **** {  
  15                    .loc 1 5 0
  16                /* prologue: function */
  17                /* frame size = 0 */
  18                /* stack size = 0 */
  19                .L__stack_usage = 0
  20                .L2:
  21 0000 00C0              rjmp .L2
  22                .LFE0:
  50                .Letext0:
  ..... (Symbol table follows)

Y el código main.c sin el bucle while:

  ...... (everything the same up to here)
  14                    .file 1 "main.c"
   1:main.c        **** #include <avr/io.h>
   2:main.c        **** #include <stdint.h>
   3:main.c        **** 
   4:main.c        **** int main(void)
   5:main.c        **** {  
  15                    .loc 1 5 0
  16                /* prologue: function */
  17                /* frame size = 0 */
  18                /* stack size = 0 */
  19                .L__stack_usage = 0
   6:main.c        ****     return 0;
   7:main.c        **** }
  20                    .loc 1 7 0
  21 0000 80E0              ldi r24,0
  22 0002 90E0              ldi r25,0
  23 0004 0895              ret
  24                .LFE0:
  52                .Letext0:
  ..... (Symbol table follows)

En las líneas marcadas 20-24 en el código de bucle non-while, puede ver que está cargando un par de registros y luego llamando a la instrucción de retorno de subrutina ret . En el bucle while, se saltan eso, porque el compilador se da cuenta de que en las líneas 20-21, nada saldrá de ese bucle.

    
respondido por el jamuraa

Lea otras preguntas en las etiquetas