Skip to main content

Rust

Day 10: Heap vs Stack

Hello, fellow Rustaceans! 🦀

Today, we’re stepping back a bit from the specifics of C or Rust. Instead, we’re going to discuss concepts that are foundational across all programming languages you might encounter. Understanding these concepts is crucial as they will form the basis for our upcoming discussions. So, let’s dive in!

Memory Layout of an Application

A lot of programming books often overlook a critical aspect of programming — the Memory layout. Understanding memory layout is crucial for debugging, optimizing performance, security, and interfacing with low-level systems. Let's look at an example

#include <stdio.h>
#include <stdlib.h>

// Global variable in the data segment
int global_data = 10;

// Uninitialized global variable in the BSS segment
int global_bss;

int main() {

    // Local variable in the stack segment
    int stack_var = 5;

    // Dynamically allocated memory in the heap segment
    int* heap_var = malloc(sizeof(int));
    *heap_var = 7;

    printf("Global Data: %d\n", global_data);
    printf("Stack Variable: %d\n", stack_var);
    printf("Heap Variable: %d\n", *heap_var);

    free(heap_var);

    return 0;
}

Looking at the program can you anticipate the layout of the application? Can we predict which sections these variables will be part of just by looking at the code? The answer is, indeed, yes. This is all done by the linker and compiler. When the compiler compiles a program, it creates different sections for each object it generates. The linker then gathers all these sections based on linker scripts and produces the final binary. Don’t fret, we’ll break down all of this step by step. First, let’s explore the different sections that exist and how the compiler determines what to place where.