C 在汇编循环中调用_printf,只输出一次

C 在汇编循环中调用_printf,只输出一次,c,gcc,assembly,x86,C,Gcc,Assembly,X86,我正在学习组装,我有一个非常基本的循环 segment .data msg: db '%d',10,0 segment .text global _asm_main extern _printf _asm_main: push DWORD 5 ; Should loop 5 times call dump_stack add esp,4 ret dump_stack: push ebp mov ebp, esp

我正在学习组装,我有一个非常基本的循环

segment .data
    msg: db '%d',10,0

segment .text

    global  _asm_main
    extern _printf

_asm_main:

    push DWORD 5 ; Should loop 5 times
    call dump_stack
    add esp,4

    ret

dump_stack:
    push ebp
    mov ebp, esp

    mov ecx, 0

loop_start:
    cmp ecx,[ebp+8] ;compare to the first param of dump_stack, (5)
    jnle loop_end

    push ecx ;push the value of my loop onto the stack
    push DWORD msg ;push the msg (%d) should just print the value of my loop
    call _printf
    add esp, 8 ;clear the stack

    inc ecx ;increment ecx
    jmp loop_start ; go back to my loop start

loop_end:

    mov esp, ebp
    pop ebp
    ret
我的输出看起来像这样

program.exe
0

只有0,然后换行。我试图通过将printf移动到循环的末尾部分来验证循环是否正在执行,结果显示ecx为6,这是正确的。所以循环正在执行,但printf不是。。。我做错了什么

(此外,该函数被称为dump stack,因为它最初应该转储堆栈的详细信息,但由于这里相同的原因,该函数没有工作)

我正在使用nasm-fwin32 program.asm-o program.o进行编译 然后我有一个包含windows.h的cpp文件,我用gcc-c include编译了它 最后我将它们与gcc-o程序.o include.o链接起来
我运行program.exe

我猜
printf()
修改
ecx
,它变成>=
[ebp+8]
,循环体只执行一次。如果是这种情况,您需要仔细阅读编译器中使用的调用约定,并手动保留和恢复所谓的易失性寄存器(被调用函数可以在不恢复的情况下自由修改这些寄存器)。请注意,可能有几种不同的调用约定。使用调试器

为什么不在调试器中单步执行代码,看看到底发生了什么?我将prinf放在循环之外进行检查,循环后的ecx是6。这意味着它运行了6次。如果你不在循环中调用
printf()
,没有人在循环中修改
ecx
,只有你的
inc-ecx
,对吗?这个测试本身并不能测试
printf()
是否修改
ecx
。没错,在包含printf的循环之后,ecx是1988740641。我想睡眠不足使我不能正确思考。好的,我应该能找到另一个选择。感谢您必须使用堆栈保存和还原ecx<代码>推ecx和
在正确的位置弹出ecx
不会有任何伤害。对于每个循环迭代,推/弹出
ecx
可能不是最好的主意。如果滥用,这种事情将导致不必要的性能损失。相反,您应该注意函数的调用约定
printf
使用
cdecl
允许变量参数列表。与
stdcall
类似,此调用约定要求
eax
ecx
edx
可被破坏。因此,您应该使用另一个寄存器作为计数器(例如
ebx
)。