What is Memory Mapping?

Memory mapping is a technique used in computer systems to manage memory resources safely, it involves creating a virtual address space that corresponds directly to the physical memory or to a portion of it, this allows programs to access memory in a way that is safe and portable to different processor environments.

Why Does Software need Memory Mapping for a Safety Application?

Deterministic Access

Memory mapping allows for direct, predictable access to memory locations, ensuring that critical data can be accessed and manipulated reliably and consistently within a predefined and guaranteed time.

Deterministic Memory Layout

Deterministic Memory Layout refers to the practice of structuring the memory layout of a program in a predictable and repeatable manner. This approach ensures that the allocation and arrangement of data structures in memory remain consistent across different runs of the program, provided the same initial conditions.

Reduced Overhead

Memory mapping reduces the overhead associated with memory access compared to other methods such as dynamic memory allocation. Minimizing overhead is essential to ensure timely response to critical events.

Fault Isolation

Memory mapping can aid in fault isolation by providing a clear separation between different memory regions. By mapping memory regions for different tasks or subsystems, potential faults can be contained within specific areas, making it easier to identify and debug issues.

Let us study this case for non-deterministic Memory layout

A company tested their software in different test environments. Here are their observations:

  • They are using standard data types, where data widths are fixed across all execution environments, e.g., fixed-width integer types (int32_t, int64_t) from .
  • The size of the pointers usually varies from one build environment to another, e.g., a pointer variable can occupy 4 bytes in 32-bit target environment, and 8 bytes in a 64-bit target environment, and that increases code size in the 64-bit environment.
  • For example, consider the following structure in C programming:

    struct Example {
    char a;
    int *b;
    double c;};

On a 32-bit system, the size of int *b would be 4 bytes, whereas on a 64-bit system, it would be 8 bytes.

This difference can cause the structure to have different paddings and alignments, resulting in different total sizes and memory layouts.

Non-deterministic memory layout arises differences in pointer size across different environments. 

This scenario is particularly relevant when considering software that runs on both 32-bit and 64-bit architectures. 

The change in pointer size from 32-bit to 64-bit environments can lead to variations in memory allocation and layout, affecting both performance and behaviour of applications.

Key Factors of the Problem

  • Pointer Size Variation:
    On a 32-bit system, pointers are 4 bytes (32 bits) in size.
    On a 64-bit system, pointers are 8 bytes (64 bits) in size.
  • Structure Padding and Alignment:
    Data structures in C/C++ (and other languages) are often aligned for performance reasons. The change in pointer size can affect the alignment and padding of these structures, leading to different memory layouts
  • Data Structure Layout:
    Internal data structures, such as trees, linked lists, and hash tables, may have different memory layouts due to the varying sizes of pointers. This can affect traversal patterns, cache performance, and overall memory usage.

Solving The Problem:

  • In Linker allocate a memory section for example here "variable" with a size of 1 KB in a linker script

        . b (READWRITE):  /* 1KB read-write data section */
            KEEP (*); /* Include all symbols placed in this section */
            >1KB     /* Allocate at least 1KB of memory */
            /* No specific content needed here */
        ... /* Other sections */

  • SECTIONS: Defines the memory layout for your program. Each section holds specific types of data or code: from the .text section for code, .data for initialized data, .rodata for read-only data, .bss for uninitialized data, to custom sections for debugging information and more.
  • . b (READWRITE): Creates a section named "b" with the READWRITE attribute, indicating it is for data that can be modified during program execution.
  • KEEP (*): Ensures all symbols (variables) placed in this section are included in the final executable.
  • >1KB: Specifies that the linker should allocate at least 1KB of memory for this section. If the variable(s) placed here require less space, the remaining memory will be unused.
  • {/* No specific content needed here */}: Defines the section body, but you do not need to put anything specific here for this purpose.

Control the alignment and padding of data structures by using compiler-specific pragmas or attributes to control structure packing and alignment explicitly, you can use preprocessor directives provided by your compiler For Example, in C programming

#pragma section (". b")

int pointer [1024]; // This array will be placed in the. b section,
// assuming its size is less than 1KB (Whatever Pointer size changed it will be fit in this section

#pragma section () // Reset to default section

Important Note:

Your memory architecture should be reflected in the linker script, so the HEX file that is generated is always the correct size for any given architecture. (Like the previous example, all memory sections should have a maximum size (.text/.sdata/.rodata/...etc).


In any safety-critical software, any unexpected behaviour or failure can have severe consequences. Memory mapping helps to mitigate the issues arising from non-deterministic memory layouts (e.g., changes in pointer size across different environments in the example) by providing a reliable and maintainable memory architecture across different environments (32-bit and 64 bit), enabling developers to design systems that meet stringent safety requirements.

Tagged as:     memory mapping     functional safety     Eman Hamouda  

Other Blog Posts By Eman Hamouda