RAM obviously loses data when power is off, why initialized global variables are stored in RAM? Storage of detailed analysis programs

foreword

(1) Because of a bug caused by a character pointer and a character array pointer, it took me an afternoon to find the problem. After that, I plan to study how the system discovers the wild pointer random access problem. Later, we will go deep into the memory management in the microcomputer system.
(2) These are actually basic knowledge, but I have never understood it, so record it here.
(3) Before reading this article, you need to have a certain understanding of pointers and dynamic memory management in C language !

program storage

The main storage model for programs

(1) Generally speaking, a program is mainly composed of five parts: code segment , constant area , static data area , stack , and heap . The static data area can be divided into BSS segment and data segment.
(2)code snippet: Responsible for storing the compiled binary code of the program. Sometimes there are some data that seem to be stored, but in fact they do not take up space. They eventually become code and are placed in the code segment. As follows:
<1> #define macro definition : In C/C++, you can use the preprocessing directive #define to define constant macros. For example: #define PI 3.1415926. At compile time, the preprocessor will replace all macro definitions and embed the constants defined by the macros directly into the code.
<2> Enumeration (Enum) : In C/C++, an enumeration can be used to define a set of symbolic names with constant values. The function of the enumeration in the code is similar to that of using a macro, and the name can be used instead of the value. Macros replace names with values ​​during preprocessing, while enumerations replace names with values ​​during compilation. In other words, these names of enumeration types are not variables, they do not occupy any memory . And the effective scope of these names is global, if there are variables and other naming conflicts, it may cause the compilation to fail.
<3> Literal Constants (Literal Constants) : Literal constants used directly in the code, such as integers, floating point numbers, character constants and string constants. These literal constants will be directly stored in the constant area at compile time. For example, if(a<5)...the number 5 is a literal constant.
(3)constant area: store read-only variables and string constants, once initialized, they cannot be modified.
<1> Global variables modified by const : Variables modified by const in the global scope will also be stored in the constant area. If it is a local variable modified by const, it is stored on the stack.
<2> Constant string : char *str2 = "hello"; "hello" in is a constant string.
(3)static data area: Used to store global variables and static data (variables with static added in front).
<1> BSS segment : used to store uninitialized or display initialized to 0 global variables and static variables.
<2> Data segment (.data) : Used to store initialized global variables and static variables.
<3>Why should we distinguish between the .data segment and the .bss segment for static data?
When the program is compiled, no space will be allocated for the data in the .bss section, but only the size of the space required for the data will be recorded. When the program is executed, memory will be allocated for the data in the .bss segment. In this way, part of the memory space can be saved, further reducing the size of the executable program.
(4)the stack: store local variables, function call information, etc. Automatically allocated/released by the system.
(5)heap: malloc, the space requested by the alloc function. It is applied/released manually by the programmer. If it is not released manually, it will be reclaimed by the system after the program ends.

insert image description here

Through code analysis

(1) We can know a lot of technical terms from textbooks, so I don't want to talk about terminology anymore, I will directly understand the code. Otherwise this is hydrology.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//宏定义和枚举常量会被当成代码编译进代码段,所以说,不占空间
#define PI 3.1415926  
enum color
{
    
    
	red,
	green,
	yellow
};

int a = 6;  //存放在静态数据区的数据段
char* str1; //存放在静态数据区的BSS段
static int c = 3;  //存储在静态数据区的数据段
static int d;  //存储在静态数据区的BSS段
const int b = 5; //存放在常量区

int main()  //main函数本质上就是一个函数指针,存放在栈中
{
    
    
	static int e; //存储在静态数据区的BSS段
	static int f = 2; //存储在静态数据区的数据段
	const char g; //存储在栈中
	char *str2 = "hello"; //str2存放在栈中,“hello”存放在常量区
	char str3[]="world"; //str3存放在栈中
	str1 = (char*)malloc(sizeof(char)*strlen(str2)); //申请的内存存放在堆中
	strcpy(str1,str2); //进行字符串拷贝
	if(a>5);
	printf("str1 = %s\r\n",str1);
	printf("str2 = %s\r\n",str2);
	printf("str3 = %s\r\n",str3);
	return 0;
}

(2) Although I wrote a comment on the above string of codes, explaining where these things are stored, I still want to analyze it for you. We first analyze the variables defined outside the function.
<1>#define PI 3.1415926 This macro definition will convert all PIs to the number 3.1415926 in the program preprocessing stage, and the number 3.1415926 will be regarded as code and stored in the code segment.
<2>enum color{} is an enumeration type. The enumeration constants red, green, and yellow inside are similar to macro definitions. During the compilation phase of the program, they will be replaced with corresponding numbers, so they do not take up space ! ( This space is relative, they are stored in the code segment, and the code segment is generally not included in the space we are talking about )
<3> Then we look at the variable a, which is initialized to a non-zero The data, so it is stored in the data segment of the static data area.
<4> and str1 is not initialized, so it is stored in the BSS segment of the static data area.
<5>Similarly, c is the data segment in the static data area, and d is the BSS segment in the static data area.
<6>Because b is modified by const, b is stored in the constant area. b cannot be modified again.

