x86-64汇编实现字符串转小写程序无限打印空格问题排查
代码异常原因分析
你的代码存在两个核心错误导致无限打印空格的问题:
- 未正确判断
read系统调用的返回值
Linux x86-64 架构下,系统调用的返回值统一存储在%rax寄存器中:read调用成功时返回实际读取的字节数,返回0代表到达输入EOF,返回负值代表调用出错。你的代码中直接比较缓冲区buf的值和0来判断退出,完全没有读取%rax里的返回值,当输入全部读完后,程序不会触发退出逻辑,会持续循环操作buf中的残留值反复输出。 syscall执行破坏了存储判断阈值的寄存器
x86-64 Linux 系统调用约定中,syscall指令执行时内核会主动覆盖%rcx和%r11寄存器的值(%rcx会被写入用户态返回地址),而你初始化时将判断阈值97存储在%ch(属于%rcx寄存器的高位部分),第一次执行read的系统调用后%ch的值就已经不是预期的97,后续的字符大小比较逻辑完全失效,会把字符错误处理为空格类字符输出。
修复建议
- 每次
read系统调用后先判断%rax的值,小于等于0就直接退出 - 不要用
%rcx、%r11这类会被syscall破坏的寄存器存储全局阈值,改为直接用立即数比较,或者使用%rbx这类调用者保存的寄存器存储 - 修正字符判断逻辑,仅对ASCII码在65(A)~90(Z)区间的大写字母做转小写处理,避免误转换其他符号
修复后的参考代码
.section .bss .comm buf, 1 .section .text .globl _start _start: Loop: mov $0, %rax # syscall number for read mov $0, %rdi # read from stdin mov $buf, %rsi # buffer address mov $1, %rdx # read 1 byte syscall cmp $0, %rax # check read return value jle Exit # EOF or error, exit cmpb $65, buf # char < 'A', write directly jl Write cmpb $90, buf # char > 'Z', write directly jg Write addb $32, buf # convert to lowercase Write: mov $1, %rax # syscall number for write mov $1, %rdi # write to stdout mov $buf, %rsi # buffer address mov $1, %rdx # write 1 byte syscall jmp Loop Exit: mov $60, %rax # syscall number for exit movb $0, %dil # exit code 0 syscall
内容的提问来源于stack exchange,提问作者Sargis Hovsepyan
相关产品推荐
相关产品推荐

