fasm,在dos环境下查词

fasm, searching a word in dos environment

练习是从键盘上取一个词,在DOS环境下搜索,如果有这个词,就在DOS环境下显示出这个词所在的行。

这是我的代码:

format binary
org 100h

 start:
        mov es,[ds:02ch]
        xor si,si

;*****************************

;*****************************

        mov ah,9
        mov dx,string
        int 21h

        mov ah,10
        mov dx,word
        int 21h

        mov ah,0
        int 16h

;*****************************

;*****************************
        xor di,di
        xor bx,bx

        start_while:

          mov di,$-word
          jge equal

          mov dl,[es:si]
          mov bl,dl
          mov dl,[bx+di]
          cmp dl,[string+di]
          jne next_line

          add di,1
          jmp start_while

        next_line:
          inc si
          cmp dl,0
          jnz notexist

        equal:
          mov ah,2
          int 21h
          jmp end

        notexist:
          mov ah,9
          mov dx,d_exist
          int 21h
          jmp end

        end:
         mov ah,08h
         int 21h
         ret

;**************************************

;**************************************

string db 'THE WORD:',10,13,"$"
word db 6
      db 0
      times 22 db "$"
d_exist db 'variable does not exist',10,13,"$'            

编译器提示:mov dl,[dl+di]错误。 我是初学者,如何修复代码?我不知道。

问题在于汇编语言的能力,更具体地说,在于处理器可以直接做什么。您尝试执行的间接内存引用无效,因为处理器不会直接添加索引寄存器(di)和通用寄存器(dl)作为指针取消引用操作(它确实允许 di + 常量,就像你在下面的几行中做的那样)。

错误消息(虽然有点混乱)来自于 dl 是那个特定位置的无效寄存器这一事实。有效选项可以是 di/si+bx+constant,或它们的任意组合。

一种可能的解决方法是使用 bp 寄存器作为变量值的中间值,而不是 dl,这在这种情况下的间接引用中是允许的。像这样的东西至少会修复这个错误:

mov bp,[es:si]
and bp, 0x00ff
mov dl,[bp+di]

请注意,由于 bp 是 16 位宽而 dl 只有 8 位,我不得不丢弃高 8 位以保留先前的预期行为,and 指令通过将那些清零来实现其余的保持不变。

除了之前提到的 x86 base plus index addressing 问题之外,还有一些其他问题和问题,其中一些会导致您不希望的结果:

start:
    mov es,[ds:02ch]
    xor si,si

    mov ah,9               ; Writes out THE WORD:
    mov dx,string
    int 21h

    mov ah,10              ; Accepts user input into "word"
    mov dx,word
    int 21h                ; reads buffered input for "word"

    ; reads keyboard key
    ; -->**** WHY? Input was just read above with INT 21 / AH = 10
    ;   
    mov ah,0
    int 16h                ;   AH = scan code, AX = ASCII char

    xor di,di
    xor bx,bx

start_while:
    mov di,$-word        ; Moves address of current location
                         ;   minus address of "word" to di -->***WHY?

    ; The last operation to affect flags was xor bx,bx, which results
    ;   in a zero. So this jump will ALWAYS be taken
    jge equal          

    ... All the code here up until the 'equal' label is skipped

equal:
    mov ah,2          ; write the character in dl to stdout
                      ;   -->*** BUT the contents of dl are unknown
    int 21h
    jmp end           ; exit the program

以上评论应该可以解释为什么您没有看到任何输出或为什么您的终端关闭(可能是 dl 中的某些控制字符)。

mov di,$-word 中的表达式 $-word 不是 word 处单词的长度。 $符号代表当前位置的地址,其中$出现,所以在上面,其实就是那个mov的地址操作说明。因此,您在 di 中得到了一些比您想要的奇数负数。如果你想要单词的长度,你应该在word之后设置一个新的数据项,一个常见的模式是在word:

的定义之后让它成为一个项目
word db 6                   ; This defines one byte, value = 6
     db 0
     times 22 db "$"
word_len db $-word          ; Word length is current address - addr of "word"
                            ; I'm assuming all 24 bytes above are for "word"