gpt4 book ai didi

linux - 在汇编中使用 printf 会导致管道输出为空,但在终端上有效

转载 作者:太空狗 更新时间:2023-10-29 11:36:02 25 4
gpt4 key购买 nike

我尝试在我的汇编代码中使用 printf,这是一个最小的例子,应该只打印 hello 到标准输出:

.section  .rodata
hello:
.ascii "hello\n\0"
.section .text
.globl _start
_start:
movq $hello, %rdi # first parameter
xorl %eax, %eax # 0 - number of used vector registers
call printf
#exit
movq $60, %rax
movq $0, %rdi
syscall

我构建它

gcc -nostdlib try_printf.s -o try_printf -lc

当我运行它时,它似乎工作了:打印出字符串 hello 并且退出状态为 0:

XXX$ ./try_printf
hello
XXX$ echo $?
0
XXX$

但是当我 try catch 文本时,很明显,有些地方工作不正常:

XXX$ output=$(./try_printf) 
XXX$ echo $output

XXX$

变量 output 应该有值 hello,但是它是空的。

我对 printf 的使用有什么问题?

最佳答案

在使用像 printf 这样的 stdio 函数后,使用 call exit 而不是原始的 _exit 系统调用。 这会刷新 stdio 缓冲区(write 系统调用),然后再进行 exit_group 系统调用)。

(或者,如果您的程序定义了 main 而不是 _start,则从 main 返回等同于调用 exit。您不能从 _startret。)调用 fflush(NULL) 也应该有效。


正如 Michael 所解释的,可以动态链接 C 库。这也是它在 "Programming bottom up" 中的介绍方式。书(见第 8 章)。

然而,重要的是从 C 库调用 exit 以结束程序而不是绕过它,这是我错误地调用 exit-syscall。正如 Michael 所暗示的那样, exit 做了很多 clean up就像冲洗溪流一样。

事情就是这样:正如所解释的here ,C 库按如下方式缓冲标准流:

  1. 没有标准错误缓冲。
  2. 如果标准输出/输入是终端,则它是行缓冲的。
  3. 如果标准输出/输入不是终端,则它是完全缓冲的,因此在原始退出系统调用之前需要刷新。

printf 第一次为流调用时决定适用哪种情况。

所以如果在终端直接调用printf_try,可以看到程序的输出,因为hello结尾有\n (在行缓冲模式下触发刷新)并且它是一个终端,也是 2. 的情况。

通过$(./printf_try) 调用printf_try 意味着标准输出不再是一个终端(实际上我不知道它是一个临时文件还是一个内存文件),因此情况 3. 有效 - 需要显式刷新,即调用 C-exit

关于linux - 在汇编中使用 printf 会导致管道输出为空,但在终端上有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38379553/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com