---
name: "r_arch"
section: "3"
platform: "linux"
package: "radare2"
version: "6.2.2-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/r_arch"
---

# r\_arch(3)

Architecture abstraction library for radare2

## NAME

**r\_arch** – Architecture abstraction library for radare2

## SYNOPSIS

The primary functions and types provided by the r\_arch API are used to select architecture plugins, configure decoding/encoding behaviour and create per-plugin sessions for advanced callbacks (for example to fetch register profiles or run ESIL hooks). Use \`r\_arch\_config\_new\` to create a configuration and \`r\_arch\_use\` to activate an architecture plugin.

**#include \<r\_arch.h\>**

## DESCRIPTION

r\_arch implements a thin, stable interface that core consumers (such as \`libr/core\` and \`libr/anal\`) use to perform disassembly, assembly and to access plugin-specific capabilities. The API exposes helpers to query plugin limits (e.g. maximum opcode size), run the generic decode/encode paths and to wrap plugin sessions when direct access to plugin callbacks is required.

Key concepts and why they matter in practice:

- \`RArch\` — holds available arch plugins and an active session; most clients keep a single \`RArch\` per \`RCore\` or \`RAnal\` instance so the arch state (current plugin, esil, reg profile) is shared.

- \`RArchConfig\` — describes desired architecture parameters (name, bits, endianness, syntax). Set this before calling \`r\_arch\_use\` so the right plugin variant is selected.

- \`RAnalOp\` — the container for decoded instruction information. Decoders fill \`op.size\`, \`op.mnemonic\`, \`op.esil\` and other fields depending on the decode mask. Consumers such as the ESIL executor rely on \`op.esil\` to obtain instruction semantics.

- \`RArchSession\` — per-plugin state allowing callers to directly invoke plugin callbacks (for example, \`plugin-\>regs\` to obtain a register profile). Use a session when you need functionality not exposed by the generic decode/encode wrappers.

## INITIALIZATION

Before decoding or encoding, create an \`RArch\` instance and configure the plugin you want to use. The configuration controls bits, syntax and other plugin-specific options. Pp *RArch* *\** **r\_arch\_new**(*void*)

*RArchConfig* *\** **r\_arch\_config\_new**(*void*)

*void* **r\_arch\_config\_free**(*RArchConfig \*cfg*)

*bool* **r\_arch\_use**(*RArch \*arch*, *RArchConfig \*config*, *const char \*name*)

*void* **r\_arch\_free**(*RArch \*arch*)

Typical initialization steps used across core components:

- Create an arch object with \`r\_arch\_new\` and a configuration with \`r\_arch\_config\_new\`.

- Set desired options (\`cfg-\>arch\`, \`cfg-\>bits\`, \`cfg-\>endian\`, \`cfg-\>syntax\`) and call \`r\_arch\_use (arch, cfg, name)\` to activate the plugin.

- Query plugin capabilities via \`r\_arch\_info\` (for example \`R\_ARCH\_INFO\_MAXOP\_SIZE\`), or create an \`RArchSession\` with \`r\_arch\_session\` when you need plugin callbacks, such as \`regs()\`.

Example (typical init):

```
RArch *arch = r_arch_new();
RArchConfig *cfg = r_arch_config_new();
strcpy (cfg->arch, "x86");
cfg->bits = 64;
cfg->syntax = R_ARCH_SYNTAX_INTEL;
if (!r_arch_use (arch, cfg, "x86")) {
    // handle error: requested plugin not available
}
// later
r_arch_config_free (cfg);
// r_arch_free (arch) when done
```

## DECODING (DISASSEMBLING)

Decoding converts raw bytes to a populated \`RAnalOp\`. The API supports masks to control what information the plugin should fill — for example basic fields, ESIL semantics or value operands. Real-world clients first query the plugin for its maximum opcode length so they read enough bytes from IO. Pp *int* **r\_arch\_info**(*RArch \*arch*, *int query*)

*bool* **r\_arch\_decode**(*RArch \*a*, *RAnalOp \*op*, *RArchDecodeMask mask*)

*void* **r\_anal\_op\_init**(*RAnalOp \*op*)

*bool* **r\_anal\_op\_set\_bytes**(*RAnalOp \*op*, *ut64 addr*, *const ut8 \*data*, *int size*)

*void* **r\_anal\_op\_fini**(*RAnalOp \*op*)

Practical sequence used in \`r\_core\_esil\_single\_step\`:

- Query maximum opcode size: \`r\_arch\_info (arch, R\_ARCH\_INFO\_MAXOP\_SIZE)\`.

- Read up to \`max\_op\_size\` bytes from the IO layer into a buffer.

- Initialize and populate an \`RAnalOp\` with \`r\_anal\_op\_init\` and \`r\_anal\_op\_set\_bytes\`.

- Call \`r\_arch\_decode (arch, &op, mask)\` with masks such as \`R\_ARCH\_OP\_MASK\_BASIC \| R\_ARCH\_OP\_MASK\_ESIL\` to obtain decoding and ESIL semantics.

- On success inspect \`op.size\`, \`op.esil\`, \`op.mnemonic\` and other fields and clean up with \`r\_anal\_op\_fini\`.

Minimal decode example (pattern taken from \`r\_core\_esil\_single\_step\`):

```
int max_op = r_arch_info (arch, R_ARCH_INFO_MAXOP_SIZE);
if (max_op < 1) { max_op = 32; }
ut8 buf[64];
if (!r_io_read_at (io, pc, buf, max_op)) {
    // read failure
}
RAnalOp op;
r_anal_op_init (&op);
r_anal_op_set_bytes (&op, pc, buf, max_op);
if (!r_arch_decode (arch, &op, R_ARCH_OP_MASK_BASIC | R_ARCH_OP_MASK_ESIL)) {
    r_anal_op_fini (&op);
    // decode failed
}
// use op.size, op.esil, op.mnemonic ...
r_anal_op_fini (&op);
```

Notes and gotchas:

- Always ensure you read at least \`R\_ARCH\_INFO\_MAXOP\_SIZE\` bytes (or a safe fallback) before calling \`r\_arch\_decode\`; plugins may require several bytes to decide instruction length.

- Check \`op.size\` and \`op.type\` after decoding. The core implementation uses hints (\`r\_anal\_hint\_get\`) to override \`op.size\` or \`op.esil\` when available.

- When decoding for emulation (ESIL) prefer to request ESIL with the \`R\_ARCH\_OP\_MASK\_ESIL\` mask so the plugin fills \`op.esil\` with the instruction semantics.

## ENCODING (ASSEMBLING)

Encoding converts textual mnemonics to machine code and populates the \`RAnalOp\` bytes. The common workflow in \`libr/anal\` (see \`r\_anal\_opasm\`) first tries the encoder callback provided by the active plugin/session and falls back to other encoders when necessary. Pp *bool* **r\_arch\_encode**(*RArch \*a*, *RAnalOp \*op*, *RArchEncodeMask mask*)

*RAnalOp* *\** **r\_anal\_op\_new**(*void*)

*void* **r\_anal\_op\_free**(*void \*op*)

*bool* **r\_anal\_op\_set\_mnemonic**(*RAnalOp \*op*, *ut64 addr*, *const char \*s*)

Key points:

- Prepare an \`RAnalOp\` with the mnemonic (for example using \`r\_anal\_op\_set\_mnemonic\`) and call \`r\_arch\_encode\` to attempt encoding.

- If the plugin cannot encode the instruction, query \`r\_arch\_info\` for fallback sizes: \`R\_ARCH\_INFO\_INVOP\_SIZE\` (size of an invalid instruction placeholder) or \`R\_ARCH\_INFO\_CODE\_ALIGN\` to choose a reasonable number of bytes to reserve.

Encoding example (conceptual):

```
RAnalOp *op = r_anal_op_new ();
r_anal_op_set_mnemonic (op, 0, "mov rax, 42");
if (r_arch_encode (arch, op, 0)) {
    // op->bytes and op->size now contain encoded data
} else {
    int sz = r_arch_info (arch, R_ARCH_INFO_INVOP_SIZE);
    if (sz < 1) sz = r_arch_info (arch, R_ARCH_INFO_CODE_ALIGN);
    if (sz < 1) sz = 1;
    // reserve `sz` bytes as fallback
}
r_anal_op_free (op);
```

## SESSIONS

When you need direct access to plugin callbacks (for example to obtain a register profile string or to use plugin-specific preludes), create a session with \`r\_arch\_session\`. Sessions wrap a \`RArchPlugin\` and expose \`session-\>plugin\` which contains callbacks such as \`regs()\` or \`esilcb()\`. Pp *RArchSession* *\** **r\_arch\_session**(*RArch \*arch*, *RArchConfig \*cfg*, *RArchPlugin \*ap*)

*int* **r\_arch\_session\_info**(*RArchSession \*as*, *int q*)

*RList* *\** **r\_arch\_session\_preludes**(*RArchSession \*as*)

Real usage example from \`r\_core\_esil\_load\_arch\`:

```
// after activating arch and creating core->anal->arch->session
char *rp = core->anal->arch->session->plugin->regs (core->anal->arch->session);
if (rp) {
    r_reg_set_profile_string (core->esil.reg, rp);
    free (rp);
}
// the plugin may also register ESIL callbacks via session->plugin->esilcb
```

Other session helpers:

- \`r\_arch\_session\_info(session, q)\` — query plugin-specific values.

- \`r\_arch\_session\_preludes(session)\` — obtain RList of preludes injected by plugins (used by disassemblers/emitters to add prologue code, etc.).

## CONFIGURATION

\`RArchConfig\` and its helpers let you specify architecture attributes before loading a plugin. Use \`r\_arch\_config\_set\_bits\`, \`r\_arch\_config\_set\_cpu\` and \`r\_arch\_config\_set\_syntax\` to set common options. Plugins can read these fields when \`r\_arch\_use\` is called to select appropriate variants. Pp *bool* **r\_arch\_config\_set\_bits**(*RArchConfig \*c*, *int bits*)

*void* **r\_arch\_config\_set\_cpu**(*RArchConfig \*config*, *const char \*cpu*)

*bool* **r\_arch\_config\_set\_syntax**(*RArchConfig \*config*, *int syntax*)

*RArchConfig* *\** **r\_arch\_config\_new**(*void*)

*void* **r\_arch\_config\_free**(*RArchConfig \*cfg*)

Example: set CPU and syntax before calling \`r\_arch\_use\`:

```
r_arch_config_set_bits(cfg, 32);
r_arch_config_set_cpu(cfg, "cortex-a53");
r_arch_config_set_syntax(cfg, R_ARCH_SYNTAX_ATT);
r_arch_use(arch, cfg, NULL);
```

## ARCHITECTURES

The architecture plugins are located under \`libr/arch/p/\*\` and provide implementations for decoders/encoders and ESIL callbacks. \`r\_arch\_find\` and \`r\_arch\_use\` select and activate a plugin by name (plugins often use short names such as \`x86\`, \`arm\`, \`mips\`).

To discover which plugins were built inspect the \`libr/arch/p\` directory or call \`r\_arch\_platform\_list\` at runtime.

## SYNTAX MODES

Some plugins support multiple syntax modes (for x86 this is commonly Intel or AT&T). The syntax influences disassembly formatting and sometimes encoding. Set \`cfg-\>syntax\` with \`r\_arch\_config\_set\_syntax\` before calling \`r\_arch\_use\`.

Common syntax constants are \`R\_ARCH\_SYNTAX\_INTEL\`, \`R\_ARCH\_SYNTAX\_ATT\` and \`R\_ARCH\_SYNTAX\_MASM\`. Use \`R\_ARCH\_SYNTAX\_REGNUM\` to request register numbers instead of names when supported.

## EXAMPLES

Below are practical snippets adapted from core components to show how decoding, ESIL integration and session usage combine to solve real tasks.

Example 1 — ESIL single-step (short sequence based on \`r\_core\_esil\_single\_step\`):

```
// 1. get max opcode size
int max_op = r_arch_info (arch, R_ARCH_INFO_MAXOP_SIZE);
if (max_op < 1) { max_op = 32; }
// 2. read bytes from IO
ut8 buf[64];
if (!r_io_read_at (io, pc, buf, max_op)) { /* read error */ }
// 3. decode requesting ESIL
RAnalOp op; r_anal_op_init (&op);
r_anal_op_set_bytes (&op, pc, buf, max_op);
if (!r_arch_decode (arch, &op, R_ARCH_OP_MASK_BASIC | R_ARCH_OP_MASK_ESIL)) {
    r_anal_op_fini (&op);
    // decode failed or unknown instruction
}
// 4. check op.size and apply hints if needed (core uses r_anal_hint_get)
if (op.size < 1 || op.type == R_ANAL_OP_TYPE_ILL) { /* trap handling */ }
// 5. run ESIL expression (op.esil) in the REsil context
char *esil_expr = r_strbuf_drain_nofree (&op.esil);
// r_esil_parse(core_esil, esil_expr);
free (esil_expr);
r_anal_op_fini (&op);
```

Example 2 — load architecture register profile into core ESIL (from \`r\_core\_esil\_load\_arch\`):

```
// after arch/plugin/session are initialized
if (core->anal->arch->session && core->anal->arch->session->plugin &&
    core->anal->arch->session->plugin->regs) {
    char *reg_profile = core->anal->arch->session->plugin->regs (
        core->anal->arch->session);
    if (reg_profile) {
        r_reg_set_profile_string (core->esil.reg, reg_profile);
        free (reg_profile);
    }
}
```

## SEE ALSO

[r\_anal(3)](/r_anal/3.md), [r\_asm(3)](/r_asm/3.md), [r\_core(3)](/r_core/3.md)
