为什么写系统调用会在 linux x86_64 (nasm) 的末尾打印 `%`? [英] Why do write syscalls print `%` at end on linux x86_64 (nasm)?
问题描述
以下 hello-world 程序在打印字符串的末尾显示一个 %
符号.这是为什么,我该如何删除它?
The following hello-world program displays a %
sign at the end of the printed string. Why is this and how can I remove it?
这是我的程序:
section .data
msg db "hello, world!"
section .text
global _start
_start:
mov rax, 1 ; syscall 1 (write)
mov rdi, 1 ; arg 1 = 1 (stdout)
mov rsi, msg ; arg 2 = msg ("hello, world!")
mov rdx, 13 ; arg 3 = 13 (char count)
syscall ; call write
mov rax, 60 ; syscall 60 (exit)
mov rdi, 0 ; arg 1 = 0 (OK)
syscall ; call exit
这是我运行可执行文件时的输出:hello, world!%
And here is the output when I run the executable: hello, world!%
提前致谢.
这似乎是由 zsh 引起的(无法在 bash 中重现).问题是为什么会发生这种情况以及如何解决.
It seems to be caused by zsh (not reproducible in bash). The question is why this happens and how to fix it.
推荐答案
发生这种情况是因为程序的输出没有以换行符结尾.
This happens because your program's output doesn't end with a newline.
您的程序没有打印%
.您可以通过将其输出通过管道传输到 hexdump -C
或类似内容来验证这一点.
Your program isn't printing the %
. You can verify this by piping its output into hexdump -C
or similar.
你也可以使用strace
来追踪系统调用它的产生,但这不会显示输出,所以不排除内核神奇地添加一个 %
.(但您可以确定内核不会这样做.唯一可能的调整是 write
在没有写入完整缓冲区的情况下提前返回.这仅适用于大缓冲区大小,尤其是写入缓冲区大于管道缓冲区(可能为 64kiB)的管道时.
You can also use strace
to trace what system calls its making, but that doesn't show the output, so it doesn't rule out the kernel magically adding a %
. (But you can be sure the kernel doesn't do that. The only munging that's possible is for write
to return early, without having written the full buffer. This is only likely with large buffer sizes, especially when writing to a pipe with a buffer larger than the pipe-buffer (maybe 64kiB).
这是部分行的 ZSH 功能:为什么 ZSH 以突出显示的百分比符号结束一行?.你没有说它是一个突出显示的 % 符号.准确/完整的描述很重要.
This is a ZSH feature for partial lines: Why ZSH ends a line with a highlighted percent symbol?. You didn't say it was a highlighted % symbol. Accurate / complete descriptions are important.
(此答案的早期版本假设您在 ZSH 中使用 %
作为提示.%
有时用作提示,但在 C-shell 中更常见像 tcsh,而不是 Bourne 派生的 shell,如 bash 和 zsh.)
(An earlier version of this answer assumed you were using %
as your prompt in ZSH. %
is sometimes used as a prompt, but more often in C-shells like tcsh, not Bourne-derived shells like bash and zsh.)
你会从 echo -n "hello, world!"
得到完全一样的东西.例如在 bash 中:
You'd get exactly the same thing from echo -n "hello, world!"
. e.g. in bash:
peter@volta:/tmp$ echo -n 'hello world!'
hello world!peter@volta:/tmp$
在 ZSH 中:
volta:/tmp$ echo -n 'hello world!'
hello world!%
volta:/tmp$ # and the % on the previous line is in inverse-video
Bash 只在前台命令退出后打印 $PS1
(或运行 $PROMPT_COMMAND
),而不管光标位置如何.它无法直接检查程序的输出是否以换行符结尾.我猜 ZSH 使用 VT100 转义码来查询光标位置以检测程序将光标不在行首的情况.
Bash just prints $PS1
(or runs $PROMPT_COMMAND
) after a foreground command exits, regardless of cursor position. It can't directly check that your program's output ended with a newline. I guess ZSH uses VT100 escape codes to query the cursor position to detect cases where programs leave the cursor not at the start of a line.
当你cat
一个不以换行符结尾的文件或任何其他情况时,你也会得到这个.
You also get this when you cat
a file that doesn't end with a newline, or any number of other cases.
要修复它,请在您的消息中包含一个换行符(ASCII 换行符,0xa):
section .rodata
msg: db "hello, world!", 0xa
msglen equ $ - msg ; use mov edx, msglen
msgend: ; or mov edx, msgend - msg
请参阅$ 在 NASM 中究竟是如何工作的?了解更多详情让汇编程序为您计算大小.
See How does $ work in NASM, exactly? for more details on getting the assembler to compute the size for you.
不要在 NASM 中省略数据标签上的 :
;它的风格很好,避免了与指令助记符和汇编指令的名称冲突.
Don't omit the :
on data labels in NASM; it's good style and avoids name conflicts with instruction mnemonics and assembler directives.
NASM(但不是 YASM)在反引号内接受 C 样式的转义符,因此您可以编写代替换行符的数字 ASCII 代码
NASM (but not YASM) accepts C-style esacapes inside backquotes, so instead of the numeric ASCII code for a newline, you could write
msg: db `hello, world!\n`
这篇关于为什么写系统调用会在 linux x86_64 (nasm) 的末尾打印 `%`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!