多次调用printf仅首次生效:汇编代码执行异常排查
问题分析与解决
核心原因
你遇到的问题主要来自两个关键层面:
1. printf的输出缓冲机制
默认情况下,stdout(终端输出)采用行缓冲模式:只有当输出包含换行符\n、缓冲区被填满,或者程序显式调用fflush刷新时,缓冲区内容才会显示到终端。如果你的output格式字符串没有换行符,每次printf的输出都会被暂存到缓冲区中,直到程序退出时才一次性刷新。这会让你误以为只打印了一次,实际是多次输出被合并显示。
2. 调用约定导致%r8寄存器被破坏
在x86-64 System V调用约定中,%r8属于调用者保存寄存器——也就是说,printf等C库函数在执行过程中有权修改这个寄存器的值。第一次调用printf后,%r8的原始值已经被覆盖,后续循环里movq %r8, %rsi传递的是被修改后的无效值,自然无法正确打印原始内容。
解决方法
针对输出缓冲问题
- 修改
output格式字符串,在末尾添加换行符。例如,如果原格式是打印长整数,改为:
这样每次const char output[] = "%ld\n";printf都会触发缓冲区自动刷新,输出会立即显示。 - 或者在每次调用
printf后手动刷新缓冲区:call printf movq $stdout, %rdi ; 将stdout的地址传入rdi call fflush ; 调用fflush刷新输出缓冲区
针对寄存器被破坏问题
将%r8的原始值保存到被调用者保存寄存器(如%r12-%r15,这类寄存器会被C库函数保留原值),循环中从保存的寄存器加载值到%rsi:
; 进入循环前先保存%r8的值到%r12 movq %r8, %r12 printing: decq %r13 movq $0, %rax movq %r12, %rsi ; 从保存的寄存器加载值 movq $output, %rdi call printf cmpq $0, %r13 jg printing
内容的提问来源于stack exchange,提问作者hellwraiz
相关产品推荐
相关产品推荐

