You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题分析与修复

你的代码存在几个核心问题:

  1. 错误的比较逻辑:你直接对比ecx和ebx里的内存地址,而不是字符串内容。movl $a, %ecx是把变量a的地址存入ecx,movl $Freccia_giu, %ebx是把Freccia_giu的地址存入ebx,这两个地址必然不同,所以cmp %ebx, %ecx永远会跳转到sbaglio。
  2. 终端输入模式限制:默认终端是规范模式,输入要等回车才会传给程序,此时输入缓冲区里除了^[[B还会多一个换行符\n,导致a的内容和Freccia_giu不匹配。
  3. 缺少字符串内容对比逻辑:没有逐字节检查两个字符串的实际内容是否一致。

修复方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:02:21