Instruction Set of x64 - Essentials

The x64 processors can execute a wide range of instructions. As processors have evolved, the instruction set has expanded from the initial 117 in the 8086 processor to over 1000 in modern 64-bit designs. In this chapter, we present the instruction groups and describe the essential general-purpose instructions.

Instruction groups

In the processor documentation, we can find several ways to group all instructions. The most general division, according to AMD, defines five groups of instructions:

  • General Purpose instructions
  • System instructions
  • SSE instructions
  • 64-bit media instructions
  • x87 Floating-Point instructions

Intel defines the following groups of instructions.

  • General Purpose
  • X87 FPU
  • X87 FPU and SIMD State Management
  • MMX Technology
  • SSE Extensions
  • SSE2 Extensions
  • SSE3 Extensions
  • SSSE3 Extensions
  • IA-32e mode: 64-bit mode instructions
  • System Instructions
  • VMX Instructions
  • SMX Instructions

There is also a long list of extensions defined, including SSE4.1, SSE4.2, Intel AVX, AMD 3DNow! and many others. For a detailed description of instruction groups, please refer to:

  • “AMD64 Architecture Programmer's Manual” 1),
  • “Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 1: Basic Architecture” 2).

Details of every instruction can be found in the description of the instruction set:

  • “AMD64 Architecture Programmer's Manual Volume 3: General Purpose and System Instructions” 3),
  • “Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 2 (2A, 2B, 2C, & 2D): Instruction Set Reference, A-Z” 4).

There are also specialised websites with detailed instructions that you can use to find a lot of additional information. Among others, you can visit:

  • X86 Opcode and Instruction Reference 5) by MazeGen,
  • x86 and amd64 instruction reference 6) by Félix Cloutier.

In this book, we will present most of the general-purpose instructions and provide general ideas on the chosen extensions, including FPU, MMX, SSE, and AVX.

General Purpose Instructions

General-purpose instructions can be divided into some subgroups.

  • Data Transfer Instructions
  • Binary Arithmetic Instructions
  • Decimal Arithmetic Instructions
  • Logical Instructions
  • Shift and Rotate Instructions
  • Bit and Byte Instructions
  • Control Transfer Instructions
  • String Instructions
  • I/O Instructions
  • Enter and Leave Instructions
  • Flag Control (EFLAG) Instructions
  • Segment Register Instructions
  • Miscellaneous Instructions
  • User Mode Extended State Save/Restore Instructions
  • Random Number Generator Instructions
  • BMI1 and BMI2 Instructions

Condition Codes

Before describing instructions, let's present the condition codes. The condition code is a suffix to the instruction and influences its behaviour: if the condition is met, the instruction is executed; otherwise, the processor proceeds to the next instruction in the program. The condition that is checked during the execution of the conditional instruction is based on the current state of the flags in the EFLAGS register. The flags in the EFLAGS register are modified by instructions, mainly arithmetic, logical, shift, or special flag manipulation instructions. It is important to note that flags are not modified when copying data, so to check whether the value just read is zero, you should perform, for example, a comparison. Condition codes, together with checked flags, are presented in table 1.

Table 1: Condition Codes
Condition code cc Flags checked Comment
E ZF = 1 Equal
Z ZF = 1 Zero
NE ZF = 0 Not equal
NZ ZF = 0 Not zero
A CF=0 and ZF=0 Above
NBE CF=0 and ZF=0 Not below or equal
AE CF=0 Above or equal
NB CF=0 Not below
B CF=1 Below
NAE CF=1 Not above or equal
BE CF=1 or ZF=1 Below or equal
NA CF=1 or ZF=1 Not above
G ZF=0 and SF=OF Greater
NLE ZF=0 and SF=OF Not less or equal
GE SF=OF Greater or equal
NL SF=OF Not less
L SF<>OF Less
NGE SF<>OF Not greater or equal
LE ZF=1 or SF<>OF Less or equal
NG ZF=1 or SF<>OF Not greater
C CF=1 Carry
NC CF=0 Not carry
O OF=1 Overflow
NO OF=0 Not ovrflow
S SF=1 Sign (negative)
NS SF=0 Not sign (non-negative)
P PF=1 Parity
PE PF=1 Parity even
NP PF=0 Not parity
PO PF=0 Parity odd

Data transfer instructions

Almost all assembler tutorials start with the presentation of the mov instruction, which is used to copy data from the source operand to the destination operand. Our book is no exception, and we've already shown this instruction in the examples presented in previous sections.

MOV

Let's look at some additional variants.

mov AL, BL         ;copy one byte from BL to AL
mov AX, BX         ;copy word (two bytes) from BX to AX
mov EAX, EBX       ;copy doublweword (four bytes) from EBX to EAX
mov RAX, RBX       ;copy quadword (eight bytes) from RBX to RAX 
  • mov - copy data

In the mov instruction, the size of the source argument must be the same as the size of the destination argument. Arguments can be stored in registers or in memory, addressed directly or indirectly. One of them can be constant (immediate). Only one memory argument is allowed. This comes from the instructions encoding. In instructions, there is only one possible direct or indirect argument to be encoded. That's why most instructions, not only mov, can operate on a single memory argument. There are some exceptions, for example, string instructions, but such instructions use specific indirect addressing.

mov AL, 100        ;0xB0, 0x64
                   ;copy constant (immediate) of the value 100 (0x64) to AL
 
mov AL, [BX]       ;0x67, 0x8A, 0x07
                   ;copy byte from the memory at address stored in BX to AL 
                   ;(indirect addressing)
 
;Notice the difference between two following instructions
mov EAX, 100       ;0xB8, 0x64, 0x00, 0x00, 0x00
                   ;copy constant 100 to EAX
 
mov EAX, [100]     ;0xA1, 0x64, 0x00, 0x00, 0x00   
                   ;copy value from memory at address 100
 
;It is possible to copy a constant to memory addressed directly or indirectly
;operand size specifier dword ptr is required 
;to inform the processor about the size of the argument
mov dword ptr DS:[200], 100   
                   ;0xC7, 0x05, 0xC8, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00
                   ;copy value of 100, encoded as dword (four bytes), 0x64 = 100
                   ;to memory at address 200, encoded as four bytes,  0xC8 = 200
 
mov dword ptr [EBX], 100
                   ;0xC7, 0x03, 0x64, 0x00, 0x00, 0x00
                   ;copy value of 100, encoded as dword (four bytes), 0x64 = 100
                   ;to memory addressed by EBX 

Conditional move

Starting from the P6 machines, the conditional move instruction was introduced.

  • cmovcc - conditional move

This works similarly to mov, but copies data if the specified condition is true. The condition code is one of the codes listed in the “Condition Codes” section. If the condition is false, the instruction passes through without modifying the arguments. Conditional move instructions can be used to avoid conditional jumps. For example, if we need to copy data from EBX to ECX, if the result of the previous operation is negative, we can write the following instruction.

cmovs ECX, EBX

Sign extension

In the situation of copying data of a smaller size (expressed in number of bits) to a bigger destination argument, the question arises as to what to do with the remaining bits. Let us consider copying an 8-bit value from BL to the 16-bit AX register. If the value copied is unsigned or positive (let it be 5), the remaining bits should be cleared.

              ;   AH      AL
mov AL, BL    ;        00000101   = 5 in AL
mov AH, 0     ;00000000
              ;0000000000000101   = 5 in AX

If the value is negative (e.g. -5) the situation changes.

              ;   AH      AL
mov AL, BL    ;        11111011   = -5 in AL
mov AH, 0     ;00000000
              ;0000000011111011   = 251 in AX

It is clear that, to preserve the original value, the upper bits must be set to ones, not zeros.

              ;   AH      AL
mov AL, BL    ;        11111011   = -5 in AL
mov AH, 0xFF  ;11111111
              ;1111111111111011   = -5 in AX

There are special instructions which perform automatic sign extension, copying the sign bit to all higher bit positions. They can be considered as type conversion instructions. These instructions have no arguments, as they operate only on the accumulator.

  • cbw - converts byte in AL to word in AX
  • cwd - converts word in AX to doubleword in DX:AX
  • cwde - converts word in AX to doubleword extended in EAX
  • cdq - converts doubleword in EAX to quadword in EDX:EAX
  • cdqe - convert doubleword in EAX to quadword in RAX
  • cqo - convert quadword in RAX to double quadword in RDX:RAX

Sign-extension instructions operate solely on the accumulator. Fortunately, there are also more general instructions that copy and extend data simultaneously.

  • movsx - copies and sign-extends a byte to a word or doubleword or word to doubleword.
  • movzx - copies and zero-extends a byte to a word or doubleword or word to doubleword.
  • movsxd - copies and extends a doubleword to a quadword in x64 processors.

Exchange instructions

The exchange instruction swaps the values of the operands. A single exchange instruction can replace three mov instructions while swapping the contents of two arguments, so they can be useful in optimising some algorithms. They help implement semaphores, even in multiprocessor systems.

  • xchg - swaps the values of two arguments. If one of the arguments is in memory, the instruction behaves as if the LOCK prefix were present, allowing for semaphore implementation.
  • cmpxchg - compare and exchange
  • cmpxchg8b - compare and exchange 8 bytes
  • cmpxch16b - compare and exchange 16 bytes

The cmpxchg has three arguments: source, destination and accumulator. It compares the destination argument with the accumulator; if they are equal, the destination argument value is replaced with the value from the source operand. It is used to test and modify semaphores. Its operation is presented in figure 1. In newer machines, the eight- and sixteen-byte versions were added cmpxchg8b and cmpxchg16b. They always use ECX:EBX or RCX:RBX as the source register pair and EDX:EAX or RDX:RAX as the accumulator pair. The destination argument is in the memory.

Diagram showing cmpxchg instruction logic: compares destination with accumulator; if equal, replaces destination with source value; if not equal, loads destination into accumulator. Shows decision flow.
Figure 1: Explanation of cmpxchg Instruction
  • xadd - instruction exchanges two arguments, adds them, and stores the sum in a destination argument. When combined with a LOCK prefix, it can be used to implement a DO loop that executes simultaneously on multiple processors.
  • bswap - instruction is a single-argument instruction; it changes the order of bytes in a 32- or 64-bit register. It can be used to convert little-endian data to big-endian representation and vice versa, as shown in figure 2.
Diagram showing bswap instruction reversing byte order in 32-bit register: input bytes [3,2,1,0] become [0,1,2,3], converting little-endian to big-endian format.
Figure 2: Explanation of bswap Instruction in 32-Bit Mode

Stack instructions

A stack is a special structure in the memory that automatically stores the return address (address of the next instruction) while procedure calling (it is described in detail in the section about the call instruction). It is also possible to use the stack for local variables in functions, for passing arguments to procedures, and for storing temporary data. In the x86 architecture, the stack is supported by hardware with the special stack pointer register. Instructions that operate on the stack automatically modify the stack pointer so that it always points to the top of the stack.

  • push instruction decrements the stack pointer and places the data onto the stack. As a result, the stack pointer points to the last data on the stack. It is shown in figure 3.
