所以我的ROT13密码非常符合我的要求,但最后命令提示符显示在与最后一行输出相同的行上。这是我在大会的第一个项目,所以我很不确定我做错了什么。
答案 0 :(得分:0)
您的程序在输出结束时不会打印换行符,因此当光标退出时,光标位于非空行的末尾。 shell不知道这一点,并在那里打印下一个提示。
echo foo
包含一个尾部换行符,因此当shell打印下一个提示时,光标已经在新行的开头。 echo -n foo
不包含尾随换行符,因此它会将光标留在以foo
开头的行的末尾,并且您的提示会被添加到该行,就像您的程序一样。将这些echo命令传递到hd
以查看它们打印的ASCII字符的hexdump。
因此,解决方案是确保输出以换行符结尾(ASCII代码= 10)。您已在msg4: db 10, "Read error", 10
字符串中使用了该字符串。 (它以换行符开头,也以一行结束。)在C语言中,你写“" \ n读取错误\ n"”,但NASM语法不能这样做。它确实支持反引号字符串中的C风格转义,但人们用数字常量编写换行符是典型的。
您的用户输入(您从sys_read获得)通常应以换行符结尾,除非用户在一行上键入256个字符,或使用ctrl-D提前读取返回。 (或类似的管道输入,不会以换行结束,因此读取命中EOF)。
我开始遵循比较的逻辑,但它很快就累了。我不确定输入中的换行符会发生什么变化,但我怀疑您的代码会修改缓冲区中的换行符。你应该避免这种情况,并保持不变。我想你只是将它们添加到你的比较列表中。分支不要修改的字符。
对于rot13程序来说,这可能比在缓冲区末尾添加额外的换行符更有用,或者在一段时间内调用sys_write来自行打印换行符。
您可以使用strace
测试程序进行的系统调用。例如strace ./a.out
将解码您所做的read()和write()系统调用。
有关更多调试提示,请参阅x86标记wiki的底部。 (除此之外还有很多有用的东西)。
顺便说一下,你可以在xmm寄存器中并行地进行所有cmp al, '?'
比较,使用SSE2(广播到xmm寄存器的每个元素,PCMPEQB用常量/ PMOVMSKB / test / jnz)。但是,除非您对标量代码有良好的处理,否则不要担心。
另一种避免CMP / JCC老鼠窝的方法是白名单字母字符,默认情况下输入字符不加修饰。
我不确定你为什么只将'1'
列入黑名单,而不是列入其他数字,或'+'
而不是'-'
,等等。
以下是我如何实施您的循环,其中包含一些"高级"将多个类似条件折叠成单一条件的技巧。请参阅我在How to access a char array and change lower case letters to upper case, and vice versa上的答案,了解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
最初我打算在AL中实际计算低级ROT13字符,然后找出它与原始的低级字符之间的区别,并将其应用于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)