The Translation Layer That Lets One Analyzer Reach Many Processors

Ghidra's auto-analysis can only work across processor families if it has a common way to describe what instructions do. This chapter focuses on that translation layer: how SLEIGH turns instruction encodings into assembly structure and p-code, and how p-code gives shared analysis machinery an explicit account of data movement and control flow. The result is not a promise that every processor is modeled perfectly. It is an architectural bargain: processor-specific specifications do the translation, while common analysis and decompilation engines work on the resulting representation.

Two translations, one semantic hinge

Assembly language and instruction semantics answer different questions. Assembly tells a person how an instruction is written for a particular processor: its mnemonic, operands, sub-operands, and syntax. Semantics describe what the instruction changes in registers and memory, how it computes a result, and where control goes next. A processor manual may show both, but a reverse-engineering platform needs them in a form that its own tools can consume consistently.

SLEIGH is Ghidra's processor-specification language for that job. A SLEIGH specification describes how bits in an instruction encoding map to a human-readable assembly statement and how the same instruction maps to p-code. The first translation supports disassembly: Ghidra can display the mnemonic and operands and understand their structure. The second supplies the semantics used by data-flow analysis and decompilation. These outputs are related, but they are not the same thing.

P-code is a register-transfer representation designed to model general-purpose processors. It is machine-independent in the sense that its operations use a common vocabulary even when the original instructions do not. A processor's addition, memory load, conditional branch, or subroutine call can be expressed as explicit operations over values in address spaces. The analysis engine can then reason about those operations without having to be rewritten around every processor's surface syntax.

That division of responsibility is what makes the architecture retargetable. Adding or refining a processor model requires describing the translation from that processor's encodings and effects into SLEIGH and p-code. The common analysis and decompilation machinery can then consume the same kind of intermediate representation it receives from other processors. Ghidra still needs processor-specific knowledge, but it keeps that knowledge at the boundary where it belongs instead of scattering it throughout every higher-level tool.

flowchart LR I["Processor instruction encoding"] --> S["SLEIGH specification"] S --> A["Assembly representation"] S --> P["P-code IR"] P --> E["Shared analysis engines"] E --> D["Decompiler"] P --> G["Debugger emulator"]

The diagram is a map of interfaces rather than a claim that the two branches are independent. Assembly helps an analyst inspect exactly what was decoded. P-code gives the analysis engine an explicit semantic account of that decoded instruction. When the two disagree with the surrounding program model, the analyst has a place to look: the bytes, the decoding rule, the semantic specification, or the higher-level inference.

This also explains why p-code is not simply another spelling of assembly. An assembly instruction can hide several effects behind one mnemonic. A load may update a register and read from a processor-specific memory space. A branch may depend on a flag that another instruction calculated implicitly. A call may transfer control and carry a convention about what counts as a return. P-code breaks those effects into operations that data-flow and control-flow analysis can follow.