---
name: "x86_disasm"
section: "3"
platform: "linux"
package: "libdisasm-dev"
version: "0.23-7"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/x86_disasm"
---

# x86\_disasm(3)

disassemble a bytestream to x86 assembly language instructions

## NAME

x86\_disasm, x86\_disasm\_forward, x86\_disasm\_range - disassemble a bytestream to x86 assembly language instructions

## SYNOPSIS

**#include \<libdis.h\>**\

**typedef void (\***DISASM\_CALLBACK**)( x86\_insn\_t \*, void \* );**\
 **typedef long (\***DISASM\_RESOLVER**)( x86\_op\_t \*, x86\_insn\_t \*, void \* );**

**int x86\_disasm( unsigned char \***buf**, unsigned int** buf\_len**,**\
\
 		**unsigned long** buf\_rva**, unsigned int** offset**,**\
\
 		**x86\_insn\_t \*** insn **);**\
 **int x86\_disasm\_range( unsigned char \***buf**, unsigned long** buf\_rva**,**\
\
 		      **unsigned int** offset**, unsigned int** len**,**\
\
 		      **DISASM\_CALLBACK** func**, void \***arg **);**\
 **int x86\_disasm\_forward( unsigned char \***buf**, unsigned int** buf\_len**,**\
\
 			**unsigned long** buf\_rva**, unsigned int** offset**,**\
\
 			**DISASM\_CALLBACK** func**, void \***arg**,**\
\
 			**DISASM\_RESOLVER** resolver**, void \***r\_arg **);**

## DESCRIPTION

\#define MAX\_REGNAME 8\
 \#define MAX\_PREFIX\_STR 32\
 \#define MAX\_MNEM\_STR 16\
 \#define MAX\_INSN\_SIZE 20	/\* same as in i386.h \*/\
 \#define MAX\_OP\_STRING 32	/\* max possible operand size in string form \*/\
 \#define MAX\_OP\_RAW\_STRING 64    /\* max possible operand size in raw form \*/\
 \#define MAX\_OP\_XML\_STRING 256   /\* max possible operand size in xml form \*/\
 \#define MAX\_NUM\_OPERANDS 8	/\* max # implicit and explicit operands \*/\
 \#define MAX\_INSN\_STRING 512        /\* 2 \* 8 \* MAX\_OP\_STRING \*/\
 \#define MAX\_INSN\_RAW\_STRING 1024   /\* 2 \* 8 \* MAX\_OP\_RAW\_STRING \*/\
 \#define MAX\_INSN\_XML\_STRING 4096   /\* 2 \* 8 \* MAX\_OP\_XML\_STRING \*/

enum x86\_reg\_type { 	/\* NOTE: these may be ORed together \*/\
\
 	reg\_gen     = 0x00001,	/\* general purpose \*/\
\
 	reg\_in      = 0x00002,	/\* incoming args, ala RISC \*/ \
\
 	reg\_out     = 0x00004,	/\* args to calls, ala RISC \*/\
\
 	reg\_local   = 0x00008,	/\* local vars, ala RISC \*/\
\
 	reg\_fpu     = 0x00010,	/\* FPU data register \*/\
\
 	reg\_seg     = 0x00020,	/\* segment register \*/\
\
 	reg\_simd    = 0x00040,	/\* SIMD/MMX reg \*/\
\
 	reg\_sys     = 0x00080,	/\* restricted/system register \*/\
\
 	reg\_sp      = 0x00100,	/\* stack pointer \*/\
\
 	reg\_fp      = 0x00200,	/\* frame pointer \*/\
\
 	reg\_pc      = 0x00400,	/\* program counter \*/\
\
 	reg\_retaddr = 0x00800,	/\* return addr for func \*/\
\
 	reg\_cond    = 0x01000,	/\* condition code / flags \*/\
\
 	reg\_zero    = 0x02000,	/\* zero register, ala RISC \*/\
\
 	reg\_ret     = 0x04000,	/\* return value \*/\
\
 	reg\_src     = 0x10000,	/\* array/rep source \*/\
\
 	reg\_dest    = 0x20000,	/\* array/rep destination \*/\
\
 	reg\_count   = 0x40000	/\* array/rep/loop counter \*/\
 };