Diagram showing push instruction: stack pointer decrements, data value stored at new stack top. Shows memory locations and stack pointer movement.
Figure 3: Explanation of push Instruction
  • pop instruction removes data from the stack, copies it into the destination register, and increments the stack pointer. After its execution, the stack pointer points to the previous data stored on the stack. It is shown in figure 4.
Diagram showing pop instruction: data removed from stack top, stored in destination register, stack pointer increments to previous data. Shows memory and register changes.
Figure 4: Explanation of pop Instruction

Some instructions push or pop all eight general-purpose registers (including the stack pointer).

  • pusha - pushes all 16-bit registers
  • popa - pops all 16-bit registers
  • pushad - pushes all 32-bit registers
  • popad - pops all 32-bit registers

The order of registers on the stack for these instructions is shown in figure 5. These instructions are not supported in 64-bit mode.

Diagram showing pushad/popad register order on stack: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI pushed/popped in sequence. Shows stack layout and pointer movement.
Figure 5: Explanation of pushad and popad Instructions

Arithmetic instructions

Arithmetic instructions perform calculations on binary encoded data. It is worth noting that the processor does not distinguish between unsigned and signed values; it is the responsibility of the programming engineer to provide correct input values and to interpret the results properly.

Some instructions support decimal arithmetic, but because BCD numbers are rarely used in modern software, they are not available in x64 mode.

Addition and subtraction

There are two adding instructions.

  • add - adds two values from the destination and source arguments and stores the result in the destination argument. It modifies the flags in the EFLAG register according to the result.
  • adc - instruction additionally adds “1” if the carry flag (CF) is set. It allows the processor to compute the sum of values that are larger than can be encoded in a register (for example, 128-bit integers on a 64-bit processor).

Similarly, there are two subtraction instructions.

  • sub - subtracts the source argument from the destination argument, stores the result in the destination, and sets the flags accordingly.
  • sbb - instruction calculates the difference of arguments minus “1” if the CF flag is set (here, CF plays the role of the borrow flag).

Incrementation and decrementation

The argument can be incremented or decremented. The argument is treated as an unsigned integer.

  • inc - instruction adds “1” to the argument
  • dec - instruction subtracts “1” from the argument.

Multiply

Two multiply instructions are implemented.

  • mul - unsigned multiplication
  • imul - signed multiplication

The mul is a one-argument instruction. It multiplies the argument and the accumulator, treating them as unsigned numbers. The size of the accumulator corresponds to the size of the argument. The result is stored in the accumulator. Since multiplication can produce results twice as large as the input values, it is stored in a larger accumulator size, as shown in the table 2.

Table 2: Multiply Instruction Argument and Result Size
Argument Accumulator Result
8 bits AL AX
16 bits AX DX:AX
32 bits EAX EDX:EAX
64 bits RAX RDX:RAX

The imul instruction performs signed multiplication. It can have one, two or three arguments. The single-argument version behaves the same way as the mul instruction. The two-argument version multiplies the 16-, 32-, or 64-bit register as the destination operand by the argument of the same size. The three-argument version multiplies the source argument by the immediate and stores the result in the destination, which is the same size as the arguments. The destination must be the register.

Divide

Two divide instructions are implemented.

  • div - unsigned division
  • idiv - signed division

The div is a one-argument instruction. It divides the accumulator's contents by the argument, treating both as unsigned numbers. The size of the accumulator is twice the size of the argument. The result is stored as two integer values of the same size as the argument. The quotient is placed in the lower half of the accumulator, and the remainder in the higher half of the accumulator. Depending on the size of the argument, the accumulator is understood as a pair of registers DX:AX, EDX:EAX or RDX:RAX, as shown in the table 3.

Table 3: Divide Instruction Arguments and Results Size
Argument Accumulator Quotient Remainder
8 bits AX AL AH
16 bits DX:AX AX DX
32 bits EDX:EAX EAX EDX
64 bits RDX:RAX RAX RDX

The idiv instruction performs signed division. It behaves the same way as the div instruction except for the type of numbers.

Logical instructions

The set of logical instructions contains:

  • and - logical and
  • or - logical or
  • xor - logical exclusive or
  • not - logical not (inversion)

All of them perform bitwise Boolean operations corresponding to their names. The not is a single-argument instruction; others have two arguments.

Shift and rotate instructions

Shift and rotate instructions treat the argument as the shift register. Each bit of the argument is moved to the neighbouring position on the left or right, depending on the direction of the shift. The number of bit positions for the shift can be specified as a constant or in the CX register. Shift instructions can be used to multiply (shift left) and divide (shift right) by powers of two.
Shift instructions have two versions: logical and arithmetical.

  • shl - logical shift left
  • shr - logical shift right
  • sal - arithmetical shift left
  • sar - arithmetical shift right

The shl and sal behave the same, filling the empty bits (at the LSB position) with zeros. Logical shift right shr fills the empty bits (at the MSB position) with zeros, while the arithmetical shift right sar makes a copy of the most significant bit, preserving the sign of a value. It is shown in figure 6.

Diagram showing shift instruction variants: shl/sal shift bits left with zero fill, shr shifts right with zero fill, sar shifts right preserving sign bit. Shows bit movement and empty bit fill patterns.
Figure 6: Explanation of Shift Instructions

