关于终端read系统调用时光标移动的问题
Question about cursor movement during read system calls on the terminal
我是 Assembly 的新手,我正在学习在 google / youtube (Mostly this) 上找到的一些教程。
我正在尝试自己飞行并编写自己的小程序,但显然,在遵循教程时它不会像它那样进行;)
我试图理解为什么我没有得到我期望的输出,而且我如何调试以理解 where/what 我的错误 is/are.
我正在使用:
-yasm 1.3.0
- Ubuntu 18.04.3 LTS(仿生海狸)
我正在使用以下选项进行编译:
yasm -Worphon-labels -g dwarf2 -f elf64 <my_file.asm> -l my_file.lst
ld -g -o my_file my_file.o
这是我的代码:
section .data
msgOne db "Number One ? ", 0x0
msgOne_len equ $-msgOne
msgTwo db "Number Two ? ", 0x0
msgTwo_len equ $-msgTwo
section .bss
numOne resb 8
numTwo resb 8
section .text
global _start
_start
mov rax, 1
mov rdi, 1
mov rsi, msgOne
mov rdx, msgOne_len
syscall
mov rax, 0
mov rdi, 0
mov rsi, numOne
mov rdx, 8
syscall
mov rax, 1
mov rdi, 1
mov rsi, msgTwo
mov rdx, msgTwo_len
syscall
mov rax, 0
mov rdi, 0
mov rsi, numTwo
mov rdx, 8
syscall
mov rax, 60
mov rdi, 0
syscall
我期待以下输出:
Number One ? <waiting for input> ; when provided, next line
Number Two ? <waiting for input> ; when provided, next line
<program exit>
但我得到以下信息:
Number One ? <waiting for input> ; say we type in 1
Number Two ? 1
_cursor is now here_ ; say we type in 1
<program exit>
有几件事让我感到困惑:
- 如果我没有在两个字符串显示之间提供 0xA,为什么会有新行?
- 为什么第二个提示出现'1',为什么光标在第三行?
- 我如何调试我的 exec 以弄清楚发生了什么?
我尝试使用 edb GUI。我知道如何设置断点/进入,但我不知道我在寻找什么以及在哪里寻找?
我也尝试了经典的 gdb,但除了 "run, next, next, next ... program completed".
之外,我不知道如何获取一些调试信息
(如果您想知道,我纯粹是出于好奇学习汇编!下一个管道是 C :D)
当你 运行 这个程序的输入连接到终端(而不是从文件或其他东西重定向)时,终端仍然处于 "echo" 模式,由内核提供行编辑.所以用户输入的换行符会影响光标。
当我运行它时,在我的终端输入1 输入两次后的最终结果是:
peter@volta:/tmp$ ./foo
Number One ? 1
Number Two ? 2
peter@volta:/tmp$
如果我使用 control-D 来 "submit" 文本(这样阅读会 return)而不输入换行符,输出看起来像这样:
peter@volta:/tmp$ ./foo
Number One ? 1Number Two ? 1peter@volta:/tmp$
要了解有关此内容的更多信息,google POSIX TTY 和终端输入。
调试中:
对于 GDB,使用 layout reg
在单步执行时显示寄存器。您也可以 运行 strace ./my_program
来跟踪系统调用。请参阅 https://whosebug.com/tags/x86/info 底部的调试提示。
Strace 输出,使用 -o
记录到一个文件中,因此它不会与实际的终端输出混合:
peter@volta:/tmp$ strace -o foo.tr ./foo
Number One ? 1
Number Two ? 1
peter@volta:/tmp$ cat foo.tr
execve("./foo", ["./foo"], 0x7fffbac22f80 /* 54 vars */) = 0
write(1, "Number One ? [=12=]", 14) = 14
read(0, "1\n", 8) = 2
write(1, "Number Two ? [=12=]", 14) = 14
read(0, "1\n", 8) = 2
exit(0) = ?
+++ exited with 0 +++
请注意,您的提示包含一个 0
字节。在终端中,它打印为零宽度,但这仍然是一个坏主意。 write
采用指针 + 长度并处理任意二进制字节。您应该只省略终止零,因为您有明确长度的字符串。
我是 Assembly 的新手,我正在学习在 google / youtube (Mostly this) 上找到的一些教程。
我正在尝试自己飞行并编写自己的小程序,但显然,在遵循教程时它不会像它那样进行;)
我试图理解为什么我没有得到我期望的输出,而且我如何调试以理解 where/what 我的错误 is/are.
我正在使用: -yasm 1.3.0 - Ubuntu 18.04.3 LTS(仿生海狸)
我正在使用以下选项进行编译:
yasm -Worphon-labels -g dwarf2 -f elf64 <my_file.asm> -l my_file.lst
ld -g -o my_file my_file.o
这是我的代码:
section .data
msgOne db "Number One ? ", 0x0
msgOne_len equ $-msgOne
msgTwo db "Number Two ? ", 0x0
msgTwo_len equ $-msgTwo
section .bss
numOne resb 8
numTwo resb 8
section .text
global _start
_start
mov rax, 1
mov rdi, 1
mov rsi, msgOne
mov rdx, msgOne_len
syscall
mov rax, 0
mov rdi, 0
mov rsi, numOne
mov rdx, 8
syscall
mov rax, 1
mov rdi, 1
mov rsi, msgTwo
mov rdx, msgTwo_len
syscall
mov rax, 0
mov rdi, 0
mov rsi, numTwo
mov rdx, 8
syscall
mov rax, 60
mov rdi, 0
syscall
我期待以下输出:
Number One ? <waiting for input> ; when provided, next line
Number Two ? <waiting for input> ; when provided, next line
<program exit>
但我得到以下信息:
Number One ? <waiting for input> ; say we type in 1
Number Two ? 1
_cursor is now here_ ; say we type in 1
<program exit>
有几件事让我感到困惑:
- 如果我没有在两个字符串显示之间提供 0xA,为什么会有新行?
- 为什么第二个提示出现'1',为什么光标在第三行?
- 我如何调试我的 exec 以弄清楚发生了什么?
我尝试使用 edb GUI。我知道如何设置断点/进入,但我不知道我在寻找什么以及在哪里寻找?
我也尝试了经典的 gdb,但除了 "run, next, next, next ... program completed".
(如果您想知道,我纯粹是出于好奇学习汇编!下一个管道是 C :D)
当你 运行 这个程序的输入连接到终端(而不是从文件或其他东西重定向)时,终端仍然处于 "echo" 模式,由内核提供行编辑.所以用户输入的换行符会影响光标。
当我运行它时,在我的终端输入1 输入两次后的最终结果是:
peter@volta:/tmp$ ./foo
Number One ? 1
Number Two ? 2
peter@volta:/tmp$
如果我使用 control-D 来 "submit" 文本(这样阅读会 return)而不输入换行符,输出看起来像这样:
peter@volta:/tmp$ ./foo
Number One ? 1Number Two ? 1peter@volta:/tmp$
要了解有关此内容的更多信息,google POSIX TTY 和终端输入。
调试中:
对于 GDB,使用 layout reg
在单步执行时显示寄存器。您也可以 运行 strace ./my_program
来跟踪系统调用。请参阅 https://whosebug.com/tags/x86/info 底部的调试提示。
Strace 输出,使用 -o
记录到一个文件中,因此它不会与实际的终端输出混合:
peter@volta:/tmp$ strace -o foo.tr ./foo
Number One ? 1
Number Two ? 1
peter@volta:/tmp$ cat foo.tr
execve("./foo", ["./foo"], 0x7fffbac22f80 /* 54 vars */) = 0
write(1, "Number One ? [=12=]", 14) = 14
read(0, "1\n", 8) = 2
write(1, "Number Two ? [=12=]", 14) = 14
read(0, "1\n", 8) = 2
exit(0) = ?
+++ exited with 0 +++
请注意,您的提示包含一个 0
字节。在终端中,它打印为零宽度,但这仍然是一个坏主意。 write
采用指针 + 长度并处理任意二进制字节。您应该只省略终止零,因为您有明确长度的字符串。