//宏定义和枚举常量会被当成代码编译进代码段,所以说,不占空间
#define PI 3.1415926  
enum color
{
    
    
	red,
	green,
	yellow
};

int a = 6;  //存放在静态数据区的数据段
char* str1; //存放在静态数据区的BSS段
static int c = 3;  //存储在静态数据区的数据段
static int d;  //存储在静态数据区的BSS段
const int b = 5; //存放在常量区

(3) Then we analyze the variables within the function.
<1> Although e and f are defined inside the function and belong to local variables, they are modified by static, so they belong to static local variables and are finally stored in the static data area . Then according to whether they have been initialized, it can be distinguished whether they are stored in the BSS segment of the static data area or the data segment.
<2> Although g is modified by the const keyword, it is not a global variable, so it is still the same as a local variable, stored on the stack, and will be released when the function ends. But the difference from local variables is that the variable g cannot be changed.
<3> Variables defined inside the function are local variables. So str2 and str3 are local variables, and the two data are not modified by special keywords, so str2 and str3 are stored in the stack.
<4> So now there is a question, where are "hello" and "world" stored? As mentioned above, the constant area can store string constants. So "hello" is actually stored in the constant area. As a pointer, str2 can access this data, but it cannot be tampered with. (I will talk about why later) "world" is different, it is stored on the stack.
<5>Why? Because str3[] is a character array, not a character pointer like str2. The data is stored in str3[], and the pointer is stored in str2.
<6>char *str2 = "hello"; For the computer, first create a "hello" string in the constant area, and then return the first address of the string to the character pointer str2 stored in the stack.
<7> and char str3[] = "world"; for the computer, it is to open up a character array space in the stack to store the "world" string. He is not a pointer!
<8> The last space requested by malloc is stored in the heap. Then the str character pointer of the BSS segment stored in the static data area points to this heap.
<9> When we call the strcpy(str1,str2); function, the "hello" constant string stored in the constant area will be read. (Note, this is reading, not writing. The constant area is readable but not writable.) After reading the string, copy the data to the space allocated by malloc on the heap.

int main()  //main函数本质上就是一个函数指针,存放在栈中
{
    
    
	static int e; //存储在静态数据区的BSS段
	static int f = 2; //存储在静态数据区的数据段
	const char g; //存储在栈中
	char *str2 = "hello"; //str2存放在栈中,“hello”存放在常量区
	char str3[]="world"; //str3存放在栈中
	str1 = (char*)malloc(sizeof(char)*strlen(str2)); //申请的内存存放在堆中
	strcpy(str1,str2); //进行字符串拷贝
	if(a>5);
	printf("str1 = %s\r\n",str1);
	printf("str2 = %s\r\n",str2);
	printf("str3 = %s\r\n",str3);
	return 0;
}

interrupt vector table

(1) In embedded systems, there is another very important concept, the interrupt vector table.
(2) The interrupt vector table is used to store interrupt programs. For example, when we write microcontroller programs, there are serial port interrupts and timer interrupts. These routines are responsible for storing in the interrupt vector table.
(3) For the same MCU, the size and location of its interrupt vector table are generally fixed. Compared with the storage size of the code segment, it is generally much smaller. So, this is one of the reasons why the experienced MCU siege lion repeatedly emphasizes that the interrupt program should be short and lean.

Relationship of these memory areas to ROM and RAM

What is ROM and RAM

(1) When many people learn this piece of knowledge, they often hear that the code is stored in the ROM area, and the code is stored in the code segment. The data requested by malloc is stored in RAM. Another way of saying is that the data requested by malloc is the heap. Presumably everyone listens to these things, and they must be confused. Yes, I was in the same fog at the time.
(2) So, to figure this out. We can first figure out what ROM and RAM are.
<1> ROM, the English full name is Read-Only Memory, which translates to a memory that can only be read. It is clear from the name that ROM is a memory that can only be read, but we need to pay attention to that this read-only memory is for the CPU, and people can write data through some external means. . The storage characteristics of ROM are relatively stable, and the data will not be lost even after the power is turned off. Therefore, ROM is a memory that is stable in storage (no loss of data when power is turned off), and is only readable by the CPU.
<2> RAM, the English full name Random Access Memory, translates to Random Access Memory. From the random words, we can know that this memory is not stable, so it will lose data when it is powered off. It can be known by storing two words that the memory CPU can write to it. Therefore, RAM is a readable and writable memory with unstable storage. (Note, this instability means that the data will be lost after the power is turned off, but if you turn on the power, the data will not have problems!)
<3> ROM and RAM are not only different in terms of storage stability and read and write permissions , There is also a difference in the speed of reading data. The data reading speed of RAM is higher than that of ROM .

