Search code examples
assemblyx86masmx86-16

8086 XLAT alternative


XLAT doesn't work in MASM.

What can I use instead to get the same behaviour:

XLAT : Set AL to memory byte DS:[(E)BX + unsigned AL]


Solution

  • xlatb is a valid instruction in 16, 32, and 64bit modes. Maybe you need to use the xlatb mnemonic for MASM? The Intel manual suggests that xlatb is the right mnemonic when used with implicit operands, or xlat byte ptr [bx] for the explicit form (where, like movs, the operand is basically just documentation or segment overrides, and implies the operand size.) Another idea is to see what syntax your disassembler uses for the instruction.


    However, using something else is usually a good idea, since it's only a win for code-size, not speed, on modern CPUs (3 uops on Intel Haswell for example). There are usually better alternatives (especially in 32 or 64bit code), like using movzx to get a zero-extended value into a register you can use as an index.

    In normal code, you could do:

    ; table in rbx
    movzx  eax,  src                 ; or any other way of producing a zero-extended result in rax
    movzx  eax, byte ptr [rbx + rax]     ; a movzx load avoids false deps and partial-reg slowdowns
    

    In 8086 code, you could do something like:

    ; pointer to the table in DI or SI
    xor  bx,bx             ; can be hoisted out of a loop, if bh will stay zeroed
    
    mov  bl, src   ; src can be any addressing mode, or the result of a computation
    
    mov  bl, [si + bx]     ; this is the same load that xlat does, your choice of dest
    

    bx is the only register that can be used in 16bit addressing modes that has separately-usable low and high halves (bl/bh). You need a REX prefix (64bit mode only) to use sil / dil. If you wanted to keep the table pointer in bx, like xlatb does, you'd have to zero-extend using a different register and then mov to si or di.

    If the table is static, you can of course use not tie up a register, and just use [table + (e/r)bx].