C Program Memory Layout

C
Author

Imad Dabbura

Published

October 19, 2022

Below is how a typical C program memory layout would look like (program was run on macOs, but the arrangement is the same on any UNIX system). As you might expect (with stack grows downward from higher to lower addresses), the memory segments will be in the following order:

I omitted few segments such as read-only data, init, etc. The code that produced the layout can be found at the endof the page (credit: Advanced Programming in the Unix Environment)

High address (args and env):
----------------------------
envp[55] at                                            : 0x7FF7BE0AD5D0
environ[55] at                                         : 0x7FF7BE0AD5D0
envp[0] at                                             : 0x7FF7BE0AD418
environ[0] at                                          : 0x7FF7BE0AD418
last arg at                                            : 0x7FF7BE0AD410
first arg at                                           : 0x7FF7BE0AD408

Stack:
------
First variable inside main at                          : 0x7FF7BE0AD294
faun_array[] ends at                                   : 0x7FF7BE0AD2C0
func_array[] (like 'array[]', but on stack) begins at  : 0x7FF7BE0AD2B0
argc at                                                : 0x7FF7BE0AD2A8
argv at                                                : 0x7FF7BE0AD2A0
envp at                                                : 0x7FF7BE0AD298
func2 (from main): frame at                            : 0x7FF7BE0AD254
func frame at                                          : 0x7FF7BE0AD258
static int n within func at                            : 0x   101E5A06C
func (called     0 times): frame at                    : 0x7FF7BE0AD258
func2 (from func): frame at                            : 0x7FF7BE0AD234

Shared memory:
--------------
shared memory attachment begins at                     : 0x   101F84000
shared memory attachment ends at                       : 0x   101F9C6A0

Heap:
-----
malloced area ends at                                  : 0x6000026AD120
malloced area begins at                                : 0x6000026AD100

Uninitialized Data (BSS):
-------------------------
Semaphore at                                           : 0x   101E5A0F4
Cond at                                                : 0x   101E5A080
Lock at                                                : 0x   101E5A0B0
array[] ends at                                        : 0x   101E5A080
array[] (uninitialized, fixed-size char * on BSS) from : 0x   101E5A070
num2 (uninitialized global int) at                     : 0x   101E5A0F0
string2 (uninitialized global char *) at               : 0x   101E5A0F8
extern **environ at                                    : 0x7FF8497239A0

Initialized Data:
-----------------
num (initialized global int) at                        : 0x   101E5A068
string (initialized global char *) at                  : 0x   101E5A060

Text Segment:
-------------
func2 (function) at                                    : 0x   101E55440
func (function) at                                     : 0x   101E55470
main (function) at                                     : 0x   101E54F20
#include <errno.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/shm.h>

#define ARRAY_SIZE 16
#define MALLOC_SIZE 32
#define SHM_SIZE 100000
#define SHM_MODE 0600

char array[ARRAY_SIZE];
char *string = "a string";
char *string2;
int num = 10;
int num2;
pthread_mutex_t lock;
pthread_cond_t cond;
sem_t sem;
extern char **environ;

void func(int);
void func2(const char *);

