How Ghidra Manages Memory and Address Spaces in Reverse Engineering

Ghidra represents program memory through a hierarchy of immutable AddressSpace objects created by an AddressFactory, where each Program instance maintains unique physical and overlay spaces that isolate RAM, registers, stacks, and constants into distinct namespaces.

Ghidra’s memory model is fundamental to its reverse engineering capabilities, enabling accurate disassembly and decompilation across diverse processor architectures. According to the NationalSecurityAgency/ghidra source code, the framework implements a type-safe, space-aware addressing system that prevents accidental cross-space address manipulation while supporting complex memory layouts including overlays and Harvard architectures.

Core Architecture of Ghidra Memory Management

AddressSpace and GenericAddressSpace

At the foundation of Ghidra memory management lies the AddressSpace interface, defined in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/AddressSpace.java. This immutable object identifies a namespace for addresses, encapsulating:

  • Name (e.g., "ram", "register", "stack")
  • Size (addressable range)
  • Type (ram, register, stack, constant, unique, other)
  • Unique ID (compact integer for fast indexing)

The concrete implementation GenericAddressSpace, located in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/GenericAddressSpace.java, provides the standard behavior for most built-in spaces. Addresses from different spaces are never interchangeable, preventing architectural errors during analysis.

AddressFactory and Address Creation

Each Program instance owns a unique AddressFactory, implemented in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/AddressFactory.java. This factory serves as the central authority for:

  • Creating Address objects via getAddress(String) and getAddress(long)
  • Parsing address strings such as ram:0x1000 or 0x1000 (default space)
  • Enumerating available spaces through getAddressSpaces() and getAddressSpace(String)
  • Determining if multiple memory spaces exist via hasMultipleMemorySpaces() (critical for Harvard architectures)

Memory Blocks and Physical Layout

Memory and MemoryBlock Interfaces

The Memory interface, defined in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java, represents the collection of MemoryBlock instances that occupy one or more address spaces. Each MemoryBlock, detailed in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java, represents a contiguous region of bytes associated with a specific AddressSpace.

The database-backed implementation MemoryBlockDB in Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryBlockDB.java provides the runtime persistence layer for these blocks.

Block Types and Permissions

Ghidra supports several memory block types through the Memory interface:

  • Initialized blocks: Contain actual byte values loaded from the binary
  • Uninitialized blocks: Reserve address ranges without backing storage
  • Byte-mapped blocks: Map existing memory to a new address range
  • Bit-mapped blocks: Map individual bits for packed bit fields
  • Overlay blocks: Create alternate views of physical memory

Each block maintains permissions (read, write, execute) and flags indicating whether it is loaded, volatile, or part of the overlay system.

Working with Address Spaces in Code

The following examples demonstrate how to interact with Ghidra's memory and address space APIs using the core framework classes.

// ------------------------------------------------------------
// 1. Obtain the address factory from a program
// ------------------------------------------------------------
Program prog = ...;                     // a loaded Program instance
AddressFactory af = prog.getAddressFactory();

// ------------------------------------------------------------
// 2. Look up a known space (e.g., RAM) and create an address
// ------------------------------------------------------------
AddressSpace ram = af.getAddressSpace("ram");
Address addr = ram.getAddress(0x0010_0000L);   // 0x00100000 in RAM

// ------------------------------------------------------------
// 3. Create an initialized memory block in RAM
// ------------------------------------------------------------
Memory mem = prog.getMemory();
mem.createInitializedBlock(
        "myData",               // block name
        addr,                   // start address
        new ByteArrayInputStream(new byte[]{0x01,0x02,0x03,0x04}),
        4,                      // length
        new TaskMonitorAdapter(),
        false);                 // not an overlay

// ------------------------------------------------------------
// 4. Iterate over all loaded/initialized addresses
// ------------------------------------------------------------
AddressSetView initSet = mem.getLoadedAndInitializedAddressSet();
AddressIterator it = initSet.getAddresses(true);
while (it.hasNext()) {
    Address a = it.next();
    byte b = mem.getByte(a);
    // process byte...
}

Overlay Address Spaces and Alternate Views