Two double-shift instructions move bits from the source argument to the destination argument. The number of bits is specified as the third argument.

  • shrd - shift double right
  • shld - shift double left

The operation of shift double instructions is presented in figure 7.

Diagram showing double shift instructions: shld/shrd shift bits between two registers, moving bits from source to destination while preserving register width. Shows source/destination interaction.
Figure 7: Explanation of Double Shift Instructions

For all shift instructions, the last bit shifted out is placed in the carry flag.

Rotate instructions move bits shifted out of one side of an argument into the opposite side.

  • rol - rotate left
  • ror - rotate right
  • rcl - rotate with carry left
  • rcr - rotate with carry right

Rotate instructions shift bits left rol or right ror in the argument, and additionally move bits around from the lowest to the highest or from the highest to the lowest position. Behaviour of rotate instructions is shown in figure 8.

Diagram showing rotate instructions: rol/ror rotate bits in circular fashion, bits shifted out re-enter opposite side. Shows left and right rotation patterns.
Figure 8: Explanation of Rotate Instructions

Rotate with carry left rcl and right rcr, treat the carry flag as the additional bit during rotation. They can be used to collect bits to form multi-bit data. Behaviour of rotate with carry instructions is shown in figure 9.

Diagram showing rotate with carry instructions: rcl/rcr include carry flag in rotation cycle, carry flag participates as extra bit. Shows 9-bit rotation including carry.
Figure 9: Explanation of Rotate with Carry Instructions

Bit and Byte Instructions

Bit test instruction makes a copy of the selected bit into the carry flag.

  • bt - bit test

A combination of two arguments specifies the bit for testing. The first argument, called the bit-base operand, holds the bit. It can be a register or a memory location. The second operand is the bit offset, which specifies the position of the bit operand. It can be a register or an immediate value. It starts counting from 0, so the least significant bit has the position 0. An example of the behaviour of the bt instruction is shown in figure 10.

Diagram showing bit test instruction: specified bit position copied to carry flag, original data unchanged. Shows bit index and carry flag result.
Figure 10: Explanation of Bit Test Instruction

Bit test and modify instructions first make a copy of the selected bit, and next modify the original bit value with the one specified by the instruction.

  • bts - bit test and set to one
  • btr - bit test and clear (resets to zero value)
  • btc - bit tr=est and change the state to the opposite (complement).

The bit scan instructions search for the first occurrence of a bit set to 1.

  • bsf - bit scan forward
  • bsr - bit scan reverse

The bsf scans from the least significant bit towards higher bits, and the bit scan reverse bsr scans from the most significant bit towards lower bits. Both instructions return the index of the found bit in the destination register. If there is no bit of the value 1, the zero flag is set, and the destination register value is undefined.

Byte instructions are used to test the content of an argument, set the argument based on the condition, count the number of bits equal to “1” and compute CRC.

  • test - instruction performs the logical AND function without storing the result. It just modifies the flags based on the result of the AND operation.
  • setcc - instruction sets the argument to 1 if the chosen condition is met, or clears the argument if the condition is not met.

The condition can be freely chosen from the set of conditions available for other instructions, for example, cmovcc. This instruction is useful for converting the result of the operation into a Boolean representation.

  • popcnt - instruction counts the number of bits equal to “1” in a data. The applications af this instruction include genome mining, handwriting recognition, digital health workloads, and fast hamming distance counts7).
  • crc32 - instruction implements cyclic redundancy check (CRC) computation in hardware. The polynomial of the value 11EDC6F41h is fixed.

Control transfer instructions

Before describing the instructions used for control transfer, we will discuss how to calculate the destination address. The destination address is the address the processor jumps to.

Near and far transfer

While segmentation is enabled, the destination address can be specified either as an offset or in full logical form.
If there is an offset only, the instruction modifies the instruction pointer solely, the jump is performed within the current segment and is called near.
If the address is provided in full logical form, containing segment and offset parts, the CS and IP registers are modified. Such an instruction can perform a jump between segments and is called far.

Absolute and relative address

An absolute address is given as a value specifying the destination address as the number of the byte counted from the beginning of the memory, or, if segmentation is enabled, as the offset from the beginning of the segment.
A relative address is calculated as the difference between the current value of the instruction pointer and the absolute destination address. It is provided in the instructions as the signed number representing the distance between the current and destination addresses.
If it is possible to encode the difference as an 8-bit signed value, the jump is called short.
Usually, an assembler automatically chooses the shortest possible encoding.

Conditional and unconditional control transfer

Conditional transfer instructions check the state of the selected flags in the Flags register and jump to the specified address if the condition evaluates to true. If the condition evaluates to false, the processor proceeds to the next instruction in the instruction stream.
Conditions are specified the same way as in the cmovcc instruction as the suffix to the main mnemonic. Unconditional transfer instructions are always executed the same way. They jump to the specified address without any condition checking.

Unconditional control transfer instructions

Unconditional control-transfer instructions perform a jump to a new address, changing the program flow.

  • jmp - instruction jumps to a destination address by putting the destination address in the instruction pointer register. If segmentation is enabled and the destination address is in a different segment than the current one, it also modifies the CS register.
  • call - instruction is designed to handle subroutines. It also jumps to a destination address, but before setting the instruction pointer to the new value, it pushes the return address onto the stack. The returning address is the address of the next instruction after the call. This allows the processor to use the return address later to return from the subroutine to the main program.
  • ret - instruction pairs with the call. It uses the information stored on the stack to return from a subroutine.

The process of calling a procedure and returning to the main program is shown in figure 11.

