Linux终端下如何检测向下箭头输入?汇编实现遇阻求助
汇编中读取向下箭头输入的问题
我搞不懂怎么在汇编里读取向下箭头的输入,需要通过这个输入进入下一个字符串。我检查了寄存器ebx和ecx,发现它们的值不一样。我尝试初始化了一个包含^[[B(按下向下箭头时的字符)的字符串,但按下向下箭头再回车后,程序会跳转到sbaglio标签,输出check_olio和变量a的内容(换行符)。
以下是我的汇编代码:
.section .bss .lcomm a 256 .section .data Freccia_giu: .string "^[[B" Freccia_giu_len: .long . - Freccia_giu _start: # write the first string movl $4, %eax movl $1 ,%ebx movl $Menu, %ecx mov Menu_len, %edx int $0x80 # interupt call to save the down arrow in a rileva_freccia: # get down arrow movl $3, %eax movl $0 ,%ebx movl $a, %ecx movl $255, %edx int $0x80 movb $0, (%ecx, %eax, 1) # verifiy down arrow movl $a, %ecx movl $Freccia_giu ,%ebx cmp %ebx ,%ecx jne sbaglio je fine #non equity lable sbaglio: movl $4, %eax movl $1 ,%ebx movl $Check_Olio, %ecx mov Check_Olio_len, %edx int $0x80 movl $4, %eax movl $1 ,%ebx movl $a, %ecx mov $256, %edx int $0x80 fine: movl $4, %eax movl $1 ,%ebx movl $Setting_Automobile, %ecx mov Setting_Automobile_len, %edx int $0x80
问题分析与修复
你的代码存在几个核心问题:
- 错误的比较逻辑:你直接对比
ecx和ebx里的内存地址,而不是字符串内容。movl $a, %ecx是把变量a的地址存入ecx,movl $Freccia_giu, %ebx是把Freccia_giu的地址存入ebx,这两个地址必然不同,所以cmp %ebx, %ecx永远会跳转到sbaglio。 - 终端输入模式限制:默认终端是规范模式,输入要等回车才会传给程序,此时输入缓冲区里除了
^[[B还会多一个换行符\n,导致a的内容和Freccia_giu不匹配。 - 缺少字符串内容对比逻辑:没有逐字节检查两个字符串的实际内容是否一致。
修复方案
1. 切换终端到非规范模式(可选)
如果不想等回车就能读取输入,需要用ioctl系统调用修改终端属性,禁用规范模式和回显。如果接受按回车的方式,也可以只处理输入的前3个字节。
2. 正确对比字符串内容
用循环逐字节对比a和Freccia_giu的内容,直到遇到终止符或不匹配字节。
修复后的代码示例
.section .bss .lcomm a 256 .lcomm termios 36 # 存储终端属性 .section .data Freccia_giu: .string "^[[B" Freccia_giu_len: .long . - Freccia_giu Menu: .string "Press Down Arrow:\n" Menu_len: .long . - Menu Check_Olio: .string "check_olio\n" Check_Olio_len: .long . - Check_Olio Setting_Automobile: .string "Setting_Automobile\n" Setting_Automobile_len: .long . - Setting_Automobile _start: # 保存原终端属性 movl $54, %eax # ioctl系统调用号 movl $0, %ebx # stdin movl $0x5401, %ecx # TCGETS 获取终端属性 movl $termios, %edx int $0x80 # 修改终端属性:禁用规范模式、回显 movl termios+12, %eax # 获取c_lflag andl $~0x00000003, %eax # 清除ICANON(规范模式)和ECHO(回显) movl %eax, termios+12 # 设置新终端属性 movl $54, %eax movl $0, %ebx movl $0x5402, %ecx # TCSETS 设置终端属性 movl $termios, %edx int $0x80 # 输出提示 movl $4, %eax movl $1, %ebx movl $Menu, %ecx movl Menu_len, %edx int $0x80 rileva_freccia: # 读取输入(非规范模式下,按下箭头直接返回3字节) movl $3, %eax movl $0, %ebx movl $a, %ecx movl $3, %edx # 读取3字节(向下箭头的转义序列长度) int $0x80 # 字符串比较 movl $Freccia_giu, %esi movl $a, %edi movl Freccia_giu_len, %ecx repe cmpsb # 逐字节对比,直到ecx为0或不匹配 jne sbaglio # 不匹配则跳转到错误标签 fine: # 输出目标字符串 movl $4, %eax movl $1, %ebx movl $Setting_Automobile, %ecx movl Setting_Automobile_len, %edx int $0x80 jmp restore_term # 恢复终端属性后退出 sbaglio: # 输出错误信息 movl $4, %eax movl $1, %ebx movl $Check_Olio, %ecx movl Check_Olio_len, %edx int $0x80 # 输出输入内容(调试用) movl $4, %eax movl $1, %ebx movl $a, %ecx movl $3, %edx int $0x80 movl $4, %eax movl $1, %ebx movl $"\n", %ecx movl $1, %edx int $0x80 restore_term: # 恢复原终端属性 movl $54, %eax movl $0, %ebx movl $0x5402, %ecx movl $termios, %edx int $0x80 # 退出程序 movl $1, %eax xorl %ebx, %ebx int $0x80
关键说明
- 终端模式修改:通过
ioctl切换到非规范模式,按下向下箭头时程序会立即读取到3字节的转义序列^[[B,无需回车。 - 字符串比较:使用
repe cmpsb指令逐字节对比字符串内容,确保完全匹配才进入正常流程。 - 终端属性恢复:程序退出前必须恢复终端原属性,否则终端会保持无回显、非规范模式,影响后续使用。
内容的提问来源于stack exchange,提问作者Not_Smart
相关产品推荐
相关产品推荐

