LOOP выполняется только один раз, когда в Turbo Debugger используется один шаг - PullRequest
0 голосов
/ 07 июня 2018

Код должен выводить 'ccb', но выводить только 'c', LOOP выполняется только один раз, я откалиброван в TD, но почему LOOP выполняется только один раз?

Я ДУМАЮ, ЧТО Я ДОЛЖЕН УМЕНЬШИТЬ STRING_LENGTH, ПОЭТОМУ Я НАПИСАЛ

DEC STRING_LENGTH

, НО ЭТО НЕ РАБОТАЕТ, ПОЭТОМУ Я ГОВОРИЛ, ЧТО

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

Я ЗНАЮ, ЧТО ВЫ ДУМАЕТЕ ПРЯМО СЕЙЧАС, ЧТОЭТО НЕПРАВИЛЬНО, ВЫ ПРАВЫ)))

Я МОГУ ИСПОЛЬЗОВАТЬ C ++, НО ХОЧУ СДЕЛАТЬ ЭТО ТОЛЬКО В СБОРКЕ,

DOSSEG
.MODEL SMALL
.STACK 200H
.DATA
STRING DB 'cScbd$'
STRING_LENGTH EQU $-STRING
STRING1 DB STRING_LENGTH DUP (?) , '$'
.CODE
MOV AX,@DATA
MOV DS,AX
XOR SI,SI
XOR DI,DI

MOV CX,STRING_LENGTH

S:

MOV BL,STRING[DI]
AND STRING[DI],01111100B
CMP STRING[DI],01100000B
JNE L1
MOV AL,BL
MOV STRING1[SI],AL
ADD SI,2
L1:

ADD DI,2

LOOP S

MOV DL,STRING1
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
END

1 Ответ

0 голосов
/ 07 июня 2018

В Turbo Debugger (TD.EXE) F8 «Шаг F8» будет полностью выполнять loop, пока cx не станет нулевым (вы даже можете создать бесконечный цикл, обновив cxвернуться к некоторому значению, не позволяя ему достичь шага 1 -> 0).

Чтобы получить «одношаговый» из инструкции loop, используйте трассировку F7 F7""- это приведет к тому, что cx изменится с 6 на 5, а указатель кода будет следовать за переходом назад в начале цикла.


О некоторых других проблемах вашего кода:

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

sp не является регистром общего назначения, не используйте его для таких расчетов.Всякий раз, когда какая-то инструкция использует стек неявно (push, pop, call, ret, ...), значения записываются и читаются в области памяти, адресуемой парой регистров ss:sp, поэтому, манипулируя значением sp, вы изменяете текущий «стек».

Также в 16-битном реальном режиме x86 все прерывания (клавиатура, таймер, ...), когда они происходят, текущее состояние регистра флага и адрес кода сохраняется в стеке, прежде чем передать управление прерываниюкод обработчика, который обычно помещает дополнительные значения в стек, поэтому все, что находится в памяти по адресам ниже текущего ss:sp, небезопасно в 16-битном реальном режиме x86, и содержимое памяти продолжает «случайным образом» изменяться там всеми прерываниями, являющимисявыполняется (сам TD.EXE использует часть этой стековой памяти после каждого шага).

Для арифметики используйте другие регистры, а не sp.Как только вы узнаете достаточно о «стеке», вы поймете, какие манипуляции sp распространены и почему (например, sub sp,40 в начале функции, которая требует дополнительного «локального» пространства памяти), и как восстановить стек обратно вожидаемое состояние.


Еще одна вещь об этом:

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

STRING_LENGTH определяется как EQU, что делает его постоянной времени компиляции и только временем компиляции.Это не «переменная» (выделение памяти), в отличие от таких вещей, как someLabel dw 1345, из-за которых ассемблер испускает два байта со значениями 0100_0001B, 0000_0101B (при чтении как 16-битное слово в порядке с прямым порядком байтов, это закодированное значение 1345)и первый байтовый адрес имеет символическое имя someLabel, которое можно использовать в дальнейших инструкциях, например dec word ptr [someLabel], для уменьшения этого значения в памяти с 1345 до 1344 во время выполнения.

Но EQU отличается, он присваивает символу STRING_LENGTH окончательное значение, например 14.

Таким образом, ваш код можно прочитать как:

mov sp,14   ; makes almost sense, (practically destroys stack setup)
dec sp      ; still valid
mov 14,sp   ; doesn't make any sense, constant can't be destination for MOV
...