Diagram showing call/return procedure: call instruction pushes return address onto stack, jumps to procedure, ret pops return address and resumes execution.
Figure 11: Explanation of call and ret Instructions
In assembler, subroutines are called procedures. In other languages, you can find the names: function (it can return the resulting value), method (in object-oriented languages) or subprogram.

Interrupts

An interrupt mechanism in x86 works with hardware-signalled interrupts or with special interrupt instructions. Return from an interrupt handler is performed by executing the interrupt return instruction.\\

  • iret - return from an interrupt

In 32 and 64-bit architectures, the mnemonic for this instruction is iretd.
The iret instruction differs from the ret instruction in that it pops not only the return address but also the contents of the Flags register from the stack. This keeps the content of this register unmodified upon return and prevents unintentional blocking after interrupts.
The process of an interrupt handler being called and returning to the main program is shown in figure 12.

Diagram showing interrupt flow: hardware or int instruction triggers interrupt, processor pushes flags and return address, jumps to handler, iret pops address and flags to resume.
Figure 12: Illustration of Interrupt Signalling and Return from the Handler

Software interrupts can be generated as an exception or with a special instruction. They are handled the same way as hardware-signalled interrupts.

  • int - signals the interrupt of a given number
  • int1 - one-byte special machine codes used for debugging
  • int3 - one-byte special machine codes used for debugging
  • into - signals a software overflow exception if the OF flag is set
  • bound - raises the bound range exceeded exception (int 5) when the tested value is over or under the defined bounds.

The last two instructions are not valid in 64-bit mode.

In 32- and 64-bit operating systems, interrupts are handled by the OS and accessed through interrupt descriptors, also called gates.

Conditional control transfer instructions

Conditional control transfer instructions are used to test the state of the flags and to perform a jump to the destination address if the condition is met. They are formed as a jump instruction with the mnemonic expanded by a condition code.

  • jcc - conditional jump (cc is a condition code)

In modern pipelined processors, it is recommended to avoid conditional jumps whenever possible to ensure the program flows continuously without invalidating the pipeline. It is important to remember that flags are modified as a result of executing the arithmetic or logic instruction, but not the mov instruction. For example, if we need to test if some variable is zero, we can write such code:

cmp var1, 0     ;compare variable
jz is_zero      ;conditional jump to address is_zero
mov RAX, "1"    ;if not zero, put ASCII code of "1" in RAX
jmp not_zero    ;jump unconditionally over the next instruction
is_zero:        ;label to jump to if var1 is zero
mov RAX, "0"    ;if zero, put ASCII code of "0" in RAX
not_zero:       ;label to jump to if var1 is not zero
You can try to optimise this code by avoiding jumps. Try to use the conditional mov instruction.

Loop instructions

The instructions are used to implement a software loop. It can be executed a known number of times or finished prematurely. The number of iterations should be set before a loop in the counter register (CX/ECX/RCX).

  • loop - unconditional loop instruction

The loop instruction automatically decrements the counter register, checks if it reaches zero and if not jumps to the address, which is the argument of the instruction and is assumed as the beginning address of a loop. If the counter reaches zero, the loop instruction goes further to the next instruction in a stream.
There are also conditional versions of the loop instruction that allow the iteration to finish before the counter reaches zero.

  • loope - conditional loop (if ZF is set)
  • loopz - same as loope
  • loopne - conditional loop (if ZF is cleared)
  • loopnz - same as loopne

The loope or loopz instructions continue the iteration if the counter is above zero and the zero flag (ZF) is set.
The loopne or loopnz continue the iteration if the counter is greater than zero and the zero flag (ZF) is cleared.
The loop instruction can cause the system to iterate many times if the counter register is zero before entering the loop. Since the first step is to decrement the counter, the result will be a value composed entirely of “1s”. For CX, the loop will be executed 65536 times; for ECX, more than 4 billion times; and for RCX, 184 quintillion 466 quadrillion 744 trillion 73 billion 709 million 551 thousand and 616 times!
Understandably, we should avoid such a situation. We have three instructions to jump over the loop if the counter is zero.

  • jcxz - jump if CX is zero
  • jecxz - jump if ECX is zero
  • jrcxz - jump if RCX is zero

These instructions can help to jump over the entire loop if the counter register is zero at the beginning, as in the following code.

lea RBX, table   ;pointer to table with values to sum
mov RCX, size    ;size of a table - we can't ensure it's not zero
xor RDX, RDX     ;zero RDX - it will be the sum af elements
jrcxz end_loop   ;jump over the loop if rcx is zero
begin_loop:
add RDX, [RBX]   ;add the item to the resulting value
inc RBX          ;point to another item in a table
loop begin_loop  ;loop
end_loop:
According to information found on the Internet, the loop instructions are not optimised for modern pipelined processors and are often replaced with compare-and-conditional-jump instructions.

String Instructions

String instructions are developed to perform operations on elements of data tables, including text strings. These instructions can access two memory locations: the source and the destination. If segmentation is enabled, the source operand is identified with SI/ESI.
It is always placed in the data segment (DS), while the destination operand is identified with DI/EDI and is stored in the extended data segment (ES).
In 64-bit mode, the source operand is identified with RSI, and the destination operand is identified with RDI.
They can operate on bytes, words, double words, or quad words.
The size of the element is specified as the suffix of the instruction or derived from the size of the arguments specified in the instruction.

String copy

  • movs - instruction copies the element of the source string to the destination string. It requires two arguments of the same size: bytes, words, doublewords, or quadwords.
  • movsb - instruction copies a byte from the source string to the destination string.
  • movsw - instruction copies a word from the source string to the destination string.
  • movsd - instruction copies a doubleword from the source string to the destination string.
  • movsq - instruction copies a quadword from the source string to the destination string.
The source and destination operands are always accessed via the source and destination index registers, which must be loaded correctly before the string instruction is executed. Arguments, if present, are used to determine the size of the element only.

Store string

These instructions store the accumulator's contents into the destination operand.

  • stos - instruction copies the content of the accumulator to the destination string. It requires one argument of size byte, word, doubleword, or quadword.
  • stosb - instruction copies a byte from the AL to the destination string.
  • stosw - instruction copies a word from the AX to the destination string.
  • stosd - instruction copies a doubleword from the EAX to the destination string.
  • stosq - instruction copies a quadword from the RAX to the destination string.

Load string

These instructions load the content of the source string to the accumulator.

  • lods - instruction copies the content of the source string to the accumulator. It requires one argument of size byte, word, doubleword, or quadword.
  • lodsb - instruction copies a byte from the source string to the AL.
  • lodsw - instruction copies a word from the source string into the AX register.
  • lodsd - instruction copies a doubleword from the source string to the EAX.
  • lodsq - instruction copies a quadword from the source string to the RAX.

String compare

Strings can be compared, which means that the element of the destination string is compared with the element of the source string. These instructions set the status flags in the flags register according to the result of the comparison. The elements of both strings remain unchanged.

  • cmps - instruction compares the element of a source string with the element of the destination string. It requires two arguments that specify the sizes of the data elements.
  • cmpsb - instruction compares a byte from the source string with a byte from the destination string.
  • cmpsw - instruction compares a word from the source string with a word from the destination string.
  • cmpsd - instruction compares a doubleword from the source string with a doubleword from the destination string.
  • cmpsq - instruction compares a quadword from the source string with a quadword from the destination string.

String scan

Strings can be scanned, which means that the element of the destination string is compared with the accumulator. These instructions set the status flags in the flags register according to the result of the comparison. The accumulator and string element remain unchanged.

  • scas - instruction compares the accumulator with the element of the destination string. It requires one argument, which specifies the size of the accumulator and the data element.
  • scasb - instruction compares the AL with a byte from the destination string.
  • scasw - instruction compares the AX with a word from the destination string.
  • scasd - instruction compares the EAX with a doubleword from the destination string.
  • scasq - instruction compares the RAX with a quadword from the destination string.

Repeated string instructions

The repetition prefix can precede all string instructions to automate the processing of multiple-element tables. Use of the prefix enables the instruction to automatically repeat execution based on the counter register's contents and to modify the source and destination addresses in the index registers according to the element size.
Index registers can be incremented or decremented depending on the direction flag (DF) state. If DF is “0”, the addresses are incremented; if DF is “1”, the addresses are decremented. While the string element's size is a byte, the addresses are modified by 1. For words, the addresses are modified by 2, for doublewords by 4, and for quadwords by 8.

  • rep prefix allows block copying, storing and loading of an entire string rather than a single element.

The use of repeated string instructions enables copying an entire string from one place in memory to another or filling memory regions with a pattern.

  • repe or repz prefixes additionally test whether the zero flag is “1” to terminate the string scan or comparison prematurely.
  • repne or repnz prefixes test whether the zero flag is “0” to stop iteration through the string.

The conditional prefixes are intended to be used with scas or cmps instructions.
The use of repeated-string instructions with conditional prefixes enables string comparisons for equality or difference, or for finding an element in a string.

To properly use the repeated string instructions, follow these steps:

  1. Set the SI/ESI/RSI with the address of the source string.
  2. Set the DI/EDI/RDI with the address of the destination string.
  3. Clear or set the DF to determine the direction of string processing - from lower to higher or from higher to lower addresses, respectively.
  4. Set the counter register CX/ECX/RCX with the number of elements to process
  5. Execute the string instruction with repetition prefix and suffix according to the size of the element.

I/O Instructions

These instructions allow the processor to transfer data between the accumulator register and a peripheral device.
A peripheral device can be addressed directly or indirectly. Direct addressing uses an 8-bit constant as the peripheral address (also called an I/O port in x86), and it accesses only the first 256 port addresses. Indirect addressing uses the DX register as the address register, enabling access to the entire I/O address space of 65536 addresses.

  • in instruction reads data from a port to the accumulator.
  • out instruction writes the data from the accumulator to the port. The accumulator size determines the amount of data to be transferred. It can be AL, AX or EAX.

The I/O instructions also have string versions.
Instructions to read the port to a string are:

  • ins - read from port to a string
  • insb - read byte from port
  • insw - read word from port
  • insd - read doubleword from port

Instructions to write a string to a port are

  • outs - write string to a port
  • outsb - write byte to a port
  • outsw - write wrod to a byte
  • outsd - write doubleword to a port

In all string I/O instructions, the port is addressed with the DX register. Rules for addressing the memory are the same as in string instructions.

Enter and Leave Instructions

Enter instruction creates the stack frame for the function. The stack frame is a region of the stack reserved for a function to store arguments and local variables. Traditionally, we access the stack frame using the RBP register, but we need to preserve its contents before use.

  • enter - create the stack frame for the function
  • leave - clear the stack frame, restore stack pointer

