R_ASM(3)
πΈ R_ASM πΈ
okay bestie, pull up a chair, we're doing the r_asm page from the radare2 library functions manual π this is the Assembler and disassembler library for radare2, and yes it's lowkey iconic, no cap.
β¨ NAME β¨
r_asm β Assembler and disassembler library for radare2 π«Ά
β¨ SYNOPSIS β¨
#include <r_asm.h>
like literally that's the whole vibe. one include and you're in π
π¦ DESCRIPTION π¦
So the r_asm API is out here exposing radare2's high level assembler and disassembler primitives, plus the glue that holds the two of them together. it's giving matchmaker energy, honestly.
It's implemented as a frontend for the r_arch api, which is the thing that actually provides the architecture logic to encode and decode instructions. but the glow-up is that r_asm also offers support for multiline assembler with directive handling and pseudo disassembling and parsing plugins. we love a queen with range π
The routines all operate on the RAsm context, which holds architecture configuration, current program counter and parser state. and the results for multi-instruction operations come back in RAsmCode objects, which contain raw bytes, the disassembly text and per-assembly metadata. cute little care package, fr fr π
π INITIALIZATION π
Before you assemble or disassemble literally anything, you must create and configure an RAsm. and when you're embedding it in r2, hit up r_asm_set_user_ptr() with the RCore so the helpers (like address-size prediction) work correctly. don't skip that step bestie, it's not decorative.
/* Initialization API (prototypes) */
RParse *r_parse_new (void);
void r_parse_free (RParse *p);
RAsm *r_asm_new (void);
void r_asm_free (RAsm *a);
void r_asm_set_user_ptr (RAsm *a, void *user);
bool r_asm_use (RAsm *a, const char *name);
int r_asm_set_bits (RAsm *a, int bits);
int r_asm_set_pc (RAsm *a, ut64 pc);
and here's what initialization + cleanup looks like in the wild, bestie:
RAsm *a = r_asm_new();
/* choose architecture and word size */
r_asm_use (a, "x86");
r_asm_set_bits (a, 64);
/* set current location for relative operands and disassembly helpers */
r_asm_set_pc (a, 0x1000);
/* when embedding in r2: r_asm_set_user_ptr (a, core); */
r_asm_free (a);
π ASSEMBLY π
The assembler API gives you two levels of convenience, which is genuinely so thoughtful of it. π₯Ή
Use r_asm_assemble() when you need multi-line assembly, directive handling, or you want an RAsmCode result with both the bytes and the produced assembly text. For single-line or binding-specific assembly callbacks, go use the lower-level encode callbacks that plugins expose. And if all you need is a raw buffer of bytes from a textual instruction, the utility you want is r_asm_from_string().
/* Assembly API (prototypes) */
RAsmCode* r_asm_assemble (RAsm *a, const char *buf);
ut8 *r_asm_from_string (RAsm *a, ut64 addr, const char *b, int *l);
void r_asm_code_free (RAsm *acode);
The assembler honors directives embedded in the input (such as .bits, .arch, or .endian) and uses the configured parser plugin to support pseudo-instructions. it's so well-behaved honestly, a dream π§
/* assemble several instructions and inspect bytes */
RAsmCode *code = r_asm_assemble (a, "mov rax, 420op");
if (code) {
for (int i = 0; i < code->len; i++) {
printf ("%02x ", code->bytes[i]);
}
printf ("%s0, code->assembly);
r_asm_code_free (code);
}
/* get a plain buffer (useful for embedding into other APIs) */
int len;
ut8 *buf = r_asm_from_string (a, 0x1000, "add eax, 1", &len);
if (buf) { free (buf); }
π DISASSEMBLY π
There are two complementary disassembly APIs, because of course there are, balance is everything. The low-level r_asm_disassemble() is the one that works with an RAnalOp, and r_asm_mdisassemble() is the one that hands you back an RAsmCode. two queens, same mission π
/* Disassembly API (prototypes) */
int r_asm_disassemble (RAsm *a, RAnalOp *op, const ut8 *buf, int len);
RAsmCode* r_asm_mdisassemble (RAsm *a, const ut8 *buf, int len);
char *r_asm_tostring (RAsm *a, ut64 addr, const ut8 *b, int l);
RAsmCode* r_asm_mdisassemble_hexstr (RAsm *a, RParse *p, const char *hexstr);
void r_asm_op_init (RAnalOp *op);
void r_asm_op_fini (RAnalOp *op);
The typical decoding loop β the one used in rasm2 and other tools β calls r_asm_disassemble() over and over, updates the PC via r_asm_set_pc(), and finalizes each RAnalOp with r_asm_op_fini(). round and round, like a little hamster wheel but make it assembly πΉ
/* decode a buffer instruction-by-instruction */
RAnalOp op;
int off = 0;
while (off < buflen) {
r_asm_op_init (&op);
r_asm_set_pc (a, base_addr + off);
int sz = r_asm_disassemble (a, &op, buf + off, buflen - off);
if (sz <= 0) { break; }
printf ("%s0, op.mnemonic);
off += op.size;
r_asm_op_fini (&op);
}
For a quick textual conversion of a byte buffer, use r_asm_tostring() or r_asm_mdisassemble(). And to parse a hex string and optionally run the pseudo-assembly parser pass, use r_asm_mdisassemble_hexstr(). pick your fighter, they're all slaying π₯
π PARSING π
The assembler includes a lightweight parse/filter layer that's used to transform or annotate the produced assembly. That's where RParse comes in, and where r_asm_use_parser() does its thing.
/* Parsing API (prototypes) */
RParse *r_parse_new (void);
void r_parse_free (RParse *p);
bool r_asm_use_parser (RAsm *a, const char *name);
char *r_asm_parse_pseudo (RAsm *a, const char *data);
The common usage patterns are: run r_asm_mdisassemble_hexstr() with an RParse instance to post-process a hex string, or call r_asm_parse_pseudo() on a previously decoded mnemonic to get a human-friendly representation (for example, replacing memory operands with symbolic names). here's the vibe:
RParse *p = r_parse_new();
p->pseudo = true; /* enable pseudo transformations */
RAsmCode *c = r_asm_mdisassemble_hexstr (a, p, "4868 2a000000");
if (c) { printf ("%s0, c->assembly); r_asm_code_free (c); }
r_parse_free (p);
π EXAMPLES π
Below are short examples that mirror patterns used across the codebase (see (libr/main/rasm2.c) and (libr/core/cmd_print.inc.c) for complete usages). real source code, real receipts, we love to see it π
Assemble multiple lines and print the encoded bytes:
RAsmCode *ac = r_asm_assemble (a, ".bits 640ov rax, 420op");
if (ac) {
for (int i = 0; i < ac->len; i++) printf ("%02x", ac->bytes[i]);
r_asm_code_free (ac);
}
Assemble and analyze instructions producing ESIL (pattern used by the r2 commands that print analysis):
RAsmCode *acode = r_asm_assemble (a, "mov rax, 420dd rax, 1");
if (acode) {
RAnalOp aop = {0};
int printed = 0;
while (printed < acode->len) {
aop.size = 0;
if (r_anal_op (anal, &aop, base_addr, acode->bytes + printed, acode->len - printed,
R_ARCH_OP_MASK_ESIL) > 0) {
printf ("%s0, R_STRBUF_SAFEGET (&aop.esil));
}
printed += aop.size;
r_anal_op_fini (&aop);
}
r_asm_code_free (acode);
}
Disassemble a hex string and run the pseudo-parser (as used by the print command):
RParse *p = r_parse_new();
p->pseudo = true;
RAsmCode *c = r_asm_mdisassemble_hexstr (a, p, "4868 2a000000");
if (c) { puts (c->assembly); r_asm_code_free (c); }
r_parse_free (p);
π SEE ALSO π
the whole friend group honestly, go say hi to all of them π«Ά
ngl if you made it this far you're officially a real one. now go free your RAsm context, bestie, we do not leak in this house π
kisses, this page came from Debian, dated September 21, 2025, and it lives under the name R_ASM(3) πβ¨
π¦ where this page comes from
- alpine 3.24: radare2-doc 6.1.6-r0 Β· GPL-3.0-or-later AND LGPL-2.0-or-later AND LGPL-2.1-or-later
- arch rolling: radare2 6.2.2-1 Β· GPL-3.0-only AND LGPL-3.0-only
- nixos 26.05: radare2 6.1.8
- nixpkgs unstable: radare2 6.2.4
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 Β· GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 Β· GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 Β· GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 Β· GPL-3.0-only AND LGPL-3.0-only
- ubuntu resolute: radare2 6.0.7+ds-1 Β· LGPL-3.0-only
- ubuntu stonking: radare2 6.1.8+ds-1 Β· LGPL-3.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms