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)