проблемы со сравнением на ассемблере (TASM)

#assembly #dos #x86-16 #tasm

#сборка #dos #x86-16 #tasm

Вопрос:

У меня возникли проблемы со сравнением двух значений в 64-разрядной версии Windows 10 TASM. Я пытаюсь отобразить последние N строк файла (я не включил весь код, но предполагаю, что обработка файла правильная, я могу предоставить полный код, если необходимо), поэтому я создал процедуру (READN), которая считывает N из входных данных.

 N          DW   3
LINES      DW   0

READN PROC NEAR

      MOV  AX, @DATA
      MOV  DS, AX
      MOV  DI, N
      MOV  AH, 1
      INT  21H
      MOV  N, AX
      XOR  AX, AX
      MOV  AX, N
      MOV  DX, AX
      MOV  AH, 2
      INT  21H
      RET
READN ENDP
  

Затем я подсчитываю количество строк в данном файле в процедуре COUNTLINES, увеличивая СТРОКИ каждый раз, когда появляется ‘ n’ или

 COUNTLINES PROC NEAR

      MOV  AH,3FH         ;read from file function
      MOV  BX,HANDLE      ;load file handle
      LEA  DX,FBUFF       ;set up pointer to data buffer
      MOV  CX,1           ;read one byte
      INT  21H            ;DOS call
      CMP  AX,0           ;were 0 bytes read?
      JZ   EOFF           ;yes, end of file found
      MOV  DL,FBUFF       ;no, load file character
      CMP  DL,1AH         ;is it Control-Z <EOF>?
      JZ   EOFF           ;jump if yes
      CMP  DL,0AH         ;is it n ?
      JZ   INCR           ;jump if yes
      JMP  COUNTLINES       ;and repeat
      MOV  AH,9           ;display string function
      INT  21H            ;DOS call
      STC                 ;set error flag

EOFF:     inc DS:[LINES]
      XOR AX, AX
      MOV AX, LINES
      ADD AX, '0'
      SUB AX, N
      MOV N, AX
      MOV LINES, 0
      MOV AX, N
      MOV DX, AX
      MOV AH, 2
      INT 21H
      CALL CLOSEFILE
      CALL OPENFILE
      RET

INCR:     INC DS:[LINES]
      JMP COUNTLINES
COUNTLINES ENDP
  

И, наконец, проблема, с которой я сталкиваюсь, заключается в процедуре DISPLAYLINES, где я снова увеличиваю СТРОКИ с нуля, но на этот раз, когда СТРОК становится меньше N, я начинаю распечатывать строки. Проблема в том, что мое сравнение (в части INCREM: ) работает не так, как я ожидал, и когда я пытаюсь сравнить N и СТРОКИ (сначала я переношу СТРОКИ в AX), программа просто никогда не переходит к нужной функции, хотя значения в какой-то момент должны быть равны. Если бы вы могли попытаться выяснить, почему это происходит, или, возможно, даже предоставить исправление, я был бы очень благодарен.

 DISPLAYLINES PROC NEAR

      MOV  AH,3FH         ;read from file function
      MOV  BX,HANDLE      ;load file handle
      LEA  DX,FBUFF       ;set up pointer to data buffer
      MOV  CX,1           ;read one byte
      INT  21H            ;DOS call
      CMP  AX,0           ;were 0 bytes read?
      JZ   EOF           ;yes, end of file found
      MOV  DL,FBUFF       ;no, load file character
      CMP  DL,1AH         ;is it Control-Z <EOF>?
      JZ   EOF           ;jump if yes
      CMP  DL,0AH         ;is it n ?
      JZ   INCREM           ;jump if yes
      JMP  DISPLAYLINES       ;and repeat

EOF:      RET

INCREM:   INC  DS:[LINES]
      MOV  AX, LINES
      CMP  AX, N
      JZ   PRINT
      JMP  DISPLAYLINES

PRINT:    MOV  AH,3FH         ;read from file function
      MOV  BX,HANDLE      ;load file handle
      LEA  DX,FBUFF       ;set up pointer to data buffer
      MOV  CX,1           ;read one byte
      INT  21H            ;DOS call
      CMP  AX,0           ;were 0 bytes read?
      JZ   EOF           ;yes, end of file found
      MOV  DL,FBUFF       ;no, load file character
      CMP  DL,1AH         ;is it Control-Z <EOF>?
      JZ   EOF           ;jump if yes
      MOV  AH,2           ;display character function
      INT  21H            ;DOS call
      JMP  PRINT       ;and repeat
DISPLAYLINES ENDP
  

Комментарии:

1. Открыт ли файл? Чтение выполнено успешно? INCREM Действительно вызывается?

2. да, да, и я не понимаю третий вопрос

3. В этом коде-спагетти много ошибок. Ваша проблема в основном основана на MOV N, AX in READN . Int 21/AH=01h возвращает результирующий символ ASCII в AL и случайное значение в AH . Итак, поместите xor ah,ah прямо перед MOV N, AX . Возможно, сегодня вечером я смогу написать полный ответ.

4. @rkhb это действительно спагетти-код: DD Я очень новичок в сборке, так что потерпите меня, пожалуйста. Я обязательно попробую ваше предложение.

Ответ №1:

readn

 MOV  AH, 1
INT  21H
MOV  N, AX
  

Эта функция DOS возвращает символ! Вместо этого вам нужно значение. Лучше напишите

 MOV  AH, 1
INT  21H
sub  al, '0'
mov  ah, 0
MOV  N, AX
  

количество строк

 MOV AX, LINES
ADD AX, '0'
SUB AX, N
MOV N, AX
  

Здесь ADD AX, '0' было несколько необходимо из-за предыдущей ошибки. Теперь вы можете просто записать

 MOV AX, LINES
SUB AX, N
MOV N, AX
  

строки отображения

Раньше это не удавалось, потому что в коде readn был старший байт 1 в переменной N. Это, в свою очередь, привело к появлению очень большого нового N после приведенного выше вычитания строк подсчета. Вот почему печать так и не произошла!
Внесите оба исправления, и вы увидите, что сбой больше не происходит…

Ответ №2:

Если вы добавите директиву IDEAL в начале вашего исходного файла, а затем замените все команды непосредственными значениями с явно указанными значениями ‘offset’ или в квадратных скобках — вы решите все свои проблемы. Если, конечно, вы используете borland turbo assembler.