一尘不染

在汇编中使用printf会导致输出空

linux

我尝试printf从我的汇编代码中使用,这是一个最小示例,应仅打印hello到stdout:

.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$

但是当我尝试捕获文本时,很明显,某些功能无法正常工作:

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

XXX$

该变量output应具有值hello,但为空。

我的用法有printf什么问题?


阅读 436

收藏
2020-06-02

共1个答案

一尘不染

使用 诸如printf之类的stdio函数后,请使用call exit而不是原始_exitsyscall。


正如Michael解释的那样,可以动态链接C库。这也是《自下而上编程》一书中介绍的方式(请参见第8章)。

但是,重要的是exit从C库调用以结束程序而不是绕过程序,这是我错误地通过调用来完成的exit- syscall。正如Michael所暗示的,exit会像冲洗流一样进行大量清理

这是发生了什么事:作为解释这里的C-库缓冲区的如下标准流:

  1. 没有缓冲用于标准错误。
  2. 如果标准输出/输入是终端,则它是行缓冲的。
  3. 如果标准输出/输入不是终端,则它是完全缓冲的,因此在写入结束时需要刷新。

确定哪种情况适用于何时printf首次为流调用。

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

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

2020-06-02