首页 > 解决方案 > 来自程序集的 Printf 调用不打印到标准输出

问题描述

我正在x86_64 Linux上的NASM中构建和运行代码。

该程序从我的程序中调用GNU libc printf函数。

该程序只需要将一个句子打印到标准输出。

; comment
section .data
fmt: db "Hello %s %c", 0
name: db "Jane Doe", 0

section .text
global _start
extern printf

func:
lea rdi, [fmt]
lea rsi, [name]
mov rcx, 0x0A
xor rax, rax
call printf
ret

_start:
call func
; exit
mov rax, 1
mov rbx, 0
int 80h
ret

这是我编译它的方式:

nasm -f elf64 Program.s -o Program.o -Werror 
ld -m elf_x86_64 Program.o -o Program -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2

当我运行程序时,它会输出到终端Hello Jane Doe。好的,这就是我所期待的。

但是当我将输出重定向如下:

./Program > output.txt

该文件output.txt

-rw-rw-r-- 1 me me    0 output.txt

任何的想法 ?在这种情况下,libc 似乎printf打印到另一个文件描述符中,stdout但也许我错了。

解决方案

用户在评论中找到了解决方案。

交换

; exit
mov rax, 1
mov rbx, 0
int 80h

成功了call exit

标签: assembly

解决方案


如果你想使用你不应该使用的 C 库函数_start,但是很好main。如果您_start从 libc 中窃取,它将无法执行多个设置和清理操作,例如刷新打开的 C 文件。

在这种情况下,这仅在写入文件时可见,因为默认情况下写入 tty 标准输出是行缓冲的,因此它会立即刷新。相反,当重定向到文件时,数据只是被复制到一个临时缓冲区中,当它足够满时被刷新,或者在终止时被刷新 - 但在你的情况下从未调用过 C 运行时清理函数,因此数据实际上永远不会传递给操作系统。

另一种可能性是使用exitlibc 函数退出(extern exit在执行开始和call exit结束时),它应该处理清理,但我不确定如果没有机会首先初始化 libc 中的东西是否需要正常工作在 Linux 上应该是安全的,请参阅@PeterCordes评论并感谢@Kirill_Zaitsev尝试它。


推荐阅读