Course contentsShow
← Rust
Lesson 1820 of 1,91016. Specialized Runtime TargetsFree lesson

Defining Global Allocators

Implement the GlobalAlloc trait to interface with physical memory mapped at specific hardware addresses.

In this lesson, you will learn how to implement the GlobalAlloc trait to manage raw memory regions mapped to specific hardware addresses.

In embedded systems or specialized runtime environments, you often encounter "Memory Mapped" regions—specific ranges of physical RAM or external SRAM accessible via a fixed base address. To use these regions for dynamic allocations (e.g., Box or Vec), you must instruct the Rust runtime how to carve them up by implementing the GlobalAlloc trait.

Implementing the Trait

To define a global allocator, you create a struct and implement the unsafe fn alloc and unsafe fn dealloc methods. These methods are the interface between Rust’s memory management and your hardware-specific memory map.

struct HardwareAllocator;

unsafe impl GlobalAlloc for HardwareAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        // Assume 0x2000_0000 is our hardware-mapped SRAM base
        // In reality, you'd use a pointer-based freelist or bump allocator here
        let base_addr = 0x2000_0000 as *mut u8;
        base_addr
    }

    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
        // Logic to return memory to the pool
    }
}

#[global_allocator]
static GLOBAL: HardwareAllocator = HardwareAllocator;

Critical Considerations

When interfacing with hardware addresses, the GlobalAlloc contract requires that your implementation is thread-safe. Since alloc and dealloc take &self, if your allocator maintains state (like a pointer to the next free byte), you must wrap that state in a synchronization primitive—typically a Spinlock or a Mutex—to prevent data races when multiple threads (or interrupt handlers) request memory simultaneously.

Furthermore, you are responsible for ensuring that the Layout alignment requirements are respected. If the hardware expects 4-byte alignment, you must mask your returned pointers to satisfy those constraints; otherwise, you risk triggering a hardware fault. By defining this at the global level, you allow the entire standard library—or alloc-dependent libraries—to treat physical hardware addresses as managed heap memory.

Key Takeaway: Implementing GlobalAlloc allows you to bridge high-level Rust abstractions like Vec and Box with raw, hardware-mapped memory regions by defining custom allocation logic marked with the #[global_allocator] attribute.