typedef struct {\
\
 	char name\[MAX\_REGNAME\];\
\
 	enum x86\_reg\_type type;			/\* what register is used for \*/\
\
 	unsigned int size;			/\* size of register in bytes \*/\
\
 	unsigned int id;				/\* register ID #, for quick compares \*/\
\
 	unsigned int alias;			/\* ID of reg this is an alias of \*/\
\
 	unsigned int shift;			/\* amount to shift aliased reg by \*/\
 } x86\_reg\_t;

typedef struct {\
\
 	unsigned int     scale;		/\* scale factor \*/\
\
 	x86\_reg\_t        index, base;	/\* index, base registers \*/\
\
 	long             disp;		/\* displacement \*/\
\
 	char             disp\_sign;	/\* is negative? 1/0 \*/\
\
 	char             disp\_size;	/\* 0, 1, 2, 4 \*/\
 } x86\_ea\_t;

enum x86\_op\_type {	/\* mutually exclusive \*/\
\
 	op\_unused = 0,		/\* empty/unused operand \*/\
\
 	op\_register = 1,	/\* CPU register \*/\
\
 	op\_immediate = 2,	/\* Immediate Value \*/\
\
 	op\_relative\_near = 3,	/\* Relative offset from IP \*/\
\
 	op\_relative\_far = 4,\
\
 	op\_absolute = 5,	/\* Absolute address (ptr16:32) \*/\
\
 	op\_expression = 6,	/\* Address expression (scale/index/base/disp) \*/\
\
 	op\_offset = 7,		/\* Offset from start of segment (m32) \*/\
\
 	op\_unknown\
 };

