Memory Layout of the C program

reference:

  1. Compilation Steps and Memory Layout of the C Program

  2. Storage Class

  3. RAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储

  4. Memory Layout in C

Memory Layout of the C Program

When you run any C program, its executable image is loaded into the RAM of the computer in an organized manner which is called the process address space or memory layout of the C program. This memory layout is organized in the following fashion:

  1. Text or Code Segment
  2. Initialized Data Segments
  3. Uninitialized Data Segments(BSS)
  4. Stack Segment
  5. Heap Segment
  6. Unmapped or Reserved Segments

layout of the c program

Text or Code Segment

The code segment, also known as the text segment which contains the machine code of the compiled program. The text segment of an executable object file is often a read-only segment that prevents a program from accidently modified. So this memory contains .bin or .exe or .hex etc.

As a memory region, a text segment may be placed below the heap or stack in order to prevent heaps and stack overflows from overwriting it.

Data Segments

The data segment stores program data. This data could be in the form of initialized or uninitialized variables, and it could be local or global. The data segment is further divied into four sub-data segments(initialized data segment, uninitialized or .bss data segment, stack and heap) to store variables depending upon if they are local or global, and initialzed or uninitialized.

Initialized Data Segment

Initialized data or simply data segment stores all global, static, constant and external variables(declared with extern keyword) that are initialized beforehand.

Note that, that data segment is not read-only, since the values of the variables can be changed at run time.

This segment can be further classified into the initialized read-only area and the initialized read-write
area.

All global, static and external variables are stored in initialized read-write memory except the const variable.

// This will be stored in initialized read-only memory
const int i = 100;

// This will be stored in initialized read-write memory
int j = 1;
char c[12] = "EmbeTronicX"

int main()
{

}

Uninitialized Data Segment

The uninitialized data segment is also called as BSS segment. BSS stands for Block Started by Symbol named after an ancient assembler operator. The uninitialized data segment contains all global and static variables that are initialzed to zero or do not have explicit initialization in the source code.

// This will be stored in uninitialized read-only memory <- incorrect
// ATTENETION: actually the comment above is incorrect.The i and j will both be stored in BSS segment where variables can be written to or read from.
static int i = 0;
int j;

int main()
{

}

Stack Segment

The stack is the place where automatic variables are stored, along with information that is saved each time a function is called. Each time a function is called, the address of where to return to and certain informain about the caller's enviroment, such as some of the machien registers, are saved on the stack. The newly called function then allocates room on the stack for its automatic and temporary variables. This is how recursive functions in C can work. Each time a recursive function calls itself, a new stack frame is used, so one set of variables doesn't interfere with the variables from another instance of the function.

So, the Stack frame contains some data like the return address, arguments passed to it, local variables, and any other information needed by the invoked function.

A "stack pointer(sp)" keeps track of the stack by each push & pop operation onto it, by adjusting the stack pointer to the next or previous address.

The stack area traditionally adjoined the heap area and grew in the opposite direction; when the stack pointer met the heap pointer, free memory was exhausted. (With modern large address spaces and virtual memory techniques they may be placed almost anywhere, but they still typically grow in opposite directions.)

You can learn the stack implementation in the C program in this article.

Heap Segment

Heap is the segment where dynamic memory allocation usually takes place.

The heap area begins at the end of the BSS segment and grows to larger addresses from there. The area is managed by malloc, realloc, and free, which may use the brk and sbrk system calls to adjust its size(note that the use of brk/sbrk and a single “heap area” is not required to fulfill the contract of malloc/realloc/free; they may also be implemented using mmap to reserve potentially non-contiguous regions of virtual memory into the process’ virtual address space). The Heap area is shared libraries and dynamically loaded modules in a process.

Unmapped or reserved segment

Unmapped or reserved segments contain command-line arguments and other program-related data like the lower address-higher address of the executable image, etc.

Memory layout in C with examples

Just see the below example. I will tell you the Memory layout using a practical example.

Example

Step 1

We will see the memory layout of the below program.

#include <stdio.h>
int main(void)
{
    return 0;
}

Compile and Check memory.

[embetronicx@linux]$ gcc memory-layout-test.c -o memory-layout-test

[embetronicx@linux]$ size memory-layout-test

text       data        bss        dec         hex       filename
960        248          8        1216         4c0    memory-layout-test
Step 2

Let us add one global variable in the program, now check the size of bss.

#include <stdio.h>
int embetronicx;   //uninitialized global variable. It will stored in bss
int main(void)
{
    return 0;
}

Compile and Check Memory.

[embetronicx@linux]$ gcc memory-layout-test.c -o memory-layout-test

[embetronicx@linux]$ size memory-layout-test

text       data        bss        dec        hex    filename

960        248         12       1220         4c4    memory-layout-test
Step 3

Let us add one static variable which is also stored in bss.

#include <stdio.h>
int embetronicx;   //uninitialized global variable. It will stored in bss
int main(void)
{     
    static int i;  //Uninitialized static variable stored in bss
    return 0;
}

Compile and Check.

[embetronicx@linux]$ gcc memory-layout-test.c -o memory-layout-test

[embetronicx@linux]$ size memory-layout-test

text       data        bss        dec          hex    filename

960        248         16         1224         4c4    memory-layout-test
Step 4

Let us initialize the static variable to non zero which will then be stored in the Initialized Data Segment (DS).

#include <stdio.h>

int embetronicx;   //uninitialized global variable. It will stored in bss

int main(void)
{
    static int i = 10;  //Initialized static variable stored in Initialized Data Segment
    return 0;
}

Compile and Check.

[embetronicx@linux]$ gcc memory-layout-test.c -o memory-layout-test

[embetronicx@linux]$ size memory-layout-test

text       data        bss        dec          hex    filename

960        252         12         1224         4c4    memory-layout-test
Step 5

Let us initialize the global variable to non zero which will then be stored in the Initialized Data Segment (DS).

#include <stdio.h>

int embetronicx = 100;   //Initialized Global variable stored in Initialized Data Segment

int main(void)
{
    static int i = 10;  //Initialized static variable stored in Initialized Data Segment
    return 0;
}

Compile and Check

[embetronicx@linux]$ gcc memory-layout-test.c -o memory-layout-test

[embetronicx@linux]$ size memory-layout-test

text       data        bss        dec          hex    filename

960        256          8         1224         4c4    memory-layout-test

Memory layout experiment by myself

reference:

#include <stdio.h>

// To use the `size` command of the gcc compiler, the memory layout of a c program will be displayed in a format like the one below:
// size --format=sysv memory-layout.exe
/*
memory-layout.exe  :
section           size      addr
.text            11156   4198400
.data               28   4210688
.rdata             720   4214784
.eh_frame         2468   4218880
.bss               112   4222976
.idata            1448   4227072
.CRT                24   4231168
.tls                32   4235264
.debug_aranges      56   4239360
.debug_info       7423   4243456
.debug_abbrev      303   4251648
.debug_line        456   4255744
.debug_frame        56   4259840
Total            24282
*/

// if a global variable is assigned a value of zero, it will be stored in read-only memory
// this means an uninitialized variable is stored in the same place where a variable is assigned to zero, also known as the bss segment
// these will be stored in read-only memory(uninitialized segment, also known as the bss segment)
// int global_i = 0; // is equal to int global_i;
// static int global_j = 0; // is equal to global_j;
// const int global_kk;
// static const int global_kk;

// if a global variable is assigned a value that is not equal to zero or uninitialized, it will be stored in the read-write initialized segment
// int global_i = 1;  
// static int global_j = -1; 

// will be stored in the read-only initialized segment
// const int global_kk = 1; // is equal to const global_kk = 0;
// static const int global_kk = 1;  // // is equal to const global_kk = 0;

int main(void)
{
    // int local_i = 1; // this will be stored in stack
    // const int local_k = 1; // this will be stored in stack
        
    // static int local_jj; // this will be stored in bss
    // variables with the prefix keyword "static" will be stored in read-write memory(initialized segment)
    // static int local_j = 0; // this will be stored in read-write memory(initialized segment)
    // static const int local_kk = 1;
        
    return 0;
}
posted @ 2024-04-26 18:04  stitchCat  阅读(35)  评论(0)    收藏  举报