Introduction
The string instructions work on one element of memory at a time, a byte, word, doubleword or quadword, and then step their pointers to the next one. Their operands are implicit:
- the source is at DS:SI, DS:ESI or RSI; another segment can be chosen with a segment prefix;
- the destination is at ES:DI, ES:EDI or RDI, always with ES;
- the address size (16, 32 or 64 bits, changed with a 67 prefix) picks the pointer registers and the count register, CX, ECX or RCX;
- the operand size picks the element size: no prefix for the default, 66 for a word in 32-bit code (or a doubleword in 16-bit code), REX.W for a quadword;
- the direction flag, DF, says which way the pointers step: up when it is clear
(
cld), down when it is set (std).
A repeat prefix runs the instruction again and again, counting down the count register until it is 0:
- REP (
F3) with MOVS, STOS, LODS, INS and OUTS; - REPE or REPZ (
F3) with CMPS and SCAS, which also stops when ZF = 0; - REPNE or REPNZ (
F2) with CMPS and SCAS, which also stops when ZF = 1.
rep movsb and rep stosb are still the usual way to copy and
fill memory, and processors with ERMSB (enhanced REP MOVSB and STOSB, CPUID leaf 7,
EBX bit 9) run them fast. The byte and word forms came with the 8086 in 1978, INS and
OUTS with the 80186, the doubleword forms with the 80386 and the quadword forms with
x86-64.
The instructions
The disassembler writes both implicit operands, as LLVM does:
rep movsb byte ptr es:[edi], byte ptr [esi] for F3 A4 in
32-bit code. Intel’s manual also has forms that name a memory operand
(MOVS m8, m8); the operands only give the size and the source segment.
Moving and storing
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
movsb | – | A4 | Copies a byte from [rSI] to ES:[rDI], then steps both pointers by 1. | 8086 (Intel 8086, 1978) |
movsw | – | A5 (16-bit operand size) | Copies a word; steps by 2. | 8086 (Intel 8086, 1978) |
movsd | – | A5 (32-bit operand size) | Copies a doubleword; steps by 4. Not to be confused with the SSE2 movsd, F2 0F 10, which has the same name. | 80386 (Intel 80386, 1985) |
movsq | – | REX.W A5 | Copies a quadword; steps by 8. | x86-64 (AMD Opteron, 2003, and Intel EM64T, 2004) |
stosb | – | AA | Stores AL at ES:[rDI], then steps rDI. | 8086 (Intel 8086, 1978) |
stosw | – | AB (16-bit operand size) | Stores AX. | 8086 (Intel 8086, 1978) |
stosd | – | AB (32-bit operand size) | Stores EAX. | 80386 (Intel 80386, 1985) |
stosq | – | REX.W AB | Stores RAX. | x86-64 (AMD Opteron, 2003, and Intel EM64T, 2004) |
lodsb | – | AC | Loads the byte at [rSI] into AL, then steps rSI. With REP only the last element is left, so it is rarely repeated. | 8086 (Intel 8086, 1978) |
lodsw | – | AD (16-bit operand size) | Loads a word into AX. | 8086 (Intel 8086, 1978) |
lodsd | – | AD (32-bit operand size) | Loads a doubleword into EAX. | 80386 (Intel 80386, 1985) |
lodsq | – | REX.W AD | Loads a quadword into RAX. | x86-64 (AMD Opteron, 2003, and Intel EM64T, 2004) |
Comparing and scanning
These set the status flags as cmp does, and are the ones REPE and REPNE
apply to.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
cmpsb | – | A6 | Compares the byte at [rSI] with the byte at ES:[rDI] (the first minus the second), then steps both. | 8086 (Intel 8086, 1978) |
cmpsw | – | A7 (16-bit operand size) | Compares words. | 8086 (Intel 8086, 1978) |
cmpsd | – | A7 (32-bit operand size) | Compares doublewords. Not to be confused with the SSE2 compare cmpsd, F2 0F C2. | 80386 (Intel 80386, 1985) |
cmpsq | – | REX.W A7 | Compares quadwords. | x86-64 (AMD Opteron, 2003, and Intel EM64T, 2004) |
scasb | – | AE | Compares AL with the byte at ES:[rDI], then steps rDI. repne scasb finds a byte, such as the zero at the end of a C string. | 8086 (Intel 8086, 1978) |
scasw | – | AF (16-bit operand size) | Compares AX with a word. | 8086 (Intel 8086, 1978) |
scasd | – | AF (32-bit operand size) | Compares EAX with a doubleword. | 80386 (Intel 80386, 1985) |
scasq | – | REX.W AF | Compares RAX with a quadword. | x86-64 (AMD Opteron, 2003, and Intel EM64T, 2004) |
Port strings
INS and OUTS move data between memory and the I/O port numbered by DX, with the
same I/O permission checks as in
and out. There is no
quadword form: with REX.W they still move doublewords.
| Instruction | Forms | Encoding | What it does | Set |
|---|---|---|---|---|
insb | – | 6C | Reads a byte from port DX into ES:[rDI], then steps rDI. | 80186 (Intel 80186, 1982) |
insw | – | 6D (16-bit operand size) | Reads a word. | 80186 (Intel 80186, 1982) |
insd | – | 6D (32- or 64-bit operand size) | Reads a doubleword. | 80386 (Intel 80386, 1985) |
outsb | – | 6E | Writes the byte at [rSI] to port DX, then steps rSI. | 80186 (Intel 80186, 1982) |
outsw | – | 6F (16-bit operand size) | Writes a word. | 80186 (Intel 80186, 1982) |
outsd | – | 6F (32- or 64-bit operand size) | Writes a doubleword. | 80386 (Intel 80386, 1985) |
Notes
- Interrupts. A repeated string instruction can be interrupted between elements. The registers then show how far it got, and it carries on after the interrupt returns.
- Flags. MOVS, STOS, LODS, INS and OUTS change no flags. CMPS and SCAS set OF, SF, ZF, AF, PF and CF.
- Other prefixes. F2 or F3 on an instruction that is not a string
instruction is shown as
repneorrepwhere LLVM shows it, and otherwise taken as part of the opcode (SSE’sF3 0F 58isaddss). With LOCK or a memory destination they may be XACQUIRE and XRELEASE instead; see the Transactions and synchronisation page. - 64-bit mode. ES has a base of 0 there, so the destination is
simply [RDI]; LLVM still writes
es:, and so does the disassembler.
Links
Reference
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – Intel’s manuals; volume 2 describes each instruction
- AMD64 Architecture Programmer’s Manual, Volume 3 – AMD’s reference to the general-purpose and system instructions
- x86 and amd64 instruction reference – Félix Cloutier’s web copy of the instruction pages of Intel’s manual