ROT13 Шифр ​​в сборе

Итак, мой шифр ROT13 в значительной степени выполняет то, что я хочу, однако в конце командная строка отображается в той же строке, что и последняя строка вывода. Это мой первый проект в Assembly, поэтому я не совсем уверен, что делаю неправильно.

1 ответ

Решение

Ваша программа не печатает новую строку в конце своего вывода, поэтому курсор находится в конце непустой строки, когда он выходит. Оболочка не знает этого и печатает следующую подсказку там.

echo foo включает в себя завершающий символ новой строки, поэтому, когда оболочка печатает следующее приглашение, курсор уже находился в начале новой строки. echo -n foo не включает завершающий символ новой строки, поэтому он оставляет курсор в конце строки, начинающейся с foo, и ваша подсказка привязана к этому, как и ваша программа. Передайте эти эхо-команды в hd чтобы увидеть hexdump символов ASCII, которые они печатают.


Таким образом, решение состоит в том, чтобы ваш вывод заканчивался символом новой строки (код ASCII = 10). У вас уже есть это в вашем msg4: db 10, "Read error", 10 строка. (Он начинается с новой строки, а также заканчивается на одну.) В C вы написали бы `"\nRead error\n", но синтаксис NASM не работает таким образом. Он поддерживает экранирование в стиле C внутри строк в кавычках, но обычно люди пишут новые строки с числовыми константами.


Ваш пользовательский ввод (который вы получаете из sys_read) должен обычно заканчиваться символом новой строки, если пользователь не набрал 256 символов в строке или не использовал ctrl-D, чтобы сделать чтение ранним. (Или аналогичным образом переданный ввод, который не заканчивается новой строкой, так что читайте хиты EOF).

Я начал следовать логике сравнений, но это довольно быстро утомило. Я не уверен, что происходит с новыми строками в вашем входе, но я подозреваю, что ваш код изменяет новые строки в буфере. Вам, вероятно, следует избегать этого и оставить их без изменений. Я полагаю, вы просто добавили бы их в свой список сравнений и веток, чтобы символы не могли быть изменены.

Это, вероятно, более полезное поведение для программы rot13, чем добавление дополнительной новой строки в конец буфера или вызов sys_write еще один раз для самостоятельной печати новой строки.


Вы можете проверить системные вызовы, которые делает ваша программа, используя strace, например strace ./a.out декодирует системные вызовы read() и write(), которые вы делаете.

Дополнительные советы по отладке см. В нижней части вики-тега x86. (Который имеет много полезных вещей, кроме этого).


Кстати, вы могли бы сделать все эти cmp al, '?' сравнивает параллельно в регистре xmm с SSE2 (широковещательно передает все элементы каждого регистра xmm и PCMPEQB с константой / PMOVMSKB / test/jnz). Но не беспокойтесь об этом, пока не разберетесь со скалярным кодом.


Другим способом избежать гнезда CMP/JCC для крыс было бы использование алфавитных символов в белом списке, оставляя входные символы неизмененными по умолчанию.

Я не уверен, почему вы только черный список '1', но не другие цифры, или '+' но нет '-', и так далее.


Вот как я реализовал ваш цикл с некоторыми "продвинутыми" приемами, чтобы объединить несколько одинаковых условий в единые условия. См. Мой ответ о том, как получить доступ к массиву символов и изменить строчные буквы на прописные, и наоборот, для объяснения хитрости сравнения без знака для isalpha().

;; ROT13 alphabetic characters.  Copy others unmodified.
;;  Untested
L1_top:
    movzx   eax, [esi]              ; get a character
    inc     esi                     ; update source pointer

    mov     edx, eax                ; save a copy of the original
    or      al, 0x20                ; make it lower-case if it's a letter (but we can still detect non-letters after this)

    sub     al, 'a'                 ; chars below 'a' will wrap to a high value
    cmp     al, 'z'-'a'
    ja      .non_alpha              ; jump if the sub wrapped, or the char was greater than 'z'

    ; input char was alphabetic
    sub     dl, 13                  ; modify the original character
    sub     al, 13                  ; check if that takes us out of the alphabet.  Can be a CMP, not SUB if we want.
    jnc     .nocarry
    add     dl, 26                  ; add 26 if the subtract wrapped
    ;add     al, 26                 ; we don't care about the value in al anymore
.nocarry:

    ; dl = the ROT13'ed character, with its original case
.non_alpha:
    mov    [edi], dl
    inc    edi

    dec    ecx                      ; I'm not sure what all the cmp ecx,0  in various branches was for.  Just do it earlier if necessary.
    jnz    L1_top

Первоначально я собирался вычислить символ ROT13 в нижнем регистре в AL, а затем найти разницу между этим и исходным символом в нижнем регистре и применить его к DL. Но потом я понял, что могу условно изменить DL в более раннем ветвлении.

    ;; after the or al,0x20:    mov   ah, al       ; don't over-do it with upper-half byte registers.  False dependencies on AMD, and partial-reg merging stalls or slowdowns on pre-Haswell Intel if you're not careful.

    add     al, 'a'                 ; 'a' + al is the lower-cased ROT13 of the input character
    sub     ah, al                  ; ah = lcase(orig) - lcase(rot13)
    sub     dl, ah                  ; apply that delta to the original in dl
    ; dl is the original character - 13 (plus 26 if necessary)
Другие вопросы по тегам