One MOVSB copies the byte at DS:SI to ES:DI, then moves both SI and DI to the next element. MOVSW does the same with a word. Nothing passes through a general register, and no flags change. Memory to memory in one instruction: MOV cannot do that.
| Form | Copies | SI and DI when DF = 0 | when DF = 1 |
|---|---|---|---|
| MOVSB | byte DS:[SI] to ES:[DI] | +1 | -1 |
| MOVSW | word DS:[SI] to ES:[DI] | +2 | -2 |
The direction flag picks the step: after CLD the pointers go up, after STD they go down. Put REP in front and the copy repeats CX times, so REP MOVSB is a complete memory copy: SI = source, DI = destination, CX = count. When it ends CX is 0 and SI and DI point just past the last element copied (just before it, going backward).
CLD ; forwardMOV SI, OFFSET SRC1MOV DI, OFFSET DST1 ; ES = DS in a .COMMOV CX, 3 ; 3 words = 6 bytesREP MOVSWMOV DX, OFFSET DST1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hSRC1 DB 'Words!'DST1 DB 6 DUP('.'), 13, 10, '$'
Segments
The source may come from another segment with an override, for example a table in the code segment. The destination is always ES:DI and cannot be overridden. A .COM starts with ES = DS, but an .EXE starts with ES pointing at the PSP, so load it yourself: MOV AX, @DATA / MOV ES, AX.
MOVS BYTE PTR ES:[DI], CS:[SI] ; source from CS: prefix 2Eh, then A4h
Pitfalls
Forgetting CLD: nothing promises DF = 0 when your code starts, and a backward copy runs off the front of the buffer. Overlapping blocks: if the destination starts inside the source, a forward copy overwrites bytes before reading them; copy backward instead (see CLD / STD). On the 8086 (not the 8088, whose bus is 8 bits wide) a word moves in the same bus cycle as a byte when it sits at an even address, so REP MOVSW with CX = bytes / 2, plus one MOVSB for an odd length, is the usual fast copy.
On the 8086 and 8088 a REP MOVS with a segment override has two prefixes, and if an interrupt arrives mid-copy only one of them survives (see REP). Prefer loading DS over using the override.
Later CPUs: the 80386 adds MOVSD for doublewords and 32-bit ESI, EDI and ECX.