Overlay blocks provide a mechanism to create alternate views of physical memory without modifying the original layout. This is particularly useful for analyzing patched firmware or modified code paths.

// ------------------------------------------------------------
// 5. Create an overlay block (alternative view)
// ------------------------------------------------------------
Address overlayStart = af.getAddressSpace("ram").getAddress(0x2000);
mem.createInitializedBlock(
        "overlayPatch",
        overlayStart,
        null,           // zero‑initialized
        0x100,          // 256 bytes
        new TaskMonitorAdapter(),
        true);          // <‑‑ overlay flag

// ------------------------------------------------------------
// 6. Determine the physical space of an overlay address
// ------------------------------------------------------------
Address overlayAddr = overlayStart.add(0x10);
AddressSpace overlaySpace = overlayAddr.getAddressSpace();
AddressSpace physical = overlaySpace.getPhysicalSpace(); // == ram

When an overlay block is created, Ghidra instantiates a new overlay address space with a distinct name while maintaining a reference to the underlying physical space via getPhysicalSpace(). This allows analysis tools to treat patched regions independently while preserving the relationship to the original memory layout.

Address Space Properties and Implementation Details

Space IDs and Fast Indexing

Each AddressSpace maintains a compact integer space ID accessible via getSpaceID(). The encoding utilizes bit masks (ID_SIZE_MASK, ID_TYPE_MASK) defined in AddressSpace.java to pack type information and size constraints into the ID for fast array indexing and comparison operations.

Addressable Unit Size and Offset Handling

Spaces may define an addressable unit size through getAddressableUnitSize(), which specifies the number of bytes per addressable word. This is critical for architectures where a single address refers to multi-byte words (e.g., 4-byte word spaces). The conversion between byte offsets and addressable word offsets is handled internally by the space implementation.

Certain space types, particularly TYPE_STACK, utilize signed offsets indicated by hasSignedOffset(). Arithmetic operations such as add, subtract, and truncateOffset apply appropriate sign-extension semantics based on the space type, ensuring correct behavior for stack-relative addressing and other signed offset contexts.

Summary

  • AddressSpace objects provide immutable namespaces that isolate RAM, registers, stacks, and constants, preventing cross-space address confusion.
  • AddressFactory serves as the central authority for creating addresses and managing the collection of spaces associated with a Program.
  • Memory and MemoryBlock interfaces model physical memory layout, supporting initialized, uninitialized, mapped, and overlay block types.
  • Overlay address spaces create alternate views of physical memory via getPhysicalSpace(), enabling analysis of patched firmware without modifying base layouts.
  • Space-specific properties including space IDs, addressable unit sizes, and signed offset handling ensure architecture-accurate address arithmetic.

Frequently Asked Questions

What is the difference between an AddressSpace and a MemoryBlock in Ghidra?

An AddressSpace is an immutable namespace that defines a range of valid addresses (such as RAM or registers), while a MemoryBlock is a contiguous region of bytes that occupies a specific range within an AddressSpace. Multiple MemoryBlocks can exist within the same AddressSpace, but addresses from different AddressSpaces are never interchangeable.

How does Ghidra handle Harvard architecture processors with separate code and data spaces?

Ghidra's AddressFactory detects multiple memory spaces via hasMultipleMemorySpaces(), returning true for Harvard architectures. The factory maintains separate AddressSpace instances for code and data (e.g., "ram" and "rom"), and analysis passes treat each space independently while the Program model coordinates between them.

What is an overlay memory block and when should I use one?

An overlay memory block creates an alternate view of existing physical memory by instantiating a new overlay AddressSpace that maps to the same underlying bytes via getPhysicalSpace(). Use overlays when analyzing patched firmware, modified code paths, or alternative memory mappings that should remain isolated from the original program layout to prevent corruption of the base analysis.

How are address space IDs used for performance optimization?

Each AddressSpace encodes a compact integer space ID using bit masks (ID_SIZE_MASK, ID_TYPE_MASK) that pack type and size information into a single integer. These IDs enable fast array indexing and comparison operations throughout Ghidra's analysis engine, avoiding expensive string comparisons when validating address ranges or performing arithmetic operations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →