Бесконечный цикл после завершения программы

#assembly #x86 #dos #infinite-loop

#сборка #x86 #dos #бесконечный цикл

Вопрос:

Итак, эта программа была для назначения. Срок выполнения прошел, и я сдал то, что у меня было, и получил хорошую оценку, но эта ошибка беспокоила меня. Технически это больше не задание, но я бы все же предпочел, чтобы вы не писали код для меня, поскольку я хочу понять, почему это происходит, а не обязательно исправлять это.

Итак, программа работает нормально (по сути toUpper() , в сборке), но после того, как я передаю программе завершающий символ (точку), программа успешно вызывает ‘end’, но затем фактически никогда не завершается. Если я запускаю его в пошаговом отладчике, вызывается «end main», тогда программа переключается на какой-то предварительно написанный код, который я не распознаю, может очищать стек, вызывая DOS, я понятия не имею. Я пробовал много разных вещей (все безуспешно), и мне любопытно, есть ли у кого-нибудь представление о том, что может быть причиной этого.

Код ниже:

 ;---------------------------------------------------------------------
;    program:     Key
;    function:    Reads in specific characters from input and displays them.
;    owner:       ----------
;    date:        9/29/11
;    09/22/2011   Original Version
;----------------------
    .model small
    .8086
;----------------------
    .data              ; Start the data segment
;----------------------
    ; No variables

;----------------------
    .code              ; Start the code segment
;----------------------
main:                  ; Reading in values
    mov ah, 8h         ; Request input without echo
    int 21h            ; Read character into al

    cmp al, 20h        ; Is it a space?
    je  print          ; If so, print with no changes
    cmp al, 2Eh        ; Is it a period?
    je  print          ; If so, go to exit.
    cmp al, 41h        ; Is it below the floor of uppercase?
    jl  main           ; Then it's useless, throw it out and read in new.
    cmp al, 7Ah        ; Is it above lower ceiling?
    jg  main           ; Then it's useless, throw it out and read in new.
    cmp al, 5Ah        ; Is it smaller than upper ceiling?
    jle print          ; If it's equal or smaller, then it's an upper.
    cmp al, 61h        ; Is it above lower floor?
    jl  main           ; If it is lower, back to main.
                       ; If we're here it's a lowercase letter
    sub al, 20h        ; Subtract 20h to make lowercase

print:                 ; Print characters
    mov dl, al         ; Copy character to output register
    mov ah, 2h         ; Load character output subroutine
    int 21h            ; Print character
    cmp dl, 2Eh        ; Check if it was a period.
    jne main           ; If not a period, go to main.

    mov ah, 4Ch        ; Place Exit Code for DOS service
    int 21h            ; call DOS service
    end main           ; If it was a period, exit program.
;----------------------
  

2 строки до конца были предложены моим другом, у которого больше опыта работы с ассемблером, чем у меня, и это приводит к правильному завершению программы на моем эмуляторе DOS, но проблема с ‘end’ все еще возникает в отладчике и моем сценарии тестирования профессора.

У кого-нибудь есть идеи, что может быть причиной этого?

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

1. Когда вы вызываете DOS для выхода, al содержит код выхода (или уровень ошибки). Попробуйте mov ax, 4c00h вместо mov ah, 4ch. Таким образом, код ошибки будет равен 0 (означает, что все в порядке)

2. Вау, так это исправлено, потрясающе. Итак, я предполагаю, что в al было оставшееся число, и это, должно быть, каким-то образом отбросило его? Отправьте это как ответ, если хотите, чтобы я мог пометить его решаемым.

3. Комментарий в sub al, 20h строке должен быть «Вычтите 20 часов, чтобы сделать верхний регистр», а не нижний регистр.

4. Хех, да, хороший улов. По-видимому, я пропустил кучу комментариев, когда возвращался к этому вопросу.

Ответ №1:

Когда вы вызываете DOS для выхода, al содержит код выхода (или уровень ошибки). Попробуйте mov ax, 4c00h вместо mov ah, 4ch этого . Таким образом, код ошибки будет равен 0 (означает, что все в порядке). Это заставляет его работать, потому что код возврата каким-то образом используется оператором DOS IF ERRORLEVEL ... , который все портит. 😉

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

1. @Чарльз: никаких проблем. Сборка полна этих причудливых головокружительных штучек 😉

Ответ №2:

Когда вы говорите, что программа успешно «завершает вызов», вы имеете в виду, что она переходит к end main ?

end ничего не делает. Это просто инструкция для ассемблера, указывающая конец вашего кода. Это не влияет на выполнение вашего кода. Без финала int 21h , предложенного вашим другом, ваш код будет просто продолжать выполняться. Если вам повезет, он продолжит выполнять nop инструкции.

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

1. Да, я думаю, это было то, что я неправильно понял. Я не понимал, что это, по сути, инструкция компилятора, и что int 21h / mox ax, 4c00h была фактической командой выхода. По сути, я приравнивал end к Java System.exit(), а команды int / mov — к числу в круглых скобках, хотя на самом деле это более или менее наоборот.

2. Хотя на самом деле приятно видеть, что студентам все еще преподают языки ассемблера, меня забавляет, что они учат вас ассемблеру x86, работающему в контексте MS-DOS. Это напоминает мне, что мне пришлось пройти курс IBM BAL (Basic Assembler Language), работающий на OS / 360, который уже сильно отстал от времени, когда я его изучал. Потребовались усилия, чтобы убедить инструктора позволить мне выполнить последние три задания, используя более современную машину и ОС. Это действительно странно видеть int 21h снова.

3. Я полностью понимаю, почему это преподается с исторической, скрытой точки зрения, хотя я действительно хотел бы, чтобы у нас было больше подобных классов, но для других языков: Ruby, php и т. Д.; Я бы получил от них гораздо больше пользы.