int main(int argc, char **argv, char **envp) {
    int vars;
    int shmid;
    char *ptr;

    char func_array[ARRAY_SIZE];

    vars = 0;
    char **tmp = envp;
    while (*tmp++) {
        vars++;
    }

    (void)printf("High address (args and env):\n");
    (void)printf("----------------------------\n");
    (void)printf("envp[%d] at                                            : 0x%12lX\n", vars, (unsigned long)&envp[vars]);
    (void)printf("environ[%d] at                                         : 0x%12lX\n", vars, (unsigned long)&environ[vars]);
    (void)printf("envp[0] at                                             : 0x%12lX\n", (unsigned long)envp);
    (void)printf("environ[0] at                                          : 0x%12lX\n", (unsigned long)environ);
    (void)printf("last arg at                                            : 0x%12lX\n", (unsigned long)&argv[argc]);
    (void)printf("first arg at                                           : 0x%12lX\n", (unsigned long)&argv[0]);
    (void)printf("\n");

    (void)printf("Stack:\n");
    (void)printf("------\n");
    (void)printf("First variable inside main at                          : 0x%12lX\n", (unsigned long)&vars);
    (void)printf("func_array[] ends at                                   : 0x%12lX\n", (unsigned long)&func_array[ARRAY_SIZE]);
    (void)printf("func_array[] (like 'array[]', but on stack) begins at  : 0x%12lX\n", (unsigned long)&func_array[0]);

    (void)printf("argc at                                                : 0x%12lX\n", (unsigned long)&argc);
    (void)printf("argv at                                                : 0x%12lX\n", (unsigned long)&argv);
    (void)printf("envp at                                                : 0x%12lX\n", (unsigned long)&envp);

    func2("from main");
    func(0);

    (void)printf("\n");

    printf("Shared memory:\n");
    printf("--------------\n");
    if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0) {
            fprintf(stderr, "Unable to get shared memory: %s\n",
                strerror(errno));
            exit(1);
        }

        if ((ptr = shmat(shmid, 0, 0)) == (void *)-1) {
            fprintf(stderr, "Unable to map shared memory: %s\n",
                strerror(errno));
            exit(1);
        }
        printf("shared memory attachment begins at                     : 0x%12lX\n", (unsigned long)ptr);
        printf("shared memory attachment ends at                       : 0x%12lX\n", (unsigned long)ptr+SHM_SIZE);  (void)
    printf("\n");
    printf("Heap:\n");
    (void)printf("-----\n");
    if ((ptr = malloc(MALLOC_SIZE)) == NULL) {
        err(EXIT_FAILURE, "unable to allocate memory");
        /* NOTREACHED */
    }

    (void)printf("malloced area ends at                                  : 0x%12lX\n", (unsigned long)ptr+MALLOC_SIZE);
    (void)printf("malloced area begins at                                : 0x%12lX\n", (unsigned long)ptr);
    free(ptr);
    (void)printf("\n");

    (void)printf("Uninitialized Data (BSS):\n");
    (void)printf("-------------------------\n");
    (void)printf("Semaphore at                                           : 0x%12lX\n", (unsigned long)&sem);
    (void)printf("Cond at                                                : 0x%12lX\n", (unsigned long)&cond);
    (void)printf("Lock at                                                : 0x%12lX\n", (unsigned long)&lock);
    (void)printf("array[] ends at                                        : 0x%12lX\n", (unsigned long)&array[ARRAY_SIZE]);
    (void)printf("array[] (uninitialized, fixed-size char * on BSS) from : 0x%12lX\n", (unsigned long)&array[0]);
    (void)printf("num2 (uninitialized global int) at                     : 0x%12lX\n", (unsigned long)&num2);
    (void)printf("string2 (uninitialized global char *) at               : 0x%12lX\n", (unsigned long)&string2);
    (void)printf("extern **environ at                                    : 0x%12lX\n", (unsigned long)&environ);
    (void)printf("\n");

    (void)printf("Initialized Data:\n");
    (void)printf("-----------------\n");
    (void)printf("num (initialized global int) at                        : 0x%12lX\n", (unsigned long)&num);
    (void)printf("string (initialized global char *) at                  : 0x%12lX\n", (unsigned long)&string);
    (void)printf("\n");

    (void)printf("Text Segment:\n");
    (void)printf("-------------\n");
    (void)printf("func2 (function) at                                    : 0x%12lX\n", (unsigned long)&func2);
    (void)printf("func (function) at                                     : 0x%12lX\n", (unsigned long)&func);
    (void)printf("main (function) at                                     : 0x%12lX\n", (unsigned long)&main);
    (void)printf("\n");
    return EXIT_SUCCESS;
}


void func(int recurse) {
    int fint;
    char *msg = "from func";

    /* Change this value to 0 and note how
     * the location of where it is stored
     * changes from the Data to BSS segment. */
    static int n = 0;
    (void)printf("func frame at                                          : 0x%12lX\n", (unsigned long)&fint);

    if (recurse) {
        msg = "recursive";
    }
    (void)printf("static int n within func at                            : 0x%12lX\n", (unsigned long)&n);
    printf("func (called %5d times): frame at                    : 0x%12lX\n", n, (unsigned long)&fint);

    n++;
    func2(msg);
}

void func2(const char *how) {
    int fint;
    (void)printf("func2 (%s): frame at                            : 0x%12lX\n", how, (unsigned long)&fint);
    func(1);
}