Реверс и изменение регистра данной строки x86 сборки - PullRequest
1 голос
/ 05 мая 2019

Цель этой программы - перевернуть заданную строку при переключении регистра каждой буквы. Строка не может быть длиннее 20 символов, если ввод длиннее, программа требует, чтобы пользователь снова ввел строку. Программа заканчивается, когда пользователь вводит «enter», и программа заканчивается после печати конечного предложения.

Реализация этого у меня 3 проблемы:

  1. Я попытался получить строку ввода с помощью вызова ReadString, и поскольку эта процедура останавливается, когда дается клавиша ввода, консоль останавливается, когда я нажимаю клавишу ввода, чтобы нормально завершить программу. Как я могу исправить свой код, чтобы он напечатал завершающее сообщение, а затем нормально завершить программу с возвращаемым значением 0?

  2. Если длина входящей строки превышает 20 символов, пользователю необходимо снова ввести строку. Поэтому я написал Ja L1. Бур по какой-то причине, mov bytecount, eax; cmp bytecount, 20; не может фильтровать дело должным образом. Когда выполняется строка mov bytecount, eax, значение bytecount является правильным, но когда программа выполняет следующую строку, cmp bytecount, 20, значение bytecount изменяется. Я не знаю, что я делаю не так.

  3. Процедура CaseChange останавливается при ее выполнении, поэтому я предполагаю, что она зацикливается бесконечно, но я не могу найти, какое условие является неправильным.

.data
MaxLength = 20
prompt3 BYTE "End of program",0
buffer BYTE MaxLength DUP(0)
bytecount DWORD ?

.code 
main PROC
    call Clrscr
L1: mov edx, OFFSET buffer
    mov ecx, SIZEOF buffer
    call PromptForInput     ; printing input prompt
    call ReadString      
    mov bytecount, eax
    cmp bytecount, 20       ;*** get input again if number of characters in the string is greater than 20
    ja L1                   ;*** 
    call ReverseString     
    call CaseChange         ;***
    mov edx, OFFSET buffer
    call WriteString        ;printing the result
    loop L1
    mov edx, OFFSET prompt3 ;*** after input <ent> how do I print prompt3?
    call WriteString
    exit
main ENDP

CaseChange PROC
    pushad 
    mov eax, OFFSET buffer
L1:
    mov dl, BYTE PTR[eax]
    test dl, dl
    jz L3
    cmp dl, 'A'
    jl L3
    xor dl,32
    cmp dl,'z'
L2:
    inc eax
    jmp L1
L3:
    popad
    ret
CaseChange ENDP

(запрос ввода): Кошки и собаки.

(запрос на вывод): .SGOd DNA STAc

(приглашение ввода): слишком долго для заданного ограничения

(запрос ввода):

Конец программы

1 Ответ

1 голос
/ 05 мая 2019

В инструкции говорится о ReadString :

Считывает строку из ненулевых символов ECX из стандартного ввода, останавливаясь, когда пользователь нажимает клавишу Enter.
Нулевой байт сохраняется после ввода символов , но символы возврата каретки и перевода строки не помещаются в буфер.
ECX всегда должен быть меньше размера буфера (никогда не равняется размеру буфера), поскольку нулевой байт может быть (ECX + 1) -ым сохраненным символом.

После этого ясно, что вам нужно увеличить буфер:

buffer BYTE MaxLength + 1 DUP (0)

Если вы указали ECX=MaxLength, то вы не можете получить ввод, который длиннее MaxLength символов, и, следовательно, нет реальной необходимости проверять такое условие.(*)

Если пользователь нажимает клавишу enter без предшествующих символов, то ReadString вернется с EAX=0.Проверьте это и перейдите к своему последнему сообщению.

Большая ошибка, когда вы написали loop L1.Инструкция loop работает с регистром ECX для выполнения известного числа итераций.Ваша программа должна просто вернуться наверх без каких-либо условий.Используйте jmp L1.

Лучше всего, если вы будете держать вещи логически вместе.Не смешивайте call PromptForInput с call ReadString и его параметрами.Можете ли вы быть уверены, что PromptForInput не изменится EDX или ECX?

L1: call    PromptForInput

    mov     edx, OFFSET buffer
    mov     ecx, MaxLength
    call    ReadString         ; -> EAX
    test    eax, eax
    jz      L2                 ; Exit

    call    ReverseString       ; Is this working fine?
    call    CaseChange

    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

    jmp     L1

L2:
    mov     edx, OFFSET prompt3
    call    WriteString         ; Final message

    exit

  • cmp dl, 'A' jl L3 The *Процедура 1050 * ChangeCase должна пройти всю строку, но вы уйдете, как только наткнетесь на байт меньше 65. Пожалуйста, используйте условие unsigned при работе с кодами ASCII [0,255].

  • xor dl,32 Вы фактически не записываете какие-либо изменения в строковую память.

  • cmp dl,'z' Вы не действуете на этомсравнить.

Если все, что вам нужно сохранить, это 1 регистр, не используйте pushad и popad.

CaseChange PROC
    push    esi
    mov     esi, OFFSET buffer
L1:
    lodsb
    test    al, al        ; End of string ?
    jz      L2
    or      al, 32        ; If "A".."Z" Then "a".."z"
    cmp     al, 'a'
    jb      L1
    cmp     al, 'z'
    ja      L1
    xor     byte ptr [esi-1], 32  ; Change case IN string memory
    jmp     L1
L2:
    pop     esi
    ret
CaseChange ENDP

(*) Есливы хотите наложить эту ошибку «Строка не может быть длиннее 20 символов», затем определить гораздо больший буфер и позволить ReadString вернуть более 20 символов, чтобы вы могли вернуться назад в программе:

buffer BYTE 99 + 1 DUP (0)

...

L1: call    PromptForInput

    mov     edx, OFFSET buffer
    mov     ecx, 99
    call    ReadString         ; -> EAX
    cmp     eax, 20
    ja      L1
    test    eax, eax
    jz      L2                 ; Exit

Последний совет - убедиться, что ReverseString и CaseChange в порядке, проверив их независимо:

    call    ReverseString
    ;;;call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

и более поздние

    ;;;call    ReverseString
    call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result

и только потом

    call    ReverseString
    call    CaseChange
    mov     edx, OFFSET buffer
    call    WriteString         ; Printing the result
...