我尝试从汇编代码中使用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
有什么问题? 最佳答案
在使用诸如printf之类的stdio函数之后,使用call exit
代替原始的_exit
syscall。
正如Michael解释的那样,可以动态链接C库。这也是"Programming bottom up"书中介绍它的方式(请参见第8章)。
但是,从C库中调用exit
以便结束程序而不是绕过程序很重要,这是我错误地通过调用exit-syscall
所做的。正如Michael所暗示的,exit像冲洗流一样执行很多clean up。
这就是发生的情况:如here所述,C库按以下方式缓冲标准流:
不缓冲标准错误。
如果标准输出/输入是终端,则它是行缓冲的。
如果标准输出/输入不是终端,则它是完全缓冲的,因此在写入结束时需要刷新。
哪种情况适用于何时首次为流调用printf
的情况。
因此,如果直接在终端中调用printf_try
,则可以看到程序的输出,因为hello
在末尾有\n
(这会在行缓冲模式下触发刷新),并且它也是一个终端。 2.案例。
通过printf_try
调用$(./printf_try)
意味着stdout不再是终端(实际上我不知道它是临时文件还是内存文件),因此3.情况有效-需要一个显式刷新,即调用C- exit
。
关于linux - 在汇编中使用printf导致输出为空,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56247270/