【问题标题】:Printf without newline in assembly汇编中没有换行符的Printf
【发布时间】:2012-01-20 03:17:07
【问题描述】:

我最近阅读了这篇关于在汇编中使用 printf 和 scanf 的文章:

Meaning of intfmt: db "%d", 10, 0 in assembly

特别是它说 “在 printf 中,换行符打印一个换行符,然后(如果输出处于行缓冲模式,它可能是)刷新内部输出缓冲区,这样你就可以实际看到结果。所以当你删除 10 时,没有刷新而且你看不到输出。”

但是,如果我不想在我的汇编文件中的输出后出现换行符,我不知道该怎么做。 这是我编写的一个简单的测试文件,用于尝试在没有换行符的情况下打印:

extern printf


LINUX        equ     80H      ; interupt number for entering Linux kernel
EXIT         equ     60       ; Linux system call 1 i.e. exit ()




section .data
    int_output_format: db "%ld", 0


segment .text
    global  main


main:
    mov r8, 10
    push rdi
    push rsi
    push r10
    push r9
    mov rsi, r8
    mov rdi, int_output_format
    xor rax, rax
    call printf
    pop r9
    pop r10
    pop rsi
    pop rdi
    call os_return      ; return to operating system


os_return:
    mov  rax, EXIT      ; Linux system call 1 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    syscall     ; Interrupt Linux kernel 64-bit

但正如我读过的文章所暗示的那样,标准输出没有被刷新。我在想也许我需要在输出数字后以某种方式刷新?但我真的不确定。

我正在使用 NASM 汇编语言。

提前致谢!

【问题讨论】:

    标签: c assembly newline printf nasm


    【解决方案1】:

    调用fflush(stdout); 以显示当前位于缓冲区中的内容。

    【讨论】:

    • 我认为这是c语法?我正在寻找如何在汇编中调用它。
    • 根据 C 标准,stdout 是一个扩展为 FILE* 类型表达式的宏。我不知道它是如何在你的编译器中定义的。您需要从stdio.h 中提取值。
    • 你可以调用fflush(NULL),这在汇编代码中更容易,也许xor %eax, %eax; call fflush
    • @BasileStarynkevitch:你是对的!我完全忘记了这种特殊行为。
    • @BasileStarynkevitch 正确。我建议将此作为单独的答案编写,以便莎拉将其标记为她需要的答案!
    【解决方案2】:

    对于 Windows 32 位模式 (FASM):

    push [_iob]
    call [fflush]   ; call into DLL.  Callee-pops calling convention
    

    GNU/Linux 32 位模式 (NASM)

    extern fflush
    extern stdout
    ...
    push dword [stdout]
    call fflush            ; linker takes care of PLT stub for dynamic linking (in a non-PIE executable)
    add  esp, 4            ; caller-pops calling convention
    etc...
    

    【讨论】:

    • 您将如何在 NASM 中完成此任务?是一样的吗?
    • 我假设 FASM 代码适用于 Windows? Linux glibc 没有定义它,调用约定看起来像 Windowsy。 FASM 在 Linux 上运行良好。
    【解决方案3】:

    fflush() 在行或全缓冲 stdio 流中刷新缓冲输出:

    extern fflush
    ...
    xor  edi, edi          ; RDI = 0
    call fflush            ; fflush(NULL) flushes all streams
    ...
    

    或者,mov rdi, [stdout] / call fflush 也可以仅刷新该流。 (使用default rel 进行高效的RIP 相对寻址,您还需要extern stdout。)

    【讨论】:

    • fflush 采用 FILE* arg(在 RDI 中)。您需要将 RDI 归零,而不是 RAX,才能将 NULL 指针传递给它(这意味着刷新所有打开的流),或者您需要 mov rdi, [rel stdout] 来加载该特定全局变量的值。 fflush 不是可变参数,因此它不关心 AL 的值。 (编辑:我会自己解决)
    【解决方案4】:

    另一种可能性是删除stdoutstream 的默认行缓冲。这里是 C 调用来做到这一点。翻译成汇编让作为练习,因为我认为在 ASM 中进行文件/流 I/O 甚至没有意义,成本/收益是非常错误的。

    setvbuf(stdout, NULL, _IONBF, 0);
    

    这样每个printf(和fputsputcputs 等...)都会有一个隐含的fflush

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-19
      • 2014-04-18
      • 2012-07-31
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多