What is the relationship between ROM and Flash

(1) In the last century, two kinds of memory were invented, one is RAM and the other is ROM. Once the ROM at that time stored data, it could no longer be changed or deleted , that is to say, the program had only one chance to download. If your program is wrong, then the chip will be scrapped. Obviously very tasteless.
(2) For ease of use and mass production, programmable read-only memory (PROM) and erasable programmable read-only memory (EPROM) have been further developed. EPROM needs to be irradiated with ultraviolet rays for a long time to be erased , which is very inconvenient to use. (3) Electrically Erasable
Programmable Read-Only Memory (EEPROM) appeared in 1980s , which overcomes the shortcomings of EPROM, but its integration level is not high and its price is relatively expensive. (4) Then a new type of memory cell structure similar to EPROM was developed (FLASH MEMORY). FLASH has high integration, low power consumption, small size, and can be quickly erased online, so it has achieved rapid development. The relationship diagram is as follows

insert image description here

(5) Therefore, the current single-chip microcomputer mainly uses Flash to store data, which is to replace the previous ROM . The biggest advantage is that it reduces the cost of the chip and can be electrically erased. But because the ROM was the first to be developed, many times, people are often willing to say that the ROM storage code in the chip is not the Flash storage code. We need to understand this, whatever you want to say. We only need to know that the current chips use Flash to store data, but we must also be able to understand that the ROM that many people talk about is Flash .

ROM, RAM and the relationship between the above storage structures

(1) Now that we know what ROM and RAM are, what is their connection with the above storage structure?
<1> Interrupt vector table : Our interrupt program must be stored in ROM, why? Suppose, the interrupt program is stored in RAM, what happens. Once your system is powered off, the code you worked so hard to write is gone. Think about how broken it is.
<2> Code segment : The code segment and the interrupt vector table are stored in the ROM area in the same way. However , it is possible to store code segments in RAM through special methods. Why do you want to do this? As mentioned above, the data reading speed of RAM is higher than that of ROM. If the code segment is placed in RAM, the execution efficiency of the code will be improved. (Note, this improvement requires a certain amount of data. Before I saw a person test the code at station B and run it in ROM and RAM, the effect is similar, because the amount of data is too small, and the effect is not obvious.) At this time, there must
be Careful students will ask. No, your code segment is placed in RAM, and all programs will disappear if the power is turned off? Yes, this is the data storage in the power-on and power-off states that we will explain later.What we discussed above are all data storage in the power-on state!
<3> Constant area : stored in ROM, because the data in the constant area cannot be modified, and the ROM is relatively large, so it is just right.
<4> Static data area : stored in RAM, because these variables will be used frequently and will be changed.
<5> Stack : Stored in RAM, function calls and local variable application and release are all changed, and we will adjust the data inside. So put it in RAM.
<6> Heap : Stored in RAM, the space requested by malloc and alloc is to be used, and they will store data, so they must be placed in RAM.

Data storage in power-off and power-on states

Why separate power-off and power-on state analysis

(1) In an MCU, after a program is compiled, it needs to be burned into it. This program has code segments, read-only data, readable and writable data. We analyzed above that the code segment and read-only data are stored in ROM, so where is the readable and writable data stored? Could it be RAM?
(2) Some people may think that I am contradicting myself. As mentioned above, readable and writable data are placed in RAM, so here is a rhetorical question. What a mess! However, if you think about it carefully, these readable and writable data have variables that are assigned initial values. Suppose, these variables are stored in RAM, what will happen?
(3) Obviously, these variables assigned initial values ​​are stored in RAM, so once the power is turned off, these initial values ​​will disappear! In other words, our initial values ​​are gone!
(4)It can be seen that our data storage should be divided into power-off and power-on states for analysis. And we have talked so much above, in fact, the analysis of data storage is carried out in the power-on state.

Power-off state data storage

(1) From the above analysis, we can know that although the readable and writable data is stored in RAM in the power-on state, it is still stored in ROM in the power-off state. So, now I will explain the power-off and power-on storage of STM32.
(2) We compile an STM32 project file, and the following compilation results will appear. One of the lines is Program Size: Code=5984 RO-data=336 RW-data=56 ZI-data=1024 .
(3)
<1>Code: code segment, which stores the code part of the program.
<2>RO-data: read-only data segment, storing constants defined in the program.
<3>RW-data: Read and write data segment, storing global variables initialized to non-zero values.
<4>ZI-data: Zero-initialized readable and writable variables, storing uninitialized global variables and variables initialized to 0.

insert image description here

(4) The above are the four types of data generated by the code we finally wrote. But will these four types of data be stored in the ROM of STM32? At this time, we can double-click the project file --> the .map file appears --> slide to the end --> see the Total ROM Size, this is the data that is finally downloaded into the STM32.
(5) Careful friends will find out why this Total ROM Size = Code + RO Data + RW Data. Where does ZI-data go?
(6) When we explained the static data area above, we saw that the static data area was divided into BSS segment and data segment. Why do you need to partition the static data area? The explanation given is that when the program is compiled, no space is allocated for the data in the .bss segment, but only the size of the space required for recording data. When the program is executed, memory will be allocated for the data in the .bss segment.
(7) Someone may want to say again, how do I record the space required for the data? This is related to the compiler. I checked some information and found that this is related to the symbol table of the compiler. But the symbol table doesn't end up being stored into the chip. Therefore, I personally guess that if a program needs to access a variable, it first needs to know its address. Therefore, this address is finally stored in the code, and then this address is accessed, so no space is required. The initialized data is different. Even if I know the address to access and how much data to access, I don't know its initial value. So we need to store this initial value in ROM. Store this initial value into the corresponding RAM at the stage of program loading.

insert image description here

(8) Therefore, we know that in the power-off state, the data is stored in the ROM, as follows. (Note that Code does not appear in this picture, but we still need to know that Code data is stored in ROM)

insert image description here

Power-on state data storage

(1) Through the above analysis, we know the data storage in the power-off and power-on states. So what happened the moment it was powered on?
(2) The RO-Data data remains unchanged, the RW-Data data is copied to the RAM area, and a ZI-data area is divided in the RAM. When the program is executed, the data initialized to 0, the CPU will write 0 to the variable corresponding to ZI-data. Data that has not been initialized is a random value. This is why when we first learned C language, we repeatedly emphasized the need to initialize. But keil has done a lot of things for us. If your variables have not been initialized, when he divides the ZI-data area, he will clear this area to zero.

insert image description here

(3) The data of RO-Data is the data of the constant area, RW-Data corresponds to the data segment of the static area, and ZI-data corresponds to the BSS segment of the static area. What about the stack?
(4) The stack is divided by the startup file. If you are interested, you can open the STM32 startup file startup_stm32f10x_hd.s. He can see that the first part is to set the stack information, so the stack is divided by the startup file.

;1-栈
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> 栈配置,用于变量,函数调用
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x00000400    ; 1KB

                AREA    STACK, NOINIT, READWRITE, ALIGN=3 ;告诉汇编器汇编一个新的代码段或者数据段,名字叫做STACK,不初始化,可读可写,以8字节对齐
Stack_Mem       SPACE   Stack_Size  ;对应EQU的那一行,表示分配1KB的空间
__initial_sp

;2-堆                                                  
; <h> 堆配置,用于malloc等函数的动态内存分配
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200   ;512B

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3 ;告诉汇编器汇编一个新的代码段或者数据段,名字叫做HEAP,不初始化,可读可写,以8字节对齐
__heap_base  ;堆的起始地址
Heap_Mem        SPACE   Heap_Size ;对应EQU的那一行,表示分配512B的空间
__heap_limit

                PRESERVE8    ;当前堆栈8字节对齐
                THUMB        ;兼容 THUMB 指令,老的指令,16bit,现在Cortex-M3的都是THUMB-2指令,兼容16/32位

reference article

(1) What is the difference between RAM, ROM, and FLASH?
https://bbs.elecfans.com/jishu_1404990_1_3.html
(2) Analysis of MAP files in STM32 KEIL:
https://blog.csdn.net/qlexcel/article/details/78884379
(3) Talk about memory allocation The difference between (.data) section and (.bss) section? Why is it divided into .data segment and .bss segment?
https://blog.csdn.net/Ivan804638781/article/details/110209548
(4) Please describe which areas the memory occupied by an executable program is divided into? What is the role of each partition?
https://blog.csdn.net/Ivan804638781/article/details/110010286
(5) The difference between ROM, FLASH and RAM:
https://zhuanlan.zhihu.com/p/38339306
(6) MCU FLASH and RAM, ROM Relationship:
https://zhidao.baidu.com/question/151273888.html
(7) Storage and execution of STM32 MCU programs:
https://mp.weixin.qq.com/s/p5oa0oZLN4Aa1QjZofBYcA

Guess you like

Origin blog.csdn.net/qq_63922192/article/details/131945593
RAM