Memory is the most precious thing in Microcontrollers/Microprocessors. So, as a programmer we need to understand it in deep. In this article we will understand the memory layout of microcontrollers.
When we write the code and compile it then an executable is generated. This executable is flashed into MCU. After bootup the MCU starts working according to our written code. But the code that we have written goes to different memory segments. There are mainly 5 memory segments.
- text segment (.txt segment)
- uninitialized segment (.bss segment)
- initialized segment (data segment)
- stack
- heap
Text Segment
This segment holds the executable instructions and is also known as code segment or flash section or simply text. This segment is read-only because at runtime the code never modifies this segment.
Uninitialized Data Segment
This segment is also known as bss block because historically it is called “block started by symbol”. All the variables of this segment are initialized by MCU to 0 before entering to main () loop. This segment holds all the global variables that are not initialized, static variables that are initialized by 0 or are not initialized.
Initialized Data Segment
This segment is also known as data segment. This segment contains all the global variables and static variables that are initialized in code are part of this segment. This segment has two sub-sections. Initialized read-only and Initialized RW section. All the const variables are part of Initialized read-only section. All the variables that are not const and are initialized are part of Initialized RW section.
Heap & Stack
Heap & Stack are typically placed on higher memory addresses. Stack and Heap keeps on growing and reducing based on execution of code. They grow in opposite direction.
Stack is responsible for holding all the local variables on a function. As soon as we enter into the main(), all the local variables of main() are pushed to stack. If we are calling func1() from main()and func1, has 5 local char variables then those 5 variables will be places inside stack. Further, if func2() is called & it have 10 local char variables then those 10 variables will be places on top of 5 variables of func1().
So, in this way the stack keeps on growing as we keep on calling function inside another function. As soon as we return from a function, the stack is reduced by size of variables of that function. e.g., in above example, if we return from func2() to func1() then the stack will get reduced by 10 bytes.
Heap is responsible for memory used dynamically e.g. allocated using malloc() or calloc() and is freed using free(). It is responsibility of the programmer to free the memory once it is used. If programmer is not freeing the memory, then then heap will keep on growing downward and eventually will collapse with stack. This will corrupt the variables of stack and may lead to crash of the code.