X86 Encoder Decoder
by Mark Charney
XED is an acronym for X86 Encoder Decoder. The latter part is pronounced like the (British) English "z".
Intel XED is a software library (and associated headers) written in C for encoding and decoding X86 (IA-32 instruction set and Intel® 64 instruction set) instructions. The decoder takes sequences of 1-15 bytes along with machine mode information and produces a data structure describing the opcode and operands, and flags. The encoder takes a similar data structure and produces a sequence of 1 to 15 bytes. Intel XED is multi-thread safe.
Intel XED was designed to be very fast and extensible.
Intel XED compiles with the following compilers:
Intel XED works with the following operating systems:
The Intel XED examples (Examples of using Intel XED) also include binary image readers for Windows PECOFF, ELF and Mac OS X* MACHO binary file formats for 32b and 64b. These allow Intel XED to be used as a simple (not symbolic) disassembler. The Intel XED disassembler supports 3 output formats: Intel, ATT SYSV, and a more detailed internal format describing all resources read and written.
This section describes the requirements for compiling with Intel XED and linking the libxed.a library. It assumes you are building from a Intel XED kit, and not directly from the sources. (See the "install" option in the Intel XED build manual for information on making kits).
The structure of a Intel XED kit is as follows:
To use Intel XED your sources should include the top-most header file: xed-interface.h.
Your compilation statement must include:
where "xed-kit-name" is the place you've unpacked the Intel XED kit.
Your Linux or Mac OS X* link statement must reference the libxed library:
(or link against libxed.lib for Windows).
Intel XED uses base types with the following names: xed_uint8_t, xed_uint16_t, xed_uint32_t, xed_uint64_t xed_int8_t, xed_int16_t, xed_int32_t, and xed_int64_t. Intel XED also defines a "xed_uint_t" type that is shorthand for "unsigned int".
Intel XED was designed to have minimal external requirements. Intel XED makes no system calls. Intel XED allocates no memory. (The examples are different). The following external functions/symbols are required for linking a program with libxed, with one caveat: The functions fprint and abort and the data object stderr are optional. If users register their own abort handler using xed_register_abort_function () , then fprintf, stderr and abort are not required and can be stubbed out to satisfy the linker.
X86 instructions are 1-15 byte values. They consist of several well defined components:
Legacy prefix bytes used for many purposes (described further below).
REX prefix byte but only in 64b mode. It has 4 1-bit fields: W, R, X, and B. The W bit modifies the operation width. The R, X and B fields extend the register encodings. The REX byte must be right before the opcode bytes else it is ignored.
VEX prefix byte sequence. The VEX prefix is used mostly for AVX1 and AVX2 instructions as well as BMI1/2 instructions and mask operations in Intel® AVX512. The VEX prefix comes in two forms. The 2-byte sequence begins with an 0xC5 byte. The 3-byte sequence begins with an 0xC4 byte.
EVEX prefix. The EVEX 3-byte sequence used for encoding Intel AVX512 instructions and begins with an 0x62 byte.
There are somewhat complex rules about which prefixes are allowed, in what order, and in what modes. Intel XED handles that complexity.
1-3 opcode bytes. When more than one opcode byte is required the leading bytes (called escapes) are either 0x0F, 0x0F 0x38 or 0x0F 0x3A. With VEX and EVEX prefixes, the escape bytes are encoded differently.
MODRM byte. Used for addressing memory, refining opcodes, specifying registers. Optional, but common. It has 3 fields: the 2-bit "mod", the 3-bit "reg" and 3-bit "r/m" fields.
SIB byte. Used for specifying memory addressing, optional. It has 3 fields: the 2-bit scale, 3-bit index and 3-bit base.
Immediates and displacements are usually limited to 4 bytes, but there are several variants of the MOV instruction that can take 8B values. The AMD 3DNow ISA extension uses the immediate field to provide additional opcode information.
The legacy prefix bytes are used for:
There are 11 distinct legacy prefixes. Three of them (operand size, and the two repeat prefixes) have different meanings in different contexts; Sometimes they are used for opcode refinement and do not have their default meaning. Less frequently. two of the segment overrides can be used for conditional branch hints.
There are also multiple ways to encode certain instructions, with the same or differing length.
For additional information on the instruction semantics and encodings:
XED has two fundamental interfaces: encoding and decoding. Supporting these interfaces are many data structures, but the two starting points are the xed_encoder_request_t and the xed_decoded_inst_t . The xed_decoded_inst_t has more information than the xed_encoder_request_t , but both types are derived from a set of common fields called the xed_operand_values_t.
The output of the decoder, the xed_decoded_inst_t , includes additional information that is not required for encoding, but provides more information about the instruction resources.
The common operand fields, used by both the encoder and decoder, hold the operands and the memory addressing information.
The decoder has an operands array that holds order of the decoded operands. This array indicates whether or not the operands are read or written.
The encoder has an operand array where the encoder user must specify the order of the operands used for encoding.
The xed_iclass_enum_t class describes the instruction names. The names are (mostly) taken from the Intel manual, with exceptions only for certain ambiguities. This is what is typically thought of as the instruction mnemonic. Note, Intel XED does not typically distinguish instructions based on width unless the ISA manuals do so as well. For example, xed_iclass_enum_t's are not suffixed with "w", "l" or "q" typically. There are instructions whose xed_iclass_enum_t ends in a "B" or a "Q" (including all byte operations and certain string operations) and those names are preserved as described in the Intel programmers' reference manuals.
There are many special cases that must be accounted for in attempting to handle all the nuances of the ISA. This is an attempt to explain the nonstandard handling of certain instruction names.
The FAR versions of 3 opcodes (really 6 distinct opcodes) are given the opcode names CALL_FAR, JMP_FAR and RET_FAR. The AMD documentation lists the far return as RETF. I call that RET_FAR to be consistent with the other far operations.
To distinguish the SSE2 MOVSD instruction from the base string instruction MOVSD, Intel XED calls the SSE version MOVSD_XMM.
In March 2015, a change was made to certain Intel XED iclasses to simplify the implementation. The changes are as follows:
NOPs are very special. Intel XED allows for encoding NOPs of 1 to 9 bytes through the use of the XED_ICLASS_NOP (the one byte nop), and XED_ICLASS_NOP2 ... XED_ICLASS_NOP9. These use the recommended NOP sequences from the Intel® 64 and IA-32 Architectures Software Developers Manual.
The instruction 0x90 is very special in the instruction set because it gets special treatment in 64b mode. In 64b mode, 32b register writes normally zero the upper 32 bits of a 64b register. No so for 0x90. If it did zero the upper 32 bits, it would not be a NOP.
There are two important NOP categories. XED_CATEGORY_NOP and XED_CATEGORY_WIDENOP. The XED_CATEGORY_NOP applies only to the 0x90 opcode. The WIDENOP category applies to the NOPs in the two byte table row 0F19...0F1F. The WIDENOPs take MODRM bytes, and optional SIB and displacements.
Intel XED uses the operand order documented in the Intel Programmers' Reference Manual. In most cases, the first operand is a source and destination (read and written) and the second operand is just a source (read).
For decode requests (xed_decoded_inst_t), the operands array is stored in the xed_inst_t strcture once the instruction is decoded. For encode requests, the request's operand order is stored in the xed_encoder_request_t.
There are several types of operands:
Each operand has two associated attributes: the R/W action and a visibility. The R/W actions (xed_operand_action_enum_t) indicate whether the operand is read, written or both read-and-written, or conditionally read or written. The visibility attribute (xed_operand_visibility_enum_t) is described in the next subsection.
The memory operation operand is really a pointer to separate fields that hold the memory operation information. The memory operation information is comprised of:
There are several important things to note:
Intel® AVX512 adds write masking, merging and zeroing to the instruction set via the EVEX encodings. Write masking, merging and zeroing are properties of the instruction encoding and are not visible by looking at individual operands. Write masking with merging makes it possible for values of the destination register to live on from prior to the execution of the instruction. Write masking with merging results in an extra register read of the destination operand. In contrast write masking with zeroing always completely overwrites the destination operand, either with values computed by the instruction or with zeros for elements that are "masked off".
For most operands, to learn if the operand reads or writes its associated resource, one can use xed_operand_rw(const xed_operand_t* p). However because masking, merging and zeroing are properties of the instruction, and not just the operand, use of a different function is required.
To handle this, Intel XED has a new interface function xed_decoded_inst_operand_action() which takes a xed_decoded_inst_t pointer and an operand index and indicates how the read/write behavior is modified in the presense of masking with merging or masking with zeroing.
The following list attempts to summarize how the value returned from xed_operand_rw() is internally modified for the 0th operand, except for stores:
There are 3 basic types of resource visibilites:
Explicit are what you think they are: resources that are required for the encoding and for each explicit resource, there is field in the corresponding instruction encoding. The implicit and suppressed resources are a more subtle.
SUPP operands are:
IMPL operands are:
The implicit resources are required for selecting an encoding, but do not show up as a specific field in the instruction representation. Implicit resources do show up in a conventional instruction disassembly. In the IA-32 instruction set or Intel64 instruction set, there are many instructions that use EAX or RAX implicitly, for example. Sometimes the CL or RCX register is implicit. Also, some instructions have an implicit 1 immediate. The opcode you chose fixes your choice of implicit register or immediate.
The suppressed resources are a form of implicit resource, but they are resources not required for encoding. The suppressed operands are not normally displayed in a conventional disassembly. The suppressed operands are emitted by the decoder but are not used when encoding. They are ignored by the encoder. Examples are the stack pointer for PUSH and POP operations. There are many others, like pseudo resources.
The explicit and implicit resources are expressed resources – they show up in disassembly and are required for encoding. The suppressed resources are considered a kind of implicit resources that are not expressed in ATT System V or Intel disassembly formats.
The suppressed operands are always after the implicit and explicit operands in the operand order.
The Intel® 64 and IA-32 Architectures Software Developers Manual indicates that "FADDP st2", reads st0, st2 writes st2 and pops the x87 stack. The result ends up in st1 after the instruction executes. That is not how Intel XED represents the operation. Intel XED will say that "FADDP st2" reads st0 and st2 and writes st2. The output register that Intel XED provides is essentially "pre pop". The pop occurs afterward, conceptually. The actual result ends up in the st1 register after the stack pop operation. Intel XED also lists the pseudo resources indicating that a stack pop has occurred. This behavior affects the output register of following instructions: FADDP, FMULP, FSUBRP, FSUBP, FDIVRP, FDIVP.
Some instructions reference machine registers or perform interesting operations that we need to represent. For example, the IDTR and GDTR are represented as pseudo resources. Operations that pop the x87 floating point register stack can have a X87POP or X87POP2 "register" to indicate if the x87 register stack is popped once or twice. These are part of the xed_reg_enum_t.
Using the API functions for setting immediates, memory displacements and branch displacements. Immediates and Displacements are stored in normal integers internally, but they are stored endian swapped and left justified. The API functions take care of all the endian swapping and positioning so you don't have to worry about that detail.
Immediates and displacements are different things in the ISA. They can be 1, 2, 4 or 8 bytes. Branch displacements (1, 2 or 4 bytes) and Memory displacements (1, 2, 4 or 8 bytes) refer to the signed constants that are used for relative distances or memory "offsets" from a base register (including the instruction pointer) or start of a memory region.
Immediates are signed or unsigned and are used for numerical computations, shift distances, and also hold things like segment selectors for far pointers for certain jump or call instructions.
There is also a second 1B immedate used only for the ENTER instruction.
Intel XED will try to use the shortest allowed width for a displacement or immediate. You can control Intel XED's selection of allowed widths using a notion of "legal widths". A "legal width" is a binary number where each bit represents a legal desired width. For example, when you have a valid base register in 32 or 64b addressing, and a displacement is required, your displacement must be either 1 byte or 4 bytes long. This is expressed by OR'ing 1 and 4 together to get 0101 (base 2) or 5 (base 10).
If a four byte displacement was required, but the value was representable in fewer than four bytes, then the legal width should be set to 0100 (base 2) or 4 (base 10).
The information in this manual is subject to change without notice and Intel Corporation assumes no responsibility or liability for any errors or inaccuracies that may appear in this document or any software that may be provided in association with this document. This document and the software described in it are furnished under license and may only be used or copied in accordance with the terms of the license. No license, express or implied, by estoppel or otherwise, to any intellectual property rights is granted by this document. The information in this document is provided in connection with Intel products and should not be construed as a commitment by Intel Corporation.
EXCEPT AS PROVIDED IN INTEL'S TERMS AND CONDITIONS OF SALE FOR SUCH PRODUCTS, INTEL ASSUMES NO LIABILITY WHATSOEVER, AND INTEL DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF INTEL PRODUCTS INCLUDING LIABILITY OR WARRANTIES RELATING TO FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER INTELLECTUAL PROPERTY RIGHT. Intel products are not intended for use in medical, life saving, life sustaining, critical control or safety systems, or in nuclear facility applications.
Designers must not rely on the absence or characteristics of any features or instructions marked "reserved" or "undefined." Intel reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompat- ibilities arising from future changes to them.
The software described in this document may contain software defects which may cause the product to deviate from published specifications. Current characterized software defects are available on request.
Intel, the Intel logo, Intel SpeedStep, Intel NetBurst, Intel NetStructure, MMX, Intel386, Intel486, Celeron, Intel Centrino, Intel Xeon, Intel XScale, Itanium, Pentium, Pentium II Xeon, Pentium III Xeon, Pentium M, and VTune are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries.
Other names and brands may be claimed as the property of others.
Copyright (c) 2002-2016 Intel Corporation. All Rights Reserved.