我目前正在终端中开发一个简单的“关于我”部分。我正在使用 NASM 程序集并在 Oracle VM 中运行 Ubuntu。我目前在打印用户输入和标签时遇到问题。
所需的输出应该是 label:userinput 但发生的只是 ascii-art 和标签遵循正确的光标位置,但用户输入要么分散,要么不在标签旁边。
这是迄今为止我的汇编代码:
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
输出如下所示: 终端
我之前的代码较长,我决定将其缩短,以便于阅读。
我还有更多内容要打印,我首先使用 2 个用户输入进行测试。
我只需要 ascii-art、标签和用户输入即可相应打印。
cursorNameLabel db 27, '[8;65H' nameLabel db 'Name: ', 0 cursorEmailLabel db 27, '[12;4H' emailLabel db 'Email: ', 0
您的程序中这些消息的长度似乎有很多混乱!例如。对于打印 nameLabel,您使用 6(省略终止零),但对于打印 emailLabel,您使用 8(包括终止零)。无论如何,sys_write 都需要一个长度,所以最好不要提及终止零。
第一个错误是因为在 displayInput 中您使用了 32
作为cursorNameLabel 和 nameLabel 的长度,不可避免地,您将打印比您预期更多的内容,并带来灾难性的结果。 但是还有一个
第二个错误。您不尊重参数放置在堆栈上的顺序!
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
根据这些说明,displayInput将在[esp+12]
找到cursorNameLabel
,在
[esp+8]
找到nameLabel,在
[esp+4]
找到name。甚至出现
第三个错误,因为虽然系统调用将保留 EBX,但您不应该相信 EAX 保留了其值!因此每次都用 4
重新加载 EAX。事实上,除了包含结果(错误代码或其他)的 EAX 之外,所有通用寄存器都被保留。请参阅https://en.wikibooks.org/wiki/X86_Assembly/Interface_with_Linux。
displayInput 两次?因此,为“name”提供一个 25 字节的缓冲区,就像“email”一样,并在“name:”前面添加一个空格字符,这样它就变得与“email:”一样长。这也更好看...
displayInput:
mov ebx, 1 ; file descriptor (stdout)
mov ecx, [esp + 12] ; Load cursor position from stack
mov edx, 7 ; Use identical lengths
mov eax, 4 ; sys_write
int 0x80
mov ecx, [esp + 8] ; Load the label address
mov edx, 7 ; Use identical lengths
mov eax, 4 ; sys_write
int 0x80
mov ecx, [esp + 4] ; Load the input address
mov edx, 25 ; Use identical lengths
mov eax, 4 ; sys_write
int 0x80
ret
cursorNameLabel db 27, '[8;65H'
nameLabel db ' Name: '
cursorEmailLabel db 27, '[12;4H'
emailLabel db 'Email: '
...
name resb 25
email resb 25
...
push cursorNameLabel ; Push cursor position for name
push name ; Push name address
call displayInput ; Call displayInput
add esp, 8 ; Clean up stack
push cursorEmailLabel ; Push cursor position for email
push Email ; Push email address
call displayInput ; Call displayInput
add esp, 8 ; Clean up stack
...
displayInput:
mov ebx, 1 ; file descriptor (stdout)
mov ecx, [esp + 8] ; Load cursor position AND label (from .DATA)
mov edx, 7+7 ; Use identical lengths
mov eax, 4 ; sys_write
int 0x80
mov ecx, [esp + 4] ; Load input address (from .BSS)
mov edx, 25 ; Use identical lengths
mov eax, 4 ; sys_write
int 0x80
ret