0

I had planned to submit a short and quick interpreter for ;# in DOS as a code golf challenge, when I discovered that DOS did not interpret the # key correctly.

It's probably better to start dissecting it via a smaller example that also exhibits the behaviour:

org 0x100
L:
  mov ah, 01h      ; new input -> al
  int 21h
test al, '#'       ; check if the hash key was pressed
jnz end            ; if it wasn't, jump to the end of program
  mov dl, '1'
  mov ah, 02h
  int 21h          ; otherwise, output `1`
  jmp L            ; and loop to the beginning
end:
  mov ah, 00h      ; end the program
  int 21h

Entering # into the program, will cause it to test as false, and jump to the end. As will most other characters. However, when I enter one or more of the following characters: D, L, H, X, it outputs 1 and loops. This is obviously not what was intended.

It is probably important to note that I used Dosbox for the test.

From testing, it happens for '#', 0x23, 0x01, 0x1b (The last two scancodes were from page two of this pdf, found via a random search).

What, exactly, is going on here?

Community
  • 1
  • 1
Aster
  • 227
  • 1
  • 13
  • What's the value of `al` when you do enter `#`? Keryboard scancodes doesn't necessarily match the encoding of the same character, especially with extended keys. – Jeff Mercado May 24 '17 at 20:57
  • After `xor`'ing `ah` out, debugx tells me `ax` is `0x0023`. This is partly why I am so puzzled. – Aster May 24 '17 at 21:06
  • Hmm, I went over this exact topic in a similar question (https://stackoverflow.com/a/15182488). Essentially, you're misusing the `test` and `jnz` instructions. They have very specific uses and your interpretation of how they should behave isn't correct. – Jeff Mercado May 24 '17 at 21:22
  • 3
    while golfing, using `test` actually may sometimes reveal something interesting, like if the input can be either `#` (0x23) or digit (0x30-0x39), then `test al,0x0C` will tell you whether the input was hash or digit 0-3 (ZF=1), or digit 4-9 (ZF=0) with single test, etc... but to test for particular value you need `cmp`. – Ped7g May 24 '17 at 22:40

1 Answers1

3

test a,b computes the bitwise and of a and b, sets the flags and discards the results. test can in general not be used to compare two values for equality, use cmp for that purpose:

cmp al, '#'
fuz
  • 88,405
  • 25
  • 200
  • 352
  • This does not answer the question, given that: A) `test` works perfectly fine for comparing all of the other characters I have thrown at it (It detects which one was pressed equal in accuracy to `cmp`), and B) altering it to use `cmp` does not solve the problem. – Aster May 24 '17 at 21:07
  • You might want to read [this](https://stackoverflow.com/questions/13064809/the-point-of-test-eax-eax) for the difference between `test` and `cmp` (There is only a marginal difference) – Aster May 24 '17 at 21:12
  • 4
    @FinnO'leary If it works “fine,” then you did something wrong. `test` only returns zero, when no bits are set in the bitwise and of the two arguments, which is generally not the case if both are equal (that is, unless both are zero). You seem to have made some sort of mistake elsewhere. – fuz May 24 '17 at 21:16
  • 4
    @FinnO'leary It also seems that you fundamentally misunderstood the answer you linked. Computing `and` is a large difference from computing `sub`. – fuz May 24 '17 at 21:18
  • 1
    Whoops, it looks like I had tested `0x32` rather than `0x23`. Using `cmp al, 0x23` does indeed work. I guess `test` working this far was purely coincidencal. Time for sleep... – Aster May 24 '17 at 21:24
  • Oh, and now your replies decide to load :( – Aster May 24 '17 at 21:25