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

如何在32位NASM汇编中正确定位打印终端用户输入?

NASM汇编终端「关于我」模块输入定位问题解决

问题场景

在Oracle虚拟机的Ubuntu环境中,使用NASM汇编开发终端端简易「关于我」模块时,遇到用户输入无法与Name:、Email:等标签正确相邻显示的问题。期望输出格式为「标签:用户输入」,但当前仅ASCII艺术字和标签处于正确光标位置,用户输入内容要么分散错位,要么无法紧邻标签显示。当前代码如下:

section .data
    clearScreen db 27, '[2J', 0          ; ANSI code to clear screen
    asciiArt1 db 27, '[5;4H', "   _   _                 _                    ", 10, \
              27, '[6;4H', "  /_\ | |__   ___  _   _| |_   _ __ ___   ___ ", 10, \
              27, '[7;4H', " //_\\| '_ \ / _ \| | | | __| | '_ ` _ \ / _ \", 10, \
              27, '[8;4H', "/  _  \ |_) | (_) | |_| | |_  | | | | | |  __/", 10, \
              27, '[9;4H', "\_/ \_/_.__/ \___/ \__,_|\__| |_| |_| |_|\___|", 10, 0

    cursorNameLabel db 27, '[8;65H'      ; Adjusted position for the name label
    nameLabel db 'Name: ', 0
    
    cursorEmailLabel db 27, '[12;4H'    ; Adjusted position for the email label
    emailLabel db 'Email: ', 0

    cursorBottom db 27, '[40;1H'

section .bss
    name resb 20     ; Reserve 20 bytes for the name
    email resb 25    ; Reserve 25 bytes for the email

section .text
    global _start

_start:
    call clearTheScreen
    call userInputs
    call displayAsciiArt
    call displayInfo
    call exitProgram

clearTheScreen:
    mov eax, 4
    mov ebx, 1
    mov ecx, clearScreen
    mov edx, 4
    int 0x80
    ret

userInputs:
    ; Input for name
    mov eax, 4
    mov ebx, 1
    mov ecx, nameLabel
    mov edx, 6          ; Length for the name label
    int 0x80

    mov eax, 3
    mov ebx, 0
    mov ecx, name
    mov edx, 20          ; Max length for the name
    int 0x80

    ; Input for email
    mov eax, 4
    mov ebx, 1
    mov ecx, emailLabel
    mov edx, 8          
    int 0x80

    mov eax, 3
    mov ebx, 0
    mov ecx, email
    mov edx, 25          ; Max length for the email
    int 0x80
    ret

displayAsciiArt:
    mov eax, 4
    mov ebx, 1
    mov ecx, asciiArt1
    mov edx, 300         ; Total length of ASCII art
    int 0x80
    ret

displayInput:
    ; Input parameters: 
    ; ecx = label address, edx = buffer address, ebx = cursor position
    mov eax, 4          ; sys_write
    mov ebx, 1          ; file descriptor (stdout)

    ; Move cursor
    mov ecx, [esp + 4]   ; Load cursor position from stack
    mov edx, 32          ; Length for cursor
    int 0x80            ; Write cursor position

    ; Print label
    mov ecx, [esp + 8]   ; Load the label address
    mov edx, 32          ; Length of the label
    int 0x80            ; Write label

    ; Print input
    mov ecx, [esp + 12]  ; Load the input address
    mov edx, 20         ; Display name input length (or change to 25 for email)
    int 0x80            ; Write input
    ret

displayInfo:
    ; Display Name
    push cursorNameLabel ; Push cursor position for name
    push nameLabel       ; Push name label
    push name            ; Push name address
    call displayInput    ; Call displayInput
    add esp, 12         ; Clean up stack

    ; Display Email
    push cursorEmailLabel; Push cursor position for email
    push emailLabel      ; Push email label
    push email           ; Push email address
    call displayInput    ; Call displayInput
    add esp, 12         ; Clean up stack
    ret

exitProgram:
    ; Move cursor to the bottom before exiting
    mov eax, 4
    mov ebx, 1
    mov ecx, cursorBottom
    mov edx, 7
    int 0x80

    mov eax, 1
    int 0x80

问题根源

  1. 流程顺序错误:先执行输入再显示ASCII艺术字和标签,导致用户输入时光标在终端默认位置,而非标签旁的指定位置。
  2. displayInput函数参数错误:
    • 光标定位序列的长度错误(cursorNameLabel实际长度为8,不是32)
    • 标签长度硬编码为32,实际Name: 长度为6,Email: 长度为8
    • 输入缓冲区长度固定为20,会包含用户输入时按下的换行符,导致显示换行错位
  3. 输入时未定位光标:用户输入前未将光标移动到标签后的指定位置,输入内容直接输出在当前光标处。

修改后的代码

