我尝试从我的汇编代码中使用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
我用它来构build它
gcc -nostdlib try_printf.s -o try_printf -lc
当我运行它,似乎工作:stringhello
打印出来,退出状态是0
:
XXX$ ./try_printf hello XXX$ echo $? 0 XXX$
但是,当我尝试捕捉文本时,很明显,有些东西不能正常工作:
XXX$ output=$(./try_printf) XXX$ echo $output XXX$
variablesoutput
的值应该是hello
,但是是空的。
我使用printf
什么问题?
正如Michael解释的那样,动态链接C库是可以的。 这也是在“自下而上”的书中介绍的(见第8章)。
然而,为了结束程序而不是绕过它,调用C库的exit
是非常重要的,这就是我通过调用exit-syscall
所做的错误。 正如迈克尔所暗示的那样,出口像清理溪流一样清理了很多。
这就是发生了什么事情:正如这里所解释的,C库缓冲标准流如下:
当第一次调用printf
时,决定使用哪种情况。
所以如果在终端直接调用printf_try
,程序的输出就可以看出来了,因为hello
在结尾处有\n
(在线路缓冲模式下触发刷新),它是一个终端,也是2.情况。
通过$(./printf_try)
调用printf_try
意味着stdout不再是一个终端(实际上我不知道是一个临时文件还是一个内存文件),因此3. case就是有效的 -一个明确的同花顺即呼叫C- exit
。
C标准库通常包含标准I / O流的初始化代码 – 通过定义自己的入口点来绕过初始化代码。 尝试定义main
而不是_start
:
.globl main main: # _start code here.
然后使用gcc try_printf.s -o try_printf
( 即不带-nostdlib
) -nostdlib
。