Ghidra Processor Module Differences: Comparing x86, ARM, AArch64, and MIPS
Ghidra processor modules for x86, ARM, AArch64, and MIPS each implement architecture-specific semantics through distinct SLEIGH language definitions, register specifications, analysis plugins, and emulation handlers located under Ghidra/Processors/.
Ghidra's open-source reverse engineering framework maintained by the NationalSecurityAgency provides specialized support for CPU architectures through dedicated processor modules. Each module resides in its own subdirectory—such as Ghidra/Processors/x86 or Ghidra/Processors/AARCH64—and contains the complete infrastructure needed to disassemble, analyze, and emulate binaries for that specific instruction set architecture.
SLEIGH Language Definitions and Instruction Semantics
The SLEIGH language definition serves as the authoritative description of an ISA's instruction encoding and semantics, implemented in .slaspec files that generate p-code for Ghidra's intermediate representation.
x86 utilizes Ghidra/Processors/x86/data/languages/x86.slaspec, which includes dozens of supplemental .sinc files adding vector-extension semantics such as avx.sinc, bmi1.sinc, and SHA instructions. This modular approach accommodates the architecture's extensive vendor-specific extensions across 16-bit real-mode, 32-bit protected-mode, and 64-bit long-mode variants.
ARM (32-bit) splits definitions across multiple files like ARM8_le.slaspec and ARM8_be.slaspec to capture differing register banks, endianness, and instruction sets including Thumb-1 and Thumb-2. The SLEIGH file expands ARM's three-operand format to p-code while handling condition codes and mode-specific banked registers.
AArch64 employs a minimal AARCH64.slaspec that functions as a thin wrapper including AARCH64instructions.sinc. Because the ARMv8-A ISA is more orthogonal than its predecessor, this architecture requires fewer conditional variations in its language definition while supporting fixed-width 64-bit operations and advanced SIMD (ASIMD) extensions.
MIPS provides separate specifications for each address-space width and endianness, such as mips32le.slaspec and mips32be.slaspec, with additional variants for MIPS-64, micro-MIPS, and MIPS-R6. The SLEIGH definitions specifically handle the architecture's characteristic branch delay slots and coprocessor instructions.
Register Metadata and Processor Specifications
Each processor module defines its register set through .pspec and .ldefs files that map architectural registers into Ghidra's internal Register objects.
In Ghidra/Processors/x86/data/languages/x86.pspec and x86.ldefs, definitions span 16-, 32-, and 64-bit general-purpose registers, segment registers, flags, and extensive SIMD registers (XMM/YMM/ZMM). The x86 module must accommodate overlapping register views (such as al/ah/ax/eax/rax) within its specification.
The ARM module's ARM8.pspec enumerates R0-R15, the CPSR, and banked registers for different processor modes (FIQ, IRQ, Supervisor, etc.), reflecting the architecture's exception model.
AArch64 defines a cleaner register file in AARCH64.pspec featuring X0-X30 general-purpose registers, SP, PC, PSTATE, and 128-bit SIMD/FP registers V0-V31. This 64-bit specification eliminates the banking complexity present in the 32-bit ARM module.
For MIPS, mips.ldefs catalogs the general-purpose registers $0-$31, the HI/LO registers for multiplication results, CP0 system control registers, and floating-point registers. The specification must account for both the 32-bit and 64-bit register widths across different MIPS variants.
Analysis Plugins and Auto-Analysis
Architecture-specific analysis is implemented through Java classes extending Ghidra's analyzer framework, with each processor module containing specialized logic for detecting compiler idioms and architecture quirks.
The x86 module includes X86Analyzer.java located at Ghidra/Processors/x86/src/main/java/ghidra/app/plugin/core/analysis/X86Analyzer.java. This analyzer provides constant-propagation analysis with special handling for LEA (Load Effective Address) operand references and x86-specific addressing modes.
ARM analysis is handled by ARMProcessorAnalyzer within ARM/src/main/java/ghidra/app/plugin/core/analysis, which adds Thumb/ARM mode detection and conditional-execution analysis to handle the architecture's predicated instructions.
For AArch64, the AARCH64PltThunkAnalyzer.java at Ghidra/Processors/AARCH64/src/main/java/ghidra/app/plugin/core/analysis/AARCH64PltThunkAnalyzer.java focuses on PLT (Procedure Linkage Table) thunk discovery and linker-generated symbol identification specific to 64-bit ARM binaries.
The MIPS module provides MipsSymbolAnalyzer.java and MipsPreAnalyzer in Ghidra/Processors/MIPS/src/main/java/ghidra/app/plugin/core/analysis, which analyze GP-relative code sequences and handle the architectural conventions of the $gp register for global data access.
Emulation State Modifiers
Ghidra's generic p-code emulator requires architecture-specific adapters to handle privileged state transitions and ISA quirks, implemented through EmulateInstructionStateModifier subclasses.
The x86 module provides X86EmulateInstructionStateModifier to manage privileged mode changes, segment overrides, and the complex flag behaviors of the x86 family.
ARM emulation uses ARMEmulateInstructionStateModifier to handle processor mode switches, CPSR updates, and the transition between ARM and Thumb instruction sets during execution.
For AArch64, AARCH64EmulateInstructionStateModifier tracks PSTATE updates and Exception Level (EL) transitions critical to the ARMv8 security model and privileged execution environments.
The MIPS implementation, MIPSEmulateInstructionStateModifier, specifically manages HI/LO register semantics and properly emulates branch delay slots, ensuring that instructions following branches execute before the branch takes effect.
Binary Format and Relocation Handling
Processor modules implement architecture-specific relocation handlers to fix up addresses during binary import, parsing ELF and Mach-O relocation tables according to each ISA's addressing models.
x86 provides X86_64_ElfRelocationHandler, X86_32_ElfRelocationHandler, and X86_64_MachoRelocationHandler to process RIP-relative relocations in position-independent code and handle the various addressing modes specific to Intel and AMD extensions.
ARM relies on ARM_ElfRelocationHandler to manage Thumb interworking thunks and ARM-specific relocation types that support the architecture's mixed 16/32-bit instruction sets.
AArch64 uses AARCH64_ElfRelocationHandler to process the larger 64-bit relocation addends and PLT-related fixups common in modern ARM64 Linux and Android binaries.
MIPS implements MIPS_ElfRelocationHandler and MIPS_Elf64RelocationHandler to handle GP-relative relocations, micro-MIPS extension fixups, and the architecture-specific HI16/LO16 relocation pairs used for loading 32-bit constants.
Pattern Files and Heuristics
Auto-analysis heuristics reside in XML pattern files within each processor's data/patterns directory, enabling Ghidra to identify function prologues, thunks, and compiler-specific idioms.
The x86 module includes x86gcc_patterns.xml and x86win_patterns.xml to detect GCC and Microsoft Visual C++ function prologues, frame pointer setups, and calling convention variations.
ARM patterns detect Thumb prologues, LDR-PC loading sequences, and compiler-specific register save patterns across different ARM variants.
AArch64 pattern files focus on PLT stub detection and linker-generated symbol identifiers that facilitate automatic function recognition in stripped binaries.
MIPS patterns identify GP-relative code sequences and account for branch delay slot patterns when determining function boundaries and cross-references.
Working with Processor Modules in Ghidra Scripts
When programmatically interacting with Ghidra's processor modules, the framework automatically instantiates the correct language definition and analysis classes based on the imported binary's architecture.
Detecting Processor Module Assignment
import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Program;
public class ShowProcessorInfo extends GhidraScript {
@Override
protected void run() throws Exception {
// Prompt the user to select a file
String path = askFile("Select binary", "Open").getAbsolutePath();
// Import the file; Ghidra will auto-detect the appropriate language
Program prog = importFileIntoProject(path, false);
println("Language: " + prog.getLanguage().getLanguageID()); // e.g. x86:LE:64:default
println("Processor: " + prog.getLanguage().getProcessor()); // x86, ARM, AARCH64, MIPS
println("Endianness: " + prog.getLanguage().isBigEndian() ? "big" : "little");
}
}
When opening a 32-bit little-endian MIPS ELF, this script reports LanguageID: MIPS:LE:32:default, automatically selecting the appropriate processor module from Ghidra/Processors/MIPS.
Accessing Architecture-Specific Registers
// Inside a Ghidra script or plugin
import ghidra.program.model.lang.Register;
// Assume 'program' is already open
Register pc = program.getLanguage().getProgramCounter();
Register sp = program.getLanguage().getRegister("sp"); // works for all CPUs
println("PC = " + pc.getName() + " SP = " + sp.getName());
Note that register names vary by processor module: the x86 module uses eip or rip for the program counter, while ARM and AArch64 use pc, and MIPS typically uses a numerical representation depending on the specific variant.
Running the Architecture-Aware Emulator
import ghidra.pcode.emulate.EmulateInstructionStateModifier;
import ghidra.pcode.emulate.Emulate;
import ghidra.program.model.mem.MemoryAccessException;
Address addr = program.getAddressFactory().getDefaultAddressSpace().getAddress(0x401000);
Emulate emulate = new Emulate(program);
EmulateInstructionStateModifier modifier =
EmulateInstructionStateModifier.getProcessorEmulator(program);
emulate.setStateModifier(modifier);
try {
emulate.executeInstruction(addr);
println("Emulated instruction at " + addr);
} catch (MemoryAccessException e) {
printerr("Failed to read memory: " + e.getMessage());
}
The modifier instance resolves to X86EmulateInstructionStateModifier, ARMEmulateInstructionStateModifier, AARCH64EmulateInstructionStateModifier, or MIPSEmulateInstructionStateModifier based on the loaded program's language, ensuring correct emulation of architecture-specific behaviors such as x86 segment overrides or MIPS branch delay slots.
Summary
- SLEIGH Definitions: x86 uses extensive included
.sincfiles for extensions, ARM splits by mode/endianness, AArch64 uses a minimal wrapper, and MIPS provides separate files for width/endianness variants. - Register Specifications: Each module defines its register set in
.pspecfiles, with x86 supporting overlapping register views, ARM supporting banked registers, and AArch64 providing a flat 64-bit register file. - Analysis Plugins: x86 focuses on
LEAhandling (X86Analyzer.java), AArch64 on PLT thunks (AARCH64PltThunkAnalyzer.java), ARM on mode detection, and MIPS on symbol analysis (MipsSymbolAnalyzer.java). - Emulation: State modifiers handle x86 segments, ARM CPSR/modes, AArch64 exception levels, and MIPS HI/LO registers with branch delay slots.
- Relocations: Each processor implements ELF handlers for architecture-specific fixups including x86 RIP-relative, MIPS GP-relative, and ARM/AArch64 thunk relocations.
Frequently Asked Questions
How does Ghidra determine which processor module to use when importing a binary?
Ghidra examines the binary's file format headers—such as the ELF e_machine field or PE COFF header—to determine the target architecture, then maps this value to a language ID (e.g., x86:LE:64:default or MIPS:LE:32:default) defined in the processor module's .ldefs files. The importer automatically loads the corresponding SLEIGH specification and register definitions from the appropriate Ghidra/Processors/ subdirectory.
Can I manually specify a different processor module if Ghidra auto-detects incorrectly?
Yes, during the import process you can override the auto-detected language by selecting "Options" in the import dialog and choosing from the available languages in the dropdown menu. This allows you to force a specific processor module—for example, selecting a big-endian MIPS variant when Ghidra defaults to little-endian, or choosing a specific ARM variant with Thumb support.
What are the main differences between ARM and AArch64 processor modules in Ghidra?
The ARM (32-bit) module supports ARMv4-v8 architectures including Thumb-1 and Thumb-2 instruction sets, with register banking for different processor modes (FIQ, IRQ, etc.) and complex condition code handling. The AArch64 module implements the 64-bit ARMv8-A ISA with a streamlined, orthogonal instruction set, 64-bit general-purpose registers (X0-X30), and support for the PSTATE register rather than the separate CPSR found in 32-bit ARM. The AArch64 module also removes the complexity of Thumb mode switching and register banking present in the 32-bit implementation.
How do SLEIGH specification files differ between x86 and MIPS architectures?
The x86 SLEIGH specification in x86.slaspec is highly decomposed, including separate .sinc files for each instruction set extension (AVX, AVX-512, BMI, SHA) to manage the architecture's complexity and variability across vendors. The MIPS SLEIGH specifications, such as mips32le.slaspec, are self-contained per-variant (addressing 32/64-bit, endianness, and micro-MIPS) and explicitly define branch delay slot semantics and coprocessor interactions that are architectural hallmarks of MIPS, rather than using an included-file approach for extensions.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →