Every running program (process) occupies some memory for its code and data. Linux follows a particular methodology for assigning memory addresses to various parts of a program. Linux assigns a “segment” to each of the following, where a segment can be defined as a single memory block of variable size:
- TEXT
This is the code segment and contains only the executable code of the program. In Linux, this is a read-only segment, implying that it’s contents can never be overwritten by the program. Thus, Linux does not support self-modifying code. - DATA
This segment contains all the data that is required throughout program execution. In C terms, this includes all extern and static variables. This is split into two physical parts:- Initialized Data Segment
This contains all the extern and static variables of the program that been explicitly initialized in the program - Uninitialized Data Segment (Also called BSS: Block Started by Symbol, a historial and outdated term!)
This contains all the extern and static variables of the program that not been explicitly initialized in the program, and hence have to be automatically initialized to 0.
- Initialized Data Segment
- STACK
This segment contains all local variables that are created when control enters a function. Note that these also include function parameters. - HEAP
This segment is internally kept track via a linked list, and is used by dynamic variables (memory allocated using malloc and calloc). Frequent memory allocations and deallocations result in fragmentation here.
The memory layout of a typical C program is shown below:
There is a strong reason for this arrangement. Note these points:
- The TEXT segment is loaded from the executable file
- The DATA segment is also blindly loaded from the executable file
These points mean that the first part of the memory is a copy of data from the executable - The BSS segment is NOT stored in the executable!
This saves space, as the whole block is anyway full of zeros. - The HEAP and the STACK grow towards each other.
This ensures that both have enough space, and you would not get problems like too much stack space and too little heap space or vice-versa - The Command Line Arguments and the Environment are dumped at the far end of the accessible memory block.
Finally, note that all addresses discussed here are logical addresses, and the actual physical address can be mapped anywhere in memory!
Given below is a C program to illustrate the above concept. We have:
- An initialized global variable, called init_global_var
- An uninitialized global variable, called global_var
- An initialized static variable in global scope, called init_static_var
- An uninitialized static variable in global scope, called static_var
- An initialized static variable within a function, called init_static_local_var
- An uninitialized static variable within a function, called static_local_var
- An initialized local variable, called init_local_var
- An uninitialized local variable, called local_var
- A dynamic variable, with address in dynamic_var
- An environment variable, with address in environ
/* * memorySegments.c * * A program to illustrate the logical addressing space within processes * * (c) 2008 Nagesh Rao, CyberPlus Infotech Pvt. Ltd. */ #include <stdio.h> #include <stdlib.h> int init_global_var = 10; /* Initialized global variable */ int global_var; /* Uninitialized global variable */ static int init_static_var = 20; /* Initialized static variable in global scope */ static int static_var; /* Uninitialized static variable in global scope */ int main(int argc, char **argv, char **envp) { static int init_static_local_var = 30; /* Initialized static local variable */ static int static_local_var; /* Uninitialized static local variable */ int init_local_var = 40; /* Initialized local variable */ int local_var; /* Uninitialized local variable */ char *dynamic_var = (char*)malloc(100); /* Dynamic variable */ printf("Address of initialized global variable: %p\n", &init_global_var); printf("Address of uninitialized global variable: %p\n", &global_var); printf("Address of initialized static variable in global scope: %p\n", &init_static_var); printf("Address of uninitialized static variable in global scope: %p\n", &static_var); printf("Address of initialized static variable in local scope: %p\n", &init_static_local_var); printf("Address of uninitialized static variable in local scope: %p\n", &static_local_var); printf("Address of initialized local variable: %p\n", &init_local_var); printf("Address of uninitialized local variable: %p\n", &local_var); printf("Address of function (code): %p\n", &main); printf("Address of dynamic variable: %p\n", dynamic_var); printf("Address of environment variable: %p\n", &envp[0]); exit(0); }
The output of the program on my system is as follows:
Address of initialized global variable: 0x80498d4 Address of uninitialized global variable: 0x80498ec Address of initialized static variable in global scope: 0x80498d8 Address of uninitialized static variable in global scope: 0x80498e8 Address of initialized static variable in local scope: 0x80498dc Address of uninitialized static variable in local scope: 0x80498e4 Address of initialized local variable: 0xbf94a890 Address of uninitialized local variable: 0xbf94a88c Address of function (code): 0x80483e4 Address of dynamic variable: 0x86ff008 Address of environment variable: 0xbf94a92c
Related Articles
No user responded in this post