section .data
    clearScreen db 27, '[2J', 27, '[H', 0  ; 清屏并重置光标到左上角
    asciiArt1 db 27, '[5;4H', "   _   _                 _                    ", 10, \
              27, '[6;4H', "  /_\ | |__   ___  _   _| |_   _ __ ___   ___ ", 10, \
              27, '[7;4H', " //_\\| '_ \ / _ \| | | | __| | '_ ` _ \ / _ \", 10, \
              27, '[8;4H', "/  _  \ |_) | (_) | |_| | |_  | | | | | |  __/", 10, \
              27, '[9;4H', "\_/ \_/_.__/ \___/ \__,_|\__| |_| |_| |_|\___|", 10, 0

    cursorNameLabel db 27, '[8;65H'      ; 标签位置:第8行第65列
    nameLabel db 'Name: ', 0
    cursorNameInput db 27, '[8;71H'      ; 输入位置:标签后(Name: 占6字符,65+6=71)
    
    cursorEmailLabel db 27, '[12;4H'     ; 标签位置:第12行第4列
    emailLabel db 'Email: ', 0
    cursorEmailInput db 27, '[12;12H'    ; 输入位置:Email: 占8字符,4+8=12

    cursorBottom db 27, '[40;1H'

section .bss
    name resb 20     ; 预留20字节存姓名
    email resb 25    ; 预留25字节存邮箱

section .text
    global _start

_start:
    call clearTheScreen
    call displayAsciiArt   ; 先显示ASCII艺术字和标签
    call userInputs        ; 再让用户输入(此时光标已定位)
    call displayInfo       ; 重新整理显示内容(可选,确保格式统一)
    call exitProgram

clearTheScreen:
    mov eax, 4
    mov ebx, 1
    mov ecx, clearScreen
    mov edx, 8            ; 清屏指令长度:27,[2J,27,[H,0 共8字节
    int 0x80
    ret

userInputs:
    ; 姓名输入流程:定位标签→显示标签→定位输入位置→获取输入
    mov eax,4
    mov ebx,1
    mov ecx,cursorNameLabel
    mov edx,8             ; cursorNameLabel长度:27,[8;65H 共8字节
    int 0x80

    mov eax,4
    mov ebx,1
    mov ecx,nameLabel
    mov edx,6             ; Name: 长度为6
    int 0x80

    mov eax,4
    mov ebx,1
    mov ecx,cursorNameInput
    mov edx,8             ; cursorNameInput长度:27,[8;71H 共8字节
    int 0x80

    mov eax,3
    mov ebx,0
    mov ecx,name
    mov edx,19            ; 最多输入19字符,留1字节替换换行符
    int 0x80
    mov byte [name + eax - 1], 0  ; 将输入末尾的换行符替换为0,避免显示换行

    ; 邮箱输入流程:同上
    mov eax,4
    mov ebx,1
    mov ecx,cursorEmailLabel
    mov edx,8             ; cursorEmailLabel长度:27,[12;4H 共8字节
    int 0x80

    mov eax,4
    mov ebx,1
    mov ecx,emailLabel
    mov edx,8             ; Email: 长度为8
    int 0x80

    mov eax,4
    mov ebx,1
    mov ecx,cursorEmailInput
    mov edx,8             ; cursorEmailInput长度:27,[12;12H 共8字节
    int 0x80

    mov eax,3
    mov ebx,0
    mov ecx,email
    mov edx,24            ; 最多输入24字符,留1字节替换换行符
    int 0x80
    mov byte [email + eax - 1], 0  ; 替换换行符为0
    ret

displayAsciiArt:
    mov eax,4
    mov ebx,1
    mov ecx,asciiArt1
    mov edx,298           ; ASCII艺术字实际总长度(计算准确值避免多余输出)
    int 0x80
    ret

displayInput:
    ; 参数栈顺序:cursor_pos, label_addr, input_addr, label_len, input_cursor, input_len
    mov eax,4
    mov ebx,1

    ; 移动光标到标签位置
    mov ecx,[esp+4]
    mov edx,8
    int 0x80

    ; 显示标签
    mov ecx,[esp+8]
    mov edx,[esp+16]
    int 0x80

    ; 移动光标到输入位置
    mov ecx,[esp+20]
    mov edx,8
    int 0x80

    ; 显示输入内容
    mov ecx,[esp+12]
    mov edx,[esp+24]
    int 0x80
    ret

displayInfo:
    ; 显示姓名
    push cursorNameLabel
    push nameLabel
    push name
    push dword 6          ; nameLabel长度
    push cursorNameInput
    push dword 19         ; 最大输入长度
    call displayInput
    add esp,24            ; 清理栈:6个参数×4字节=24

    ; 显示邮箱
    push cursorEmailLabel
    push emailLabel
    push email
    push dword 8          ; emailLabel长度
    push cursorEmailInput
    push dword 24         ; 最大输入长度
    call displayInput
    add esp,24
    ret

exitProgram:
    mov eax,4
    mov ebx,1
    mov ecx,cursorBottom
    mov edx,7
    int 0x80

    mov eax,1
    int 0x80

修改说明

  1. 调整流程顺序:先清屏、显示ASCII艺术字,再定位光标显示标签并接收输入,确保输入时光标在标签旁的正确位置。
  2. 新增输入光标定位:为每个输入字段单独设置光标位置(标签后紧邻的列),保证输入内容紧跟标签。
  3. 修正长度参数:所有字符串、光标序列的长度都使用准确值,避免多余输出导致的格式混乱。
  4. 处理输入换行符:将用户输入末尾的换行符替换为0,防止显示时自动换行错位。
  5. 优化displayInput函数:新增长度参数,支持不同长度的标签和输入,方便后续扩展更多字段。

内容的提问来源于stack exchange,提问作者symphonyyyyyy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:59:52