关于终端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 采用指针 + 长度并处理任意二进制字节。您应该只省略终止零,因为您有明确长度的字符串。