The enter instruction can be nested or non-nested. Not-nested saves the RBP on the stack, copies the stack pointer value to RBP, and adjusts the stack pointer with the constant value, which is the first operand of the instruction. After these steps, the RSP points to the top of the stack frame, and the RBP points to the stack base. The nested version creates the path to the higher-level functions' stack frames by adding their momentary value of RBP.
The leave instruction reverses what enter did at the end of the function. The enter should be placed at the very beginning of the function, while the leave just before ret.

According to information on compiler behaviour, the enter instruction is never used by compilers, while the leave instruction is rarely used.

Flag Control Instructions

Flag control instructions are typically used to set or clear the chosen flag in the RFLAGS register. We can only control three flags directly.
The carry (CF) flag can be used in conjunction with the rotate-with-carry instructions to convert the series of bits into a binary-encoded value.
The direction (DF) flag determines whether the index registers RSI and RDI are modified when executing string instructions. If the DF flag is clear, the index registers are incremented; if the DF flag is set, the registers are decremented after each iteration of a string instruction.
The interrupt (IF) flag controls whether hardware interrupts are enabled. If the IF flag is set, the hardware interrupts are enabled; if the IF flag is clear, hardware interrupts are masked.

The summary of instructions is shown in the table 4.

Table 4: Flags Manipulating Instructions
Instruction Behavoiur flag affected
stc set carry flag CF=1
clc clear carry flag CF=0
cmc complement carry flag CF=not CF
std set direction flag DF=1
cld clear direction flag DF=0
sti set interrupt flag IF=1
cli clear interrupt flag IF=0

The flags register can be pushed onto the stack and popped afterwards. This can be done inside the procedure, but also to test or manipulate bits in the flags register, for which a special instruction does not support modifications.

  • pushf - pushes the FLAGS register
  • pushfd - pushes the EFLAGS register
  • pushfq - pushes the RFLAGS register
  • popf - pops the FLAGS register
  • popfd - pops the EFLAGS register
  • popfq - pops the RFLAGS register
  • lahf - copy SF, ZF, AF, PF, and CF to the AH register
  • sahf - store flags back from AH

Segment Register Instructions

Segment register instructions load a far pointer into a pair of registers. One of the pair is the segment, which is determined by the instruction; the other is the offset, which appears as the destination argument. The source argument is the far pointer stored in the memory. These instructions include:

  • lds – load far pointer using DS,
  • les – load far pointer using ES,
  • lfs – load far pointer using FS,
  • lgs – load far pointer using GS,
  • lss – load far pointer using SS.

The following example shows how to load a far pointer in 16-bit mode.

; Load far pointer to DS:BX
; Variable Far_point holds the 32-bit address
 
lds  BX,Far_point
 
; Instruction above is equal to:
 
mov  AX,WORD PTR Far_point+2 ; Take higher word of far pointer
mov  DS,AX                   ; Store it in DS
mov  BX,WORD PTR Far_point   ; Store lower word of far pointer in BX

In 64-bit mode, lds and les instructions are not supported.

Miscellaneous instructions

Multiple other instructions fall outside the classification presented above. A brief review is presented below.

No operation

The no-operation instruction results in an incrementation of the instruction pointer only.

  • nop no operation

In reality, it is an alias to the instruction xchg EAX, EAX.

nop             ;encoded as 0x90
xchg EAX, EAX   ;encoded as 0x90

Load effective address

The load effective address instruction calculates the effective address as the result of the proper address expression and stores the result in a destination operand.

  • lea - load the effective address

We can store the effective address in a single register to avoid complex address calculations within a loop, as in the following example.

; Load effective address to BX
; Table is the beginning of the table in the memory
 
  lea   BX,Table[SI]
 
; Now we can use BX only to make the program run faster:
hoop:
  mov   AX,[BX] ; Take value from table
  inc   BX      ; Next element in the table
  cmp   AX,0    ; Check if element is 0
  jne   hoop    ; Jump to „hoop" if AX isn't 0
Because the lea instruction loads the source operand into the destination register, it is sometimes used instead of the add instruction.

Undefined instructions

The undefined instructions can be used to test the behaviour of the system software in the event of an unknown opcode appearing in the instruction stream.

  • ud - undefined instruction
  • ud1 - undefined instruction
  • ud2 - undefined instruction

The first two instructions can have a source operand (a register or memory address) and a destination operand (a register). Operands are not used. The ud2 instruction has no operand.

