Flash memory size usage with const

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have some doubt about the program memory usage in three cases given below.

In first case, const keyword is not used. In this case program memory size is not getting increased. But since myList is a global variable, it should also be part of ROM right? Why 100 bytes arevnot getting added to program memory? 

In second case, const keyword is used and program memory is getting increased by 100 bytes as expected (Even with PROGMEM in second case gives same 11188 bytes of program memory).

 

Now I removed myList[] and added just one global variable in case3. Even with or without const keyword, 4 bytes are getting reflected in both ROM and RAM. So why program memory size is not getting updated when array is used? 

 

Case1:

uint32_t myList[25]={0};
int main(void)
{

    //Some code here

}

 

avr-size -C Debug\studentsproject.elf
AVR Memory Usage
----------------
Device: Unknown
Program:   11088 bytes
(.text + .data + .bootloader)
Data:        392 bytes
(.data + .bss + .noinit)

 

Case2:

const uint32_t myList[25]={0};

int main(void)
{
    //some code
}

 

AVR Memory Usage
----------------
Device: Unknown
Program:   11188 bytes
(.text + .data + .bootloader)
Data:        392 bytes
(.data + .bss + .noinit)
 

 

 

Case3:

uint32_t var1=456666;

int main(void)
{
    
}

AVR Memory Usage
----------------
Device: Unknown
Program:   11092 bytes
(.text + .data + .bootloader)
Data:        296 bytes
(.data + .bss + .noinit)

 

I am using avr8-gnu-toolchain with Atmega328P.

Optimization: -Os

 

This topic has a solution.

Last Edited: Mon. Apr 30, 2018 - 12:14 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You need to get a good book about C and understand the distinction between .data and .bss

 

Oh and if you are thinking that const alone will locate fixed data into only flash you are wrong. You need "const __flash"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am sorry if there is anything wrong in my problem description. I understand that .data segment is initialized globals/statics and .bss is uninitialized globals/statics. This question is not about the difference between them. 

In my example, data is initialized in all 3 cases and hence .bss does not come into picture if I am correct.

According to https://en.wikipedia.org/wiki/Data_segment

The values for these variables are initially stored within the read-only memory (typically within .text) and are copied into the .data segment during the start-up routine of the program.

That means myList[] should be part of program memory and later it gets copied to RAM. But it is part of program memory (I am talking only based on program memory and .data memory as reported by size command and not based on any output files) only if const keyword was used or PROGMEM is used (for which const is anyway needed). So in case1 there is an issue. 

Last Edited: Sun. Apr 29, 2018 - 05:57 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Init with 0 is BSS!

 

In fact your ={0} might as well not be there as  C guarantees this anyway.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the help. Following links also helped me to understand the concept.

https://stackoverflow.com/questions/8721475/if-a-global-variable-is-initialized-to-0-will-it-go-to-bss 

https://stackoverflow.com/questions/9535250/why-is-the-bss-segment-required

 

But why const keyword keep the data in ROM as well. const means only read only (PROGMEM means it will anyway go to ROM) and is this because const variables must be anyway initialized at the time of declaration and hence compiler treats it as initialized data even if their initial value is zero?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joneewheelock wrote:
But why const keyword keep the data in ROM as well.
const does NOT keep the data in ROM. If you have an object in RAM that has non-0 initialisers then obviously those initialisers have to start life in ROM (flash) at power on then the _dop_copy_data() loop LPMs the data and writes it to RAM before main().

 

The easiest way to see all this is to try it. If you start with a program that has neither .bss nor .data:

#include <avr/io.h>

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

you get:

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18            ; 0x14 <__ctors_end>
   2:   0e c0           rjmp    .+28            ; 0x20 <__bad_interrupt>
   4:   0d c0           rjmp    .+26            ; 0x20 <__bad_interrupt>
   6:   0c c0           rjmp    .+24            ; 0x20 <__bad_interrupt>
   8:   0b c0           rjmp    .+22            ; 0x20 <__bad_interrupt>
   a:   0a c0           rjmp    .+20            ; 0x20 <__bad_interrupt>
   c:   09 c0           rjmp    .+18            ; 0x20 <__bad_interrupt>
   e:   08 c0           rjmp    .+16            ; 0x20 <__bad_interrupt>
  10:   07 c0           rjmp    .+14            ; 0x20 <__bad_interrupt>
  12:   06 c0           rjmp    .+12            ; 0x20 <__bad_interrupt>

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1
  16:   1f be           out     0x3f, r1        ; 63
  18:   cf e9           ldi     r28, 0x9F       ; 159
  1a:   cd bf           out     0x3d, r28       ; 61
  1c:   02 d0           rcall   .+4             ; 0x22 <main>
  1e:   02 c0           rjmp    .+4             ; 0x24 <_exit>

