如何在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
问题根源
- 流程顺序错误:先执行输入再显示ASCII艺术字和标签,导致用户输入时光标在终端默认位置,而非标签旁的指定位置。
- displayInput函数参数错误:
- 光标定位序列的长度错误(
cursorNameLabel实际长度为8,不是32) - 标签长度硬编码为32,实际
Name:长度为6,Email:长度为8 - 输入缓冲区长度固定为20,会包含用户输入时按下的换行符,导致显示换行错位
- 光标定位序列的长度错误(
- 输入时未定位光标:用户输入前未将光标移动到标签后的指定位置,输入内容直接输出在当前光标处。
修改后的代码
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
修改说明
- 调整流程顺序:先清屏、显示ASCII艺术字,再定位光标显示标签并接收输入,确保输入时光标在标签旁的正确位置。
- 新增输入光标定位:为每个输入字段单独设置光标位置(标签后紧邻的列),保证输入内容紧跟标签。
- 修正长度参数:所有字符串、光标序列的长度都使用准确值,避免多余输出导致的格式混乱。
- 处理输入换行符:将用户输入末尾的换行符替换为
0,防止显示时自动换行错位。 - 优化displayInput函数:新增长度参数,支持不同长度的标签和输入,方便后续扩展更多字段。
内容的提问来源于stack exchange,提问作者symphonyyyyyy
相关产品推荐
相关产品推荐

