The interested reader can peruse the first part of this series here – <An understanding of memory layout in C – Part 1>
From the previous article it was seen how the different layers of memory are aligned for a C program that runs on a system.
A “C” Program is provided below which progressively adds various variables and looks at different instances and how memory changes with the addition of different types of variables.
/* function with no variables added */
int main () {
return 0;
}
now compile via gcc to obtain the memory layout with the “size” command
$ gcc Test_memory_Layout.c -o Test_memory_Layout_barebones.o
$ size Test_memory_Layout.o
text data bss dec hex filename
1099 544 8 1651 673 Test_memory_Layout.o
Note: Analyzing the different segments, .text/.data and .bss segments are present. The .stack and .heap segments are not shown by the “size command”. This is because – both the stack and heap are run-time allocations and are dynamic and not shown at compilation time.
Adding Global variables to the program
/* global variables added to function */
#include <stdio.h>
#include <stdlib.h>
int value_int; /* value stored in .BSS – unintialized data segment – init to zero*/
int value_int_1 = 10; /* value stored in initialized data segment */
int main () {
return 0;
}
$ gcc Test_memory_Layout.c -o Test_memory_Layout.o
$ size Test_memory_Layout.o
text data bss dec hex filename
1099 548 12 1659 67b Test_memory_Layout.o
it can be seen that the initialized data segment and the bss segment is increased by 4.
Add static variables – initialized and un-initialized into code
/* static variables added to function */
int value_int; /* value stored in .BSS – unintialized data segment – init to zero*/
int value_int_1 = 10; /* value stored in initialized data segment */
int main () {
static int value2; /* value stored in .BSS – uninitialized data segment – init to zero */
static int value3 = 5; /* value stored in initialized data segment */
return 0;
}
$ gcc Test_memory_Layout.c -o Test_memory_Layout.o
$ size Test_memory_Layout.o
text data bss dec hex filename
1099 552 16 1667 683 Test_memory_Layout.o
it is seen that the .data and ,bss sections increased by size 4 again
Adding an un-initialized global array
int value_int;
int value_int_1 = 10;
int value[10];
int main () {
static int value2; /* value stored in .BSS – uninitialized data segment – init to zero */
static int value3 = 5; /* value stored in initialized data segment */
return 0;
}
$ gcc Test_memory_Layout.c -o Test_memory_Layout.o
$ size Test_memory_Layout.o
text data bss dec hex filename
1099 552 80 1731 6c3 Test_memory_Layout.o
As seen above – the .BSS segment increased to accomodate the un-initialized array
Add an initialized array to the midst
int value_int;
int value_int_1 = 10;
int value[10];
int val[2] = {1, 2};
int main () {
static int value2; /* value stored in .BSS – uninitialized data segment – init to zero */
static int value3 = 5; /* value stored in initialized data segment */
return 0;
}
$ gcc Test_memory_Layout.c -o Test_memory_Layout.o
$ size Test_memory_Layout.o
text data bss dec hex filename
1099 564 80 1743 6cf Test_memory_Layout.o
And as expected the .data segment increased to accomodate the initialized array.
All constant variables usually go into the .text segment or .rodata segment. #define variables are not allocated memory. The preprocessor replaces the #define value in code whenever it is used. Hence, #define values form part of text segment
Pingback: An understanding of memory layout in C – Part 1 | Hitch Hiker's Guide to Learning