enum x86\_op\_datatype {		/\* these use Intel's lame terminology \*/\
\
 	op\_byte = 1,		/\* 1 byte integer \*/\
\
 	op\_word = 2,		/\* 2 byte integer \*/\
\
 	op\_dword = 3,		/\* 4 byte integer \*/\
\
 	op\_qword = 4,		/\* 8 byte integer \*/\
\
 	op\_dqword = 5,		/\* 16 byte integer \*/\
\
 	op\_sreal = 6,		/\* 4 byte real (single real) \*/\
\
 	op\_dreal = 7,		/\* 8 byte real (double real) \*/\
\
 	op\_extreal = 8,		/\* 10 byte real (extended real) \*/\
\
 	op\_bcd = 9,		/\* 10 byte binary-coded decimal \*/\
\
 	op\_simd = 10,		/\* 16 byte packed (SIMD, MMX) \*/\
\
         op\_ssimd = 10,          /\* 16 byte : 4 packed single FP (SIMD, MMX) \*/\
\
         op\_dsimd = 11,          /\* 16 byte : 2 packed double FP (SIMD, MMX) \*/\
\
         op\_sssimd = 12,         /\* 4 byte : scalar single FP (SIMD, MMX) \*/\
\
         op\_sdsimd = 13,         /\* 8 byte : scalar double FP (SIMD, MMX) \*/\
\
 	op\_descr32 = 14,	/\* 6 byte Intel descriptor 2:4 \*/\
\
 	op\_descr16 = 15,	/\* 4 byte Intel descriptor 2:2 \*/\
\
 	op\_pdescr32 = 16,	/\* 6 byte Intel pseudo-descriptor 32:16 \*/\
\
 	op\_pdescr16 = 17,	/\* 6 byte Intel pseudo-descriptor 8:24:16 \*/\
\
 	op\_fpuenv = 11		/\* 28 byte FPU control/environment data \*/\
 };

enum x86\_op\_access {	/\* ORed together \*/\
\
 	op\_read = 1,\
\
 	op\_write = 2,\
\
 	op\_execute = 4\
 };

enum x86\_op\_flags {	/\* ORed together, but segs are mutually exclusive \*/\
\
 	op\_signed = 1,		/\* signed integer \*/\
\
 	op\_string = 2,		/\* possible string or array \*/\
\
 	op\_constant = 4,	/\* symbolic constant \*/\
\
 	op\_pointer = 8,		/\* operand points to a memory address \*/\
\
 	op\_sysref = 0x010,	/\* operand is a syscall number \*/\
\
 	op\_implied = 0x020,	/\* operand is implicit in insn \*/\
\
 	op\_hardcode = 0x040, /\* operans is hardcoded in insn \*/\
\
 	op\_es\_seg = 0x100,	/\* ES segment override \*/\
\
 	op\_cs\_seg = 0x200,	/\* CS segment override \*/\
\
 	op\_ss\_seg = 0x300,	/\* SS segment override \*/\
\
 	op\_ds\_seg = 0x400,	/\* DS segment override \*/\
\
 	op\_fs\_seg = 0x500,	/\* FS segment override \*/\
\
 	op\_gs\_seg = 0x600	/\* GS segment override \*/\
 };

typedef struct {\
\
 	enum x86\_op\_type 	type;		/\* operand type \*/\
\
 	enum x86\_op\_datatype 	datatype;	/\* operand size \*/\
\
 	enum x86\_op\_access 	access;		/\* operand access \[RWX\] \*/\
\
 	enum x86\_op\_flags	flags;		/\* misc flags \*/\
\
 	union {\
\
 		/\* immediate values \*/\
\
 		char 		sbyte;\
\
 		short 		sword;\
\
 		long 		sdword;\
\
 		qword 		sqword;\
\
 		unsigned char 	byte;\
\
 		unsigned short 	word;\
\
 		unsigned long 	dword;\
\
 		qword 			qword;\
\
 		float	        sreal;	\
\
 		double	        dreal;	\
\
 		/\* misc large/non-native types \*/\
\
 		unsigned char 	extreal\[10\];\
\
 		unsigned char 	bcd\[10\];\
\
 		qword		dqword\[2\];\
\
 		unsigned char	simd\[16\];\
\
 		unsigned char	fpuenv\[28\];\
\
 		/\* absolute address \*/\
\
 		void 		\* address;\
\
 		/\* offset from segment \*/\
\
 		unsigned long	offset;\
\
 		/\* ID of CPU register \*/\
\
 		x86\_reg\_t	reg;\
\
 		/\* offsets from current insn \*/\
\
 		char 		relative\_near;\
\
 		long 		relative\_far;\
\
 		/\* effective address \[expression\] \*/\
\
 		x86\_ea\_t 	expression;\
\
 	} data;\
\
 	void \* insn;\
 } x86\_op\_t;

typedef struct x86\_operand\_list {\
\
 	x86\_op\_t op;\
\
 	struct x86\_operand\_list \*next;\
 } x86\_oplist\_t;

enum x86\_insn\_group {\
\
 	insn\_none = 0,\
\
 	insn\_controlflow = 1,\
\
 	insn\_arithmetic = 2,\
\
 	insn\_logic = 3,\
\
 	insn\_stack = 4,\
\
 	insn\_comparison = 5,\
\
 	insn\_move = 6,\
\
 	insn\_string = 7,\
\
 	insn\_bit\_manip = 8,\
\
 	insn\_flag\_manip = 9,\
\
 	insn\_fpu = 10,\
\
 	insn\_interrupt = 13,\
\
 	insn\_system = 14,\
\
 	insn\_other = 15\
 };

enum x86\_insn\_type {\
\
 	insn\_invalid = 0,\
\
 	/\* insn\_controlflow \*/\
\
 	insn\_jmp = 0x1001,\
\
 	insn\_jcc = 0x1002,\
\
 	insn\_call = 0x1003,\
\
 	insn\_callcc = 0x1004,\
\
 	insn\_return = 0x1005,\
\
 	insn\_loop = 0x1006,\
\
 	/\* insn\_arithmetic \*/\
\
 	insn\_add = 0x2001,\
\
 	insn\_sub = 0x2002,\
\
 	insn\_mul = 0x2003,\
\
 	insn\_div = 0x2004,\
\
 	insn\_inc = 0x2005,\
\
 	insn\_dec = 0x2006,\
\
 	insn\_shl = 0x2007,\
\
 	insn\_shr = 0x2008,\
\
 	insn\_rol = 0x2009,\
\
 	insn\_ror = 0x200A,\
\
 	/\* insn\_logic \*/\
\
 	insn\_and = 0x3001,\
\
 	insn\_or = 0x3002,\
\
 	insn\_xor = 0x3003,\
\
 	insn\_not = 0x3004,\
\
 	insn\_neg = 0x3005,\
\
 	/\* insn\_stack \*/\
\
 	insn\_push = 0x4001,\
\
 	insn\_pop = 0x4002,\
\
 	insn\_pushregs = 0x4003,\
\
 	insn\_popregs = 0x4004,\
\
 	insn\_pushflags = 0x4005,\
\
 	insn\_popflags = 0x4006,\
\
 	insn\_enter = 0x4007,\
\
 	insn\_leave = 0x4008,\
\
 	/\* insn\_comparison \*/\
\
 	insn\_test = 0x5001,\
\
 	insn\_cmp = 0x5002,\
\
 	/\* insn\_move \*/\
\
 	insn\_mov = 0x6001,	/\* move \*/\
\
 	insn\_movcc = 0x6002,	/\* conditional move \*/\
\
 	insn\_xchg = 0x6003,	/\* exchange \*/\
\
 	insn\_xchgcc = 0x6004,	/\* conditional exchange \*/\
\
 	/\* insn\_string \*/\
\
 	insn\_strcmp = 0x7001,\
\
 	insn\_strload = 0x7002,\
\
 	insn\_strmov = 0x7003,\
\
 	insn\_strstore = 0x7004,\
\
 	insn\_translate = 0x7005,	/\* xlat \*/\
\
 	/\* insn\_bit\_manip \*/\
\
 	insn\_bittest = 0x8001,\
\
 	insn\_bitset = 0x8002,\
\
 	insn\_bitclear = 0x8003,\
\
 	/\* insn\_flag\_manip \*/\
\
 	insn\_clear\_carry = 0x9001,\
\
 	insn\_clear\_zero = 0x9002,\
\
 	insn\_clear\_oflow = 0x9003,\
\
 	insn\_clear\_dir = 0x9004,\
\
 	insn\_clear\_sign = 0x9005,\
\
 	insn\_clear\_parity = 0x9006,\
\
 	insn\_set\_carry = 0x9007,\
\
 	insn\_set\_zero = 0x9008,\
\
 	insn\_set\_oflow = 0x9009,\
\
 	insn\_set\_dir = 0x900A,\
\
 	insn\_set\_sign = 0x900B,\
\
 	insn\_set\_parity = 0x900C,\
\
 	insn\_tog\_carry = 0x9010,\
\
 	insn\_tog\_zero = 0x9020,\
\
 	insn\_tog\_oflow = 0x9030,\
\
 	insn\_tog\_dir = 0x9040,\
\
 	insn\_tog\_sign = 0x9050,\
\
 	insn\_tog\_parity = 0x9060,\
\
 	/\* insn\_fpu \*/\
\
 	insn\_fmov = 0xA001,\
\
 	insn\_fmovcc = 0xA002,\
\
 	insn\_fneg = 0xA003,\
\
 	insn\_fabs = 0xA004,\
\
 	insn\_fadd = 0xA005,\
\
 	insn\_fsub = 0xA006,\
\
 	insn\_fmul = 0xA007,\
\
 	insn\_fdiv = 0xA008,\
\
 	insn\_fsqrt = 0xA009,\
\
 	insn\_fcmp = 0xA00A,\
\
 	insn\_fcos = 0xA00C,\
\
 	insn\_fldpi = 0xA00D,\
\
 	insn\_fldz = 0xA00E,\
\
 	insn\_ftan = 0xA00F,\
\
 	insn\_fsine = 0xA010,\
\
 	insn\_fsys = 0xA020,\
\
 	/\* insn\_interrupt \*/\
\
 	insn\_int = 0xD001,\
\
 	insn\_intcc = 0xD002, 	/\* not present in x86 ISA \*/\
\
 	insn\_iret = 0xD003,\
\
 	insn\_bound = 0xD004,\
\
 	insn\_debug = 0xD005,\
\
 	insn\_trace = 0xD006,\
\
 	insn\_invalid\_op = 0xD007,\
\
 	insn\_oflow = 0xD008,\
\
 	/\* insn\_system \*/\
\
 	insn\_halt = 0xE001,\
\
 	insn\_in = 0xE002,	/\* input from port/bus \*/\
\
 	insn\_out = 0xE003, 	/\* output to port/bus \*/\
\
 	insn\_cpuid = 0xE004,\
\
 	/\* insn\_other \*/\
\
 	insn\_nop = 0xF001,\
\
 	insn\_bcdconv = 0xF002, 	/\* convert to or from BCD \*/\
\
 	insn\_szconv = 0xF003	/\* change size of operand \*/\
 };

enum x86\_insn\_note {\
\
 	insn\_note\_ring0		= 1,	/\* Only available in ring 0 \*/\
\
 	insn\_note\_smm		= 2,	/\* "" in System Management Mode \*/\
\
 	insn\_note\_serial	= 4	/\* Serializing instruction \*/\
 };

enum x86\_flag\_status {\
\
 	insn\_carry\_set = 0x1,\
\
 	insn\_zero\_set = 0x2,\
\
 	insn\_oflow\_set = 0x4,\
\
 	insn\_dir\_set = 0x8,\
\
 	insn\_sign\_set = 0x10,\
\
 	insn\_parity\_set = 0x20,\
\
 	insn\_carry\_or\_zero\_set = 0x40,\
\
 	insn\_zero\_set\_or\_sign\_ne\_oflow = 0x80,\
\
 	insn\_carry\_clear = 0x100,\
\
 	insn\_zero\_clear = 0x200,\
\
 	insn\_oflow\_clear = 0x400,\
\
 	insn\_dir\_clear = 0x800,\
\
 	insn\_sign\_clear = 0x1000,\
\
 	insn\_parity\_clear = 0x2000,\
\
 	insn\_sign\_eq\_oflow = 0x4000,\
\
 	insn\_sign\_ne\_oflow = 0x8000\
 };

enum x86\_insn\_cpu {\
\
 	cpu\_8086 	= 1,	/\* Intel \*/\
\
 	cpu\_80286	= 2,\
\
 	cpu\_80386	= 3,\
\
 	cpu\_80387	= 4,\
\
 	cpu\_80486	= 5,\
\
 	cpu\_pentium	= 6,\
\
 	cpu\_pentiumpro	= 7,\
\
 	cpu\_pentium2	= 8,\
\
 	cpu\_pentium3	= 9, \>br\>\
 	cpu\_pentium4	= 10,\
\
 	cpu\_k6		= 16,	/\* AMD \*/\
\
 	cpu\_k7		= 32,\
\
 	cpu\_athlon	= 48\
 };

enum x86\_insn\_isa {\
\
 	isa\_gp		= 1,	/\* general purpose \*/\
\
 	isa\_fp		= 2,	/\* floating point \*/\
\
 	isa\_fpumgt	= 3,	/\* FPU/SIMD management \*/\
\
 	isa\_mmx		= 4,	/\* Intel MMX \*/\
\
 	isa\_sse1	= 5,	/\* Intel SSE SIMD \*/\
\
 	isa\_sse2	= 6,	/\* Intel SSE2 SIMD \*/\
\
 	isa\_sse3	= 7,	/\* Intel SSE3 SIMD \*/\
\
 	isa\_3dnow	= 8,	/\* AMD 3DNow! SIMD \*/\
\
 	isa\_sys		= 9	/\* system instructions \*/\
 };

enum x86\_insn\_prefix {\
\
 	insn\_no\_prefix = 0,\
\
 	insn\_rep\_zero = 1,\
\
 	insn\_rep\_notzero = 2,\
\
 	insn\_lock = 4,\
\
 	insn\_delay = 8\
 };

typedef struct {\
\
 	/\* information about the instruction \*/\
\
 	unsigned long addr;		/\* load address \*/\
\
 	unsigned long offset;		/\* offset into file/buffer \*/\
\
 	enum x86\_insn\_group group;	/\* meta-type, e.g. INSN\_EXEC \*/\
\
 	enum x86\_insn\_type type;	/\* type, e.g. INSN\_BRANCH \*/\
\
 	unsigned char bytes\[MAX\_INSN\_SIZE\];\
\
 	unsigned char size;		/\* size of insn in bytes \*/\
\
 	enum x86\_insn\_prefix prefix;\
\
 	enum x86\_flag\_status flags\_set; /\* flags set or tested by insn \*/\
\
 	enum x86\_flag\_status flags\_tested; \
\
 	/\* the instruction proper \*/\
\
 	char prefix\_string\[32\];		/\* prefixes \[might be truncated\] \*/\
\
 	char mnemonic\[8\];\
\
 	x86\_op\_t operands\[3\];\
\
 	/\* convenience fields for user \*/\
\
 	void \*block;			/\* code block containing this insn \*/\
\
 	void \*function;			/\* function containing this insn \*/ \
\
 	void \*tag;			/\* tag the insn as seen/processed \*/\
 } x86\_insn\_t;\
 \#define X86\_WILDCARD\_BYTE 0xF4

typedef struct {\
\
         enum x86\_op\_type        type;           /\* operand type \*/\
\
         enum x86\_op\_datatype    datatype;       /\* operand size \*/\
\
         enum x86\_op\_access      access;         /\* operand access \[RWX\] \*/\
\
         enum x86\_op\_flags       flags;          /\* misc flags \*/\
 } x86\_invariant\_op\_t;

typedef struct {\
\
 	unsigned char bytes\[64\];	/\* invariant representation \*/\
\
 	unsigned int  size;		/\* number of bytes in insn \*/\
\
         enum x86\_insn\_group group;      /\* meta-type, e.g. INSN\_EXEC \*/\
\
         enum x86\_insn\_type type;        /\* type, e.g. INSN\_BRANCH \*/\
\
 	x86\_invariant\_op\_t operands\[3\];	/\* use same ordering as x86\_insn\_t \*/\
 } x86\_invariant\_t;

## EXAMPLES

The following sample callback outputs instructions in raw syntax:

void raw\_print( x86\_insn\_t \*insn, void \*arg ) {\
\
         char line\[1024\];\
\
         x86\_format\_insn(insn, line, 1024, raw\_syntax);\
\
         printf( "%s0, line);\
 }

The following sample resolver performs very limited checking on the operand of a jump or call to determine what program address the operand refers to:

long resolver( x86\_op\_t \*op, x86\_insn\_t \*insn ) {\
\
         long retval = -1;\
\
         /\* this is a flat ripoff of internal\_resolver in libdis.c --\
\
            we don't do any register or stack resolving, or check\
\
            to see if we have already encountered this RVA \*/\
\
         if ( op-\>type == op\_absolute \|\| op-\>type == op\_offset ) {\
\
                 retval = op-\>data.sdword; \
\
         } else if (op-\>type == op\_relative ){\
\
                 if ( op-\>datatype == op\_byte ) {\
\
                         retval = insn-\>addr + insn-\>size + op-\>data.sbyte;\
\
                 } else if ( op-\>datatype == op\_word ) {\
\
                         retval = insn-\>addr + insn-\>size + op-\>data.sword;\
\
                 } else if ( op-\>datatype == op\_dword ) {\
\
                         retval = insn-\>addr + insn-\>size + op-\>data.sdword;\
\
                 }\
\
         }\
\
         return( retval );\
 }

The following code snippets demonstrate how to use the various disassembly routines:

        unsigned char \*buf;  /\* buffer of bytes to disassemble \*/\
\
         unsigned int buf\_len;/\* length of buffer \*/\
\
         unsigned long rva;   /\* load address of start of buffer \*/\
\
         unsigned int pos;    /\* position in buffer \*/\
\
         x86\_insn\_t insn;     /\* disassembled instruction \*/

        /\* disassemble entire buffer, printing automatically \*/\
\
         x86\_disasm\_range( buf, buf\_rva, pos, buf\_len,\
\
                           raw\_print, NULL );

        /\* disassemble a single instruction, then print it \*/\
\
         if (x86\_disasm( buf, buf\_len, buf\_rva, pos, &insn ) ) {\
\
                 raw\_print( &insn, NULL );\
\
         }

        /\* disassemble forward in 'buf' starting at 'pos' \*/\
\
         x86\_disasm\_forward( buf, buf\_len, buf\_rva, pos,\
\
                             raw\_print, NULL, resolver );\

## SEE ALSO

[libdisasm(7)](/libdisasm/7.md), [x86\_format\_insn(3)](/x86_format_insn/3.md), [x86\_init(3)](/x86_init/3.md), [x86dis(1)](/x86dis/1.md)