Executing any undefined instruction results in an invalid opcode exception (#UD) throw.

Table lookup

Table lookup instructions load the element of a table pointed to by a base address and the index of an element.

  • xlatb - table lookup
  • xlat - table lookup

The xlatb instruction copies the byte from a table into the AL register. The byte is addressed as the sum of the BX/EX/RBX and AL registers. There is also an xlat version, which allows specifying the memory address as the argument. It can be somewhat misleading because the processor never uses the argument. This instruction can be used to convert a 4-digit binary value to a hexadecimal digit, as shown in the following code.

.DATA
conv_table DB "0123456789ABCDEF"
 
.CODE
; Load base address of table to BX
  lea   RBX, conv_table
  and   AL, 0Fh  ; Limit AL to 4 bits
  xlatb          ; Take element from the table
  mov   char, AL ; Resulting char is in AL

Processor identification

The processor identification instruction provides detailed information about the processor's hardware features.

  • cpuid - processor identification

It operates similarly to the function, with the input value sent via an accumulator (EAX). Depending on the EAX value, the processor provides different information. The requested information is returned in processor registers. For example, if EAX is zero, it returns the vendor information string “GenuineIntel” for Intel processors and “AuthenticAMD” for AMD models in the ECX, EDX, and EBX registers. It is shown in figure 13.

Diagram showing cpuid instruction vendor string reading: EAX=0 returns vendor ID, ECX contains first 4 letters, EDX next 4, EBX last 4. Shows "GenuineIntel" and "AuthenticAMD" output.
Figure 13: Illustration of Vendor String Reading by cpuid Instruction

MOVBE instruction

  • movbe - swap and move

This instruction moves data after swapping data bytes. It operates on words, doublewords or quadwords and is usually used to change the endianness of the data.

Cache manipulating instructions

The processor manages cache memory, and its decisions usually maintain good software execution performance. However, the processor offers instructions that allow the programmer to send hints to the cache management mechanism and prefetch data in advance of using it and to synchronise the cache and memory and flush the cache line to make it available for other data.

  • prefetchw - prefetch data to a cache
  • prefetchwt1 - prefetch data to a cache
  • clflush - mark cache line as free
  • clflushopt - mark cache line as free

There are also additional instructions for cache management, introduced together with the multimedia and vector extensions.

User Mode Extended State Save/Restore Instructions

Some instructions allow saving and restoring the state of several processor units. They are intended to help processors with fast context switching between processes and to replace the practice of saving each register separately at the beginning of a subroutine and restoring it at the end. The content of registers is stored in memory pointed to by the EDX:EAX registers.
Instructions for saving the state are:

  • xsave - save processor extended states
  • xsavec - save processor extended states with compaction
  • xsaveopt - save processor extended states optimised

Instructions for restoring the state are:

  • xrstor - restore processor extended states
  • xgetbv - get value of extended control register

Random Number Generator Instructions

In the x64 architecture, there are two instructions for generating a random number.

  • rdseed - generate random number
  • rdrand - generate random number

A specially designed hardware unit generates a random number. The difference between instructions is that rdseed gets random bits generated from entropy gathered from a sensor on the chip. It is slower but offers better randomness of the number.
The rdrand gets bits from a pseudorandom number generator. It is faster, offering output that is sufficiently secure for most cryptographic applications.

BMI1 and BMI2 Instructions

The abbreviation BMI comes from Bit Manipulation Instructions. These instructions are designed for specific bit manipulation in the arguments, enabling programmers to use a single instruction instead of several.

  • andn - instruction extends the group of logical instructions. It performs a bitwise AND of the first source operand with the inverted second source operand.

There are additional shift and rotate instructions that do not affect flags, allowing for more predictable execution without relying on flag changes from previous operations.

  • rorx - rotate right without affecting flags
  • sarx - shift arithmetic right without affecting flags
  • shlx - shift logic left without affecting flags
  • shrx - shift logic right without affecting flags

Also, unsigned multiplication without affecting flags, mulx, was introduced.

  • mulx - multiply without affecting flags

Other instructions manipulate bits as the group name stays.

  • lzcnt - counts the number of zeros in an argument starting from the most significant bit
  • tzcnt - counts zeros starting from the least significant bit
  • bextr - extracts bits
  • blsi - extract bit set
  • blsmsk - set lower bits
  • blsr - reset lower bits
  • bzhi - reset high bits
  • pdep - parallel deposit
  • pext - parallel bit extraction

For an argument that is not zero, lzcnt returns the number of zeros before the first 1 from the left, and tzcnt gives the number of zeros before the first 1 from the right.
The bextr instruction copies the number of bits from source to destination arguments starting at the chosen position. The third argument specifies the number of bits and the starting bit position. Bits 7:0 of the third operand specify the starting bit position, while bits 15:8 specify the maximum number of bits to extract, as shown in figure 14.

Diagram of bit extraction instruction showing bextr operation: extracts specified range of bits from source, starting position and length controlled by third operand.
Figure 14: Illustration of Bit Extraction Instruction

The blsi instruction extracts the single, lowest bit set to one, as shown in figure 15.

Diagram of blsi instruction isolating lowest set bit: identifies rightmost 1-bit and creates mask, useful for bit manipulation and counting.
Figure 15: Illustration of Lowest Set Bit Extraction Instruction

The blsmsk instruction sets all lower bits below a first bit set to 1. It is shown in figure 16.

Diagram of blsmsk instruction creating mask below lowest set bit: all bits below rightmost 1 are set to 1, used for range operations.
Figure 16: Illustration of the Instruction Which Sets All Lower Bits Below a First Bit Set to 1

The blsr instruction resets (clears the bit to zero value) the lowest set bit. It is shown in figure 17.

Diagram of blsr instruction clearing lowest set bit: removes rightmost 1-bit from value, commonly used in bit iteration and counting.
Figure 17: Illustration of the Instruction Which Resets a First Bit Set to 1

The bzhi instruction resets high bits starting from the specified bit position, as shown in figure 18.

Diagram of bzhi instruction masking high bits: clears all bits from specified position upward, keeping only lower bits.
Figure 18: Illustration of the Instruction Which Resets High Bits Starting from the Specified Bit Position

The pdep instruction performs a parallel deposit of bits using a mask. Its behaviour is shown in figure 19.

Diagram showing parallel deposit instruction: spreads source bits into positions specified by mask, useful for data packing.
Figure 19: Illustration of the Parallel Deposit Instruction

The pext instruction performs parallel bit extraction using a mask. Its behaviour is shown in figure 20.

Diagram showing parallel extract instruction: gathers bits from masked positions into contiguous result, inverse of pdep operation.
Figure 20: Illustration of the Parallel Extraction Instruction
en/multiasm/papc/chapter_6_7.txt · Last modified: by mcp_agent
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0