00000020 <__bad_interrupt>:
  20:   ef cf           rjmp    .-34            ; 0x0 <__vectors>

00000022 <main>:
#include <avr/io.h>

int main(void) {
  22:   ff cf           rjmp    .-2             ; 0x22 <main>

00000024 <_exit>:
  24:   f8 94           cli

00000026 <__stop_program>:
  26:   ff cf           rjmp    .-2             ; 0x26 <__stop_program>

When you add something in BSS:

#include <avr/io.h>

char buffer[20];

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

you get:

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18            ; 0x14 <__ctors_end>
   2:   16 c0           rjmp    .+44            ; 0x30 <__bad_interrupt>
   4:   15 c0           rjmp    .+42            ; 0x30 <__bad_interrupt>
   6:   14 c0           rjmp    .+40            ; 0x30 <__bad_interrupt>
   8:   13 c0           rjmp    .+38            ; 0x30 <__bad_interrupt>
   a:   12 c0           rjmp    .+36            ; 0x30 <__bad_interrupt>
   c:   11 c0           rjmp    .+34            ; 0x30 <__bad_interrupt>
   e:   10 c0           rjmp    .+32            ; 0x30 <__bad_interrupt>
  10:   0f c0           rjmp    .+30            ; 0x30 <__bad_interrupt>
  12:   0e c0           rjmp    .+28            ; 0x30 <__bad_interrupt>

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1
  16:   1f be           out     0x3f, r1        ; 63
  18:   cf e9           ldi     r28, 0x9F       ; 159
  1a:   cd bf           out     0x3d, r28       ; 61

0000001c <__do_clear_bss>:
  1c:   20 e0           ldi     r18, 0x00       ; 0
  1e:   a0 e6           ldi     r26, 0x60       ; 96
  20:   b0 e0           ldi     r27, 0x00       ; 0
  22:   01 c0           rjmp    .+2             ; 0x26 <.do_clear_bss_start>

00000024 <.do_clear_bss_loop>:
  24:   1d 92           st      X+, r1

00000026 <.do_clear_bss_start>:
  26:   a4 37           cpi     r26, 0x74       ; 116
  28:   b2 07           cpc     r27, r18
  2a:   e1 f7           brne    .-8             ; 0x24 <.do_clear_bss_loop>
  2c:   02 d0           rcall   .+4             ; 0x32 <main>
  2e:   02 c0           rjmp    .+4             ; 0x34 <_exit>

00000030 <__bad_interrupt>:
  30:   e7 cf           rjmp    .-50            ; 0x0 <__vectors>

00000032 <main>:
#include <avr/io.h>

char buffer[20];

int main(void) {
  32:   ff cf           rjmp    .-2             ; 0x32 <main>

00000034 <_exit>:
  34:   f8 94           cli

00000036 <__stop_program>:
  36:   ff cf           rjmp    .-2             ; 0x36 <__stop_program>

and when you add something in .data:

#include <avr/io.h>

char text[] = "Hello World";

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

you get:

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18            ; 0x14 <__ctors_end>
   2:   19 c0           rjmp    .+50            ; 0x36 <__bad_interrupt>
   4:   18 c0           rjmp    .+48            ; 0x36 <__bad_interrupt>
   6:   17 c0           rjmp    .+46            ; 0x36 <__bad_interrupt>
   8:   16 c0           rjmp    .+44            ; 0x36 <__bad_interrupt>
   a:   15 c0           rjmp    .+42            ; 0x36 <__bad_interrupt>
   c:   14 c0           rjmp    .+40            ; 0x36 <__bad_interrupt>
   e:   13 c0           rjmp    .+38            ; 0x36 <__bad_interrupt>
  10:   12 c0           rjmp    .+36            ; 0x36 <__bad_interrupt>
  12:   11 c0           rjmp    .+34            ; 0x36 <__bad_interrupt>

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1
  16:   1f be           out     0x3f, r1        ; 63
  18:   cf e9           ldi     r28, 0x9F       ; 159
  1a:   cd bf           out     0x3d, r28       ; 61

0000001c <__do_copy_data>:
  1c:   10 e0           ldi     r17, 0x00       ; 0
  1e:   a0 e6           ldi     r26, 0x60       ; 96
  20:   b0 e0           ldi     r27, 0x00       ; 0
  22:   ee e3           ldi     r30, 0x3E       ; 62
  24:   f0 e0           ldi     r31, 0x00       ; 0
  26:   02 c0           rjmp    .+4             ; 0x2c <__do_copy_data+0x10>
  28:   05 90           lpm     r0, Z+
  2a:   0d 92           st      X+, r0
  2c:   ac 36           cpi     r26, 0x6C       ; 108
  2e:   b1 07           cpc     r27, r17
  30:   d9 f7           brne    .-10            ; 0x28 <__do_copy_data+0xc>
  32:   02 d0           rcall   .+4             ; 0x38 <main>
  34:   02 c0           rjmp    .+4             ; 0x3a <_exit>

00000036 <__bad_interrupt>:
  36:   e4 cf           rjmp    .-56            ; 0x0 <__vectors>

00000038 <main>:
#include <avr/io.h>

char text[] = "Hello World";

int main(void) {
  38:   ff cf           rjmp    .-2             ; 0x38 <main>

0000003a <_exit>:
  3a:   f8 94           cli

0000003c <__stop_program>:
  3c:   ff cf           rjmp    .-2             ; 0x3c <__stop_program>

You can't "see" the .data in that but you can here:

C:\SysGCC\avr\bin>avr-objdump -s -j .data avr.elf

avr.elf:     file format elf32-avr

Contents of section .data:
 800060 48656c6c 6f20576f 726c6400           Hello World.

Also if I create a binary in the same way that I would create a hex file (-O ihex):

C:\SysGCC\avr\bin>avr-objcopy -O binary -j .text -j .data avr.elf avr.bin

Then the binary looks like this:

Offset      0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

00000000   09 C0 19 C0 18 C0 17 C0  16 C0 15 C0 14 C0 13 C0    À À À À À À À À
00000010   12 C0 11 C0 11 24 1F BE  CF E9 CD BF 10 E0 A0 E6    À À $ ¾ÏéÍ¿ à æ
00000020   B0 E0 EE E3 F0 E0 02 C0  05 90 0D 92 AC 36 B1 07   °àîãðà À   ’¬6± 
00000030   D9 F7 02 D0 02 C0 E4 CF  FF CF F8 94 FF CF 48 65   Ù÷ Ð ÀäÏÿÏø”ÿÏHe
00000040   6C 6C 6F 20 57 6F 72 6C  64 00                     llo World 

which is the code listed above immediately followed by the .data - that is exactly what would be in the flash of the AVR

 

As this shows:

C:\SysGCC\avr\bin>avr-size avr.elf
   text    data     bss     dec     hex filename
     62      12       0      74      4a avr.elf

There are 62 bytes in the program code and then 12 bytes in the data section.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you again for the wonderful explanation

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

"const" has nothing at all to do with ROM. "const" is just a hint that you don't plan to modify the thing; it doesn't require that it be "in ROM" or anything like that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the modern compiler "const __flash" is what you use to say "ROM only". So:

#include <avr/io.h>

const char text[] = "Hello World";

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

with nothing but "const" creates:

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18            ; 0x14 <__ctors_end>
   2:   19 c0           rjmp    .+50            ; 0x36 <__bad_interrupt>
   4:   18 c0           rjmp    .+48            ; 0x36 <__bad_interrupt>
   6:   17 c0           rjmp    .+46            ; 0x36 <__bad_interrupt>
   8:   16 c0           rjmp    .+44            ; 0x36 <__bad_interrupt>
   a:   15 c0           rjmp    .+42            ; 0x36 <__bad_interrupt>
   c:   14 c0           rjmp    .+40            ; 0x36 <__bad_interrupt>
   e:   13 c0           rjmp    .+38            ; 0x36 <__bad_interrupt>
  10:   12 c0           rjmp    .+36            ; 0x36 <__bad_interrupt>
  12:   11 c0           rjmp    .+34            ; 0x36 <__bad_interrupt>

00000014 <__ctors_end>:
  14:   11 24           eor     r1, r1
  16:   1f be           out     0x3f, r1        ; 63
  18:   cf e9           ldi     r28, 0x9F       ; 159
  1a:   cd bf           out     0x3d, r28       ; 61

0000001c <__do_copy_data>:
  1c:   10 e0           ldi     r17, 0x00       ; 0
  1e:   a0 e6           ldi     r26, 0x60       ; 96
  20:   b0 e0           ldi     r27, 0x00       ; 0
  22:   ee e3           ldi     r30, 0x3E       ; 62
  24:   f0 e0           ldi     r31, 0x00       ; 0
  26:   02 c0           rjmp    .+4             ; 0x2c <__do_copy_data+0x10>
  28:   05 90           lpm     r0, Z+
  2a:   0d 92           st      X+, r0
  2c:   ac 36           cpi     r26, 0x6C       ; 108
  2e:   b1 07           cpc     r27, r17
  30:   d9 f7           brne    .-10            ; 0x28 <__do_copy_data+0xc>
  32:   02 d0           rcall   .+4             ; 0x38 <main>
  34:   02 c0           rjmp    .+4             ; 0x3a <_exit>

00000036 <__bad_interrupt>:
  36:   e4 cf           rjmp    .-56            ; 0x0 <__vectors>

00000038 <main>:
#include <avr/io.h>

const char text[] = "Hello World";

int main(void) {
  38:   ff cf           rjmp    .-2             ; 0x38 <main>

0000003a <_exit>:
  3a:   f8 94           cli

0000003c <__stop_program>:
  3c:   ff cf           rjmp    .-2             ; 0x3c <__stop_program>

which still builds in the _do_copy_data() loop to copy (LPM) the data from flash to RAM. The .data initial content will be expected to be in flash immediately after the code. But:

#include <avr/io.h>

const __flash char text[] = "Hello World";

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

creates:

C:\SysGCC\avr\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0f c0           rjmp    .+30            ; 0x20 <__ctors_end>
   2:   14 c0           rjmp    .+40            ; 0x2c <__bad_interrupt>
   4:   13 c0           rjmp    .+38            ; 0x2c <__bad_interrupt>
   6:   12 c0           rjmp    .+36            ; 0x2c <__bad_interrupt>
   8:   11 c0           rjmp    .+34            ; 0x2c <__bad_interrupt>
   a:   10 c0           rjmp    .+32            ; 0x2c <__bad_interrupt>
   c:   0f c0           rjmp    .+30            ; 0x2c <__bad_interrupt>
   e:   0e c0           rjmp    .+28            ; 0x2c <__bad_interrupt>
  10:   0d c0           rjmp    .+26            ; 0x2c <__bad_interrupt>
  12:   0c c0           rjmp    .+24            ; 0x2c <__bad_interrupt>

00000014 <__trampolines_end>:
  14:   48 65           ori     r20, 0x58       ; 88
  16:   6c 6c           ori     r22, 0xCC       ; 204
  18:   6f 20           and     r6, r15
  1a:   57 6f           ori     r21, 0xF7       ; 247
  1c:   72 6c           ori     r23, 0xC2       ; 194
  1e:   64 00           .word   0x0064  ; ????

00000020 <__ctors_end>:
  20:   11 24           eor     r1, r1
  22:   1f be           out     0x3f, r1        ; 63
  24:   cf e9           ldi     r28, 0x9F       ; 159
  26:   cd bf           out     0x3d, r28       ; 61
  28:   02 d0           rcall   .+4             ; 0x2e <main>
  2a:   02 c0           rjmp    .+4             ; 0x30 <_exit>

0000002c <__bad_interrupt>:
  2c:   e9 cf           rjmp    .-46            ; 0x0 <__vectors>

0000002e <main>:
#include <avr/io.h>

const __flash char text[] = "Hello World";

int main(void) {
  2e:   ff cf           rjmp    .-2             ; 0x2e <main>

00000030 <_exit>:
  30:   f8 94           cli

00000032 <__stop_program>:
  32:   ff cf           rjmp    .-2             ; 0x32 <__stop_program>

has no such copying loop and the data is visible in flash in this listing. As already seen above "Hello World" looks like:

48 65 6C 6C 6F 20 57 6F 72 6C 64 00 Hello World

and you can see that here:

  14:   48 65           ori     r20, 0x58       ; 88
  16:   6c 6c           ori     r22, 0xCC       ; 204
  18:   6f 20           and     r6, r15
  1a:   57 6f           ori     r21, 0xF7       ; 247
  1c:   72 6c           ori     r23, 0xC2       ; 194
  1e:   64 00           .word   0x0064  ; ????

(yes the disassembler has had a crack at disassembling what is really ASCII text!)