8
\$\begingroup\$

As per the memory layout of C program ,constant variables are stored in the Initialized data segment of the RAM. But as per some of the Microcontroller memory layout ,const variables are stored in FLASH Memory. I have also seen that the size of BIN file of my code increases when I change const variables to Macro definitions? Help me clear this ambiguity. I used Nuc2240 Cortex M0 .

\$\endgroup\$
3
  • 4
    \$\begingroup\$ RAM in most micros is volatile, so constants are stored in flash and may (or may not) be copied to RAM during initialisation (it depends on the micro). The "memory layout of C program" that you reference is not a standard as such, much of these sort of details are implementation dependent. C itself is just the high level language, memory usage will be determined by the compiler and linker, with some knowledge of the target platform. I don't see any "ambiguity" in this, unless I misunderstood your concern? \$\endgroup\$ Commented Jan 20, 2017 at 8:47
  • 1
    \$\begingroup\$ Possible duplicate of What resides in the different memory types of a microcontroller?. \$\endgroup\$
    – Lundin
    Commented Jan 20, 2017 at 12:37
  • \$\begingroup\$ Several different schemes are discussed in the answers here (load the constant from flash or RAM, or encode it in the instruction). You can see what your toolchain is doing for various cases by viewing a disassembly listing of the program and following the assembler instructions. Many IDE's provide for generating disassembly listings, or you can use a standalone program. \$\endgroup\$
    – tcrosley
    Commented Jan 20, 2017 at 18:38

5 Answers 5

6
\$\begingroup\$

If you were writing assembler, you would decide which locations are used to hold which constants or variables, through org or similar directives.

When you are writing C, the C tool chain you're using will store stuff where it's been programmed to. Variables obviously tend to go in RAM, constants can go in either RAM or Flash, program tends to go in Flash.

It's all down to how the tool for that particular target processor has been designed, where it gets its instruction from where to put stuff. It might all be baked into the code, in which case you don't get any say, it goes where the tool chain's creators chose to send it. It may take directives from somewhere (source code, command line, make file, environmental variable) so that you can rebase stuff.

Read your specific documentation. It's not physics, it's all down to the whim of man.

\$\endgroup\$
2
  • \$\begingroup\$ It not the task of the compiler but of the code generator and the linker to place segments with constants at a location inside EPROM, FLASH or battery buffered RAM. But constants may also placed into volatile RAM if they are initialized at programm start by special code generated by the compiler. \$\endgroup\$
    – Uwe
    Commented Jan 20, 2017 at 12:33
  • \$\begingroup\$ yeah, compiler is me being lazy, the tool chain. \$\endgroup\$
    – Neil_UK
    Commented Jan 20, 2017 at 13:51
7
\$\begingroup\$

The answer to your question is specific to the particularly architecture you are using. Since you have mentioned ARM, I'll give you an answer based on this.

The ARM Cortex is a register based design, so basically any operands (const or not) must some how make their way into one of the internal registers before they can be used by program instructions. This is central to answering your question, because there are a couple of different ways the architecture allows this to be done.

For small constants (typically less than 8 or 10-bits), the value can be encoded directly into certain instructions. For example, there is an ADD #imm instruction that will add a 12-bit value encoded into the instruction word to a register. This can be used to directly specify a constant in your program. If you were adding the same constant in various different places in your code, and the value was 12-bits or less, then the compiler would just use an ADD #imm instruction everywhere your constant was required. In other words, the actual const will be replicated in multiple locations throughout the code that is stored in FLASH.

If the constant is large then this won't work, so the value will have to be stored in its own dedicated FLASH memory location. The chip has another instruction, called LDR which it uses to move a value from a memory location into the internal registers where it can be used. This instruction does not care whether the value is physically stored in FLASH or RAM, it just pulls the value from a specific address in memory and puts it into a register. Note that compared to the situation with small constants, this requires an extra instruction cycle, but if the constant is used repeatedly in a block of code then the compiler will cache it by putting it into a spare register if one is available.

However now we run into a potential problem. On most Cortex chips the FLASH memory runs at the same speed or slower than the CPU core. If we attempt to execute an LDR instruction from a FLASH location, this read operation of the physical memory must compete with the reading of the next instruction. This creates a bottleneck, which causes the CPU to have to stall until the data has been read. Even worse, on many implementations, the FLASH runs very slow and a pipeline cache is used to feed instructions to the CPU faster. In these devices reading, say, a table of constant values can expose the fundamental FLASH access bottleneck causing severe loss of performance.

For this reason, many compilers will look to copy any constant data into spare RAM locations if possible. This will prevent such issues, and since RAM is normally faster to access than FLASH can prevent a lot of performance bottlenecks. If there is unused RAM in your program anyway, then it is virtually no overhead for the compiler to do this.

So there is most definitely a logic to how the compiler allocates constant data to physical memory, but thankfully in most situations the chip and compiler designers have done all this hard work for you, and you can just trust that it is doing whatever is best for your particular code and optimization level.

\$\endgroup\$
3
\$\begingroup\$

The link you provided explains what happens on regular computers, which load everything (including code) in RAM, anyway (because this is the only thing available, but there is plenty of it). It doesn't apply to embedded programming, where you also have flash available. So, if you use a linker script appropriate for embedded programming (which should be the default for embedded IDEs), constant data actually end up in flash, as it should.

Now, if you use macro definitions, it is completely different. Macros are replaced within the source code by the preprocessor, which means that the constant will be recompiled independently each time you use it in your code. And, if you use it multiple times, indeed, the code will be bigger. This, of course, shouldn't be the case for simple integer constants. For string constants, good compilers will try to merge multiple identical values to reduce this effect and keep size small, but this is not guaranteed, and may depend whether the strings are only used within the same compilation unit (.c source file) or across multiple comilation units. For constant structures/objects, the compilers usually don't do much optimization.

Answers would be more relevant to your specific case if you provided extracts of your source code, and indicate which compiler/IDE you're using.

\$\endgroup\$
0
\$\begingroup\$

the answer depends on your definition of "constant variable" and the compiler used.

if it is indeed a "constant variable", most compilers will store it as in flash.

if it is declared via a macro, it cannot possibly be a constant variable - it is a constant. it is generally stored in flash and copied to ram.

\$\endgroup\$
0
\$\begingroup\$

Looks like you are confusing constants with variables. This is specially important if you're using C and not C++.

In C, what you call a constant variable (like a const int) will actually get thrown in RAM. That's how the compiler deals with the need to sometimes reference the variable's address (pointers).

If this is a global variable, the compiler will put this in the initialized data section, which means the values go to flash in the .etext section and are copied to .sdata section (part of .data) by the startup script. If it is a local variable, the function's start code will do this like any other variable.

However, if you use a macro, the "variable" doesn't get an address space. That means it is loaded as an immediate, either by the very instruction you're using (if the value is small enough and the instruction supports immediates) or loaded to a register just before the instruction which uses the value. This will use only flash space, presuming you're running code from flash.

On the other hand, if you're using C++, the compiler does optimizations use the value directly from flash. This is not done in C by design. See this answer for more information.

\$\endgroup\$
1
  • \$\begingroup\$ By the way, this is actually how the Cortex-M3 I use does things in GCC. \$\endgroup\$ Commented Jan 20, 2017 at 15:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.