A far pointer is a double word in memory: the offset in the first (lower) word and the segment in the second. LDS reg, mem loads the first word into the 16-bit general register and the second word into DS. LES does the same with ES. One instruction sets a complete segment:offset address, ready for [reg] or for a string instruction. No flags change.
MOV WORD PTR [FPTR+2], CS ; the segment half, known only at run timePUSH DS ; LDS overwrites DS: keep itLDS DX, DWORD PTR [FPTR] ; DX = offset of MSG1, DS = segmentMOV AH, 09h ; DOS: print the string at DS:DXINT 21hPOP DSFPTR DW OFFSET MSG1, 0 ; offset first, then segmentMSG1 DB 'Printed through a far pointer', 13, 10, '$'
A .COM file cannot hold a segment value written by the assembler (the loader does not patch it), so the example fills in the segment half at run time. In a .EXE, DD label stores both halves and the loader fixes the segment.
Typical uses
LES DI is the usual way to aim ES:DI at video memory or at a buffer for STOS and MOVS. LDS SI aims DS:SI at a source. Pointers in the interrupt vector table at 0000:0000 are far pointers too, four bytes per interrupt.
LES DI, DWORD PTR [SCRN] ; ES:DI = B800:0000, colour text memoryMOV AX, 1F41h ; 'A', white on blueMOV ES:[DI], AX ; the top-left cell of the screenSCRN DW 0, 0B800h
XOR AX, AXMOV ES, AX ; segment 0: the interrupt vectorsMOV BX, 21h*4 ; four bytes per vectorLES BX, DWORD PTR ES:[BX] ; ES:BX = the INT 21h handler
Rules and pitfalls
The source must be memory; there is no form that takes two registers. The destination is a general 16-bit register, never a segment register. LDS changes DS, so every later access to your own variables goes to the new segment until you restore DS; save it with PUSH DS first. In MASM, give the operand DWORD PTR when the label was declared as words. The memory operand is read before either register is written, so LES BX, [BX] works.
Later CPUs
The 80386 adds LSS, LFS and LGS for the other segment registers, and 48-bit pointers with a 32-bit offset. In protected mode the segment half is a selector and loading it can fault.