8

From https://www.felixcloutier.com/x86/div:

    ...
    temp ← AX / SRC;
    IF temp > FFH
        THEN #DE; (* Divide error *)
        ELSE
            AL ← temp;
            AH ← AX MOD SRC;
    FI;
    ...

For div ah the SRC would be ah. IMHO temp will always be larger than FFH and therefore the exception will be raised since:

  1. AX = 256*AH+AL
  2. temp = AX / AH = (256*AH+AL)/AH = 256 + AL/AH
  3. temp is over FFH

Do I miss something here?

rfalke
  • 451
  • 4
  • 7
  • Your reasoning seems correct. – fuz Aug 05 '20 at 21:38
  • 3
    Yeah. But it's not like they made separate instructions for each operand (although some instructions do have special encodings for particular operands). Just because you can use an operand that makes little sense doesn't mean they specifically implemented that behavior. – Jester Aug 05 '20 at 21:39

1 Answers1

9

That's correct, just like div edx it's never usable without faulting. The criterion for 2N/N => N-bit div not overflowing its quotient is high_half(dividend) < divisor, as you showed, so using divisor = high(dividend) will always overflow (or divide by zero). Why "DIV EDX" in MASM always generates processor exception? explains the same thing another way.

Interesting point that it's a guaranteed one-instruction way to raise #DE without requiring any instructions to put values in register, though.

(In protected mode, int 0 is not exactly the same thing. e.g. under Linux, in user-space int 0 will #GP -> SIGSEGV because of permissions on the IDT entry, while an actual divide exception will #DE -> SIGFPE).


As Jester points out, that encoding only accounts for 1 of the 2^5 possible encodings of F6 /6 div r/m8, counting just the ModRM byte (not the vast possibilities of extra bytes that addressing modes can use).

Making it not-encodeable would take extra transistors in the decoders. And then what do you do with that 2-byte sequence? #UD illegal instruction exception? That's silly, just let it raise #DE after decoding normally and getting to the execution unit like any other div instruction. Or use it for some other special thing like mfence?

It probably wouldn't really have been a sensible design decision to have the 2-byte machine code for div ah actually mean some totally different single instruction. In any case, that ship sailed with 8086 where it will raise #DE, not #UD; any change would break that backwards compat. Since there are less intrusive ways to find new coding-space for new opcodes (e.g. like the illegal encodings of lds and les or whatever that VEX prefixes borrow), Intel and AMD haven't yet stooped to such insanity. Those LES / LDS 32-bit-mode encodings already raised #ud instead of another exception, and more importantly had more spare bits so the VEX prefixes have room to actually encode some fields in those 2 or 3 byte prefixes.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • (I should maybe mention that 8086 itself didn't have `#UD` exceptions; every byte sequence decoded as *something*. Also fun fact, the exception address was always the *end* of the faulting instruction, even for `#DE`, unlike on later CPUs where the fault address is the start of the div / idiv. So 8086 maybe didn't even keep track of where the instruction started, and it can process an unlimited number of prefixes before an opcode. Unlike later CPUs that limit instruction-length to 15 bytes max, else #UD) – Peter Cordes Apr 04 '21 at 19:20