Home » Linux, OS Concepts and Networking » Operating System Concepts » C program memory layout and understanding text, data, code, heap and stack segments

C program memory layout and understanding text, data, code, heap and stack segments

.bss segment

 $ vim uninitiailsed_global_variable.c 
#include <stdio.h>
 
int uninitilised_global_variable;
 
int main(int argc, char **argv) {
        return 0;
}
 $ gcc -o uninitiailsed_global_variable uninitiailsed_global_variable.c 
$ size uninitiailsed_global_variable
   text	   data	    bss	    dec	    hex	filename
   1017	    272	      8	   1297	    511	uninitiailsed_global_variable

.data segment

The .data segment contains any global or static variables which have a pre-defined value and can be modified. That is any variables that are not defined within a function (and thus can be accessed from anywhere) or are defined in a function but are defined as static so they retain their address across subsequent calls.

$ vim initiailsed_global_variable.c 
#include <stdio.h>
 
int initilised_global_variable = 78;
 
int main(int argc, char **argv) {
        printf("address of : initilised_global_variable = %p\n", &amp;initilised_global_variable);
        return 0;
}
$ size initiailsed_global_variable
   text	   data	    bss	    dec	    hex	filename
   1156	    280	      4	   1440	    5a0	initiailsed_global_variable

Now lets run this program to check, what is the address assigned to our initiailsed global integer variable as,

 $ address of : initilised_global_variable = 0x804a01c 

Now, lets check using nm tool what is the predefined address space our program got from the compiler as,

$ nm -s a.out 
0804a020 B __bss_start
0804a020 b completed.7200
0804a014 D __data_start
0804a014 W data_start
08048350 t deregister_tm_clones
080483c0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a018 D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804a024 B _end
080484a4 T _fini
080484b8 R _fp_hw
080483e0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
080485e4 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
080484f0 r __GNU_EH_FRAME_HDR
080482ac T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
0804a01c D initilised_global_variable
080484bc R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses
080484a0 T __libc_csu_fini
08048440 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804840b T main
         U printf@@GLIBC_2.0
08048380 t register_tm_clones
08048310 T _start
0804a020 D __TMC_END__
08048340 T __x86.get_pc_thunk.bx

output of nm shows that we got the address for “int initilised_global_variable” i.e. 0x804a01c which is predefined as seen in “nm -s” in bold ( just before _IO_stdin_used in above nm output ) and after data segment address has started at “0804a014 D __data_start”

 $ vim local_initialised_and_uninitialised_variable.c 
#include <stdio.h>
 
int main(int argc, char **argv) {
        int local_initialised_variable = 78;
        int local_variable;
        return 0;
}
$ gcc -o local_initialised_and_uninitialised_variable local_initialised_and_uninitialised_variable.c 
$ size local_initialised_and_uninitialised_variable
   text	   data	    bss	    dec	    hex	filename
   1017	    272	      4	   1293	    50d	local_initialised_and_uninitialised_variable

.stack segment

 $ vim variables_in_stack.c 
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
 
//check cat /proc/pid/maps to know address printed belogs to stack
 
int main(int argc, char **argv) {
        int local_initialised_variable = 78;
        int local_uninitialised_variable;
        printf("Address of : local_initialised_variable = %p\n", &local_initialised_variable);
        printf("Address of : local_uninitialised_variable = %p\n", &local_uninitialised_variable);
 
        //create a infinite loop so we can check address mapped in /proc
        while(1); //this is just to identify where we got the address mapped 
 
        return 0;
}
 $ gcc -o variables_in_stack variables_in_stack.c 
$ ./variables_in_stack 
Address of : local_initialised_variable = 0xbf961c34
Address of : local_uninitialised_variable = 0xbf961c38

Now, lets identify from proc map of a process we created just now to identify which area the addresses we printed belongs to,

know the process Id as program running above from another terminal as,

 $ ps -ax | grep variables_in_stack
 6971 pts/9    R+     1:37 ./variables_in_stack

We can see, we have got 6971 as process Id, now lets check the process map from proc file system as,

 $ cd /proc/6971/ 
 $ ls 
$ sudo cat maps 
08048000-08049000 r-xp 00000000 08:06 13894234   variables_in_stack
08049000-0804a000 r--p 00000000 08:06 13894234   variables_in_stack
0804a000-0804b000 rw-p 00001000 08:06 13894234   variables_in_stack
09859000-0987a000 rw-p 00000000 00:00 0          [heap]
b7539000-b76e9000 r-xp 00000000 08:06 18879084   /lib/i386-linux-gnu/libc-2.23.so
b76e9000-b76eb000 r--p 001af000 08:06 18879084   /lib/i386-linux-gnu/libc-2.23.so
b76eb000-b76ec000 rw-p 001b1000 08:06 18879084   /lib/i386-linux-gnu/libc-2.23.so
b76ec000-b76ef000 rw-p 00000000 00:00 0 
b771b000-b771d000 rw-p 00000000 00:00 0 
b771d000-b771f000 r--p 00000000 00:00 0          [vvar]
b771f000-b7720000 r-xp 00000000 00:00 0          [vdso]
b7720000-b7742000 r-xp 00000000 08:06 18874426   /lib/i386-linux-gnu/ld-2.23.so
b7742000-b7743000 rw-p 00000000 00:00 0 
b7743000-b7744000 r--p 00022000 08:06 18874426   /lib/i386-linux-gnu/ld-2.23.so
b7744000-b7745000 rw-p 00023000 08:06 18874426   /lib/i386-linux-gnu/ld-2.23.so
bf942000-bf963000 rw-p 00000000 00:00 0          [stack]

As we can see above, the address printed by our program are 0xbf961c34 and 0xbf961c38 and the stack memory allocated for this program ranges from bf942000 to bf963000 . Which shows that the local variables resides in the stack memory of a program.

Heap Memory allocation

 $ vim memory_allocated_in_heap.c 
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char **argv) {
        int *memory = malloc(sizeof(int));
        printf("Address of : int memory allocated = %p\n", memory);
        while(1);
        return 0;
}

Subscribe our Rurban Life YouTube Channel.. "Rural Life, Urban LifeStyle"

Leave a Comment