x86汇编使用printf打印数组元素触发Segmentation Fault问题求助
问题分析与修复
你的代码触发段错误的核心原因是调用printf时破坏了循环计数器ecx的值。在x86 Linux的C调用约定(cdecl)中,printf这类标准库函数会修改ecx、edx等易失性寄存器,而你把循环计数器存在ecx里,调用printf后ecx的原值丢失,导致循环失控,访问超出数组范围的内存,最终触发段错误。
另外你的代码还未实现“逗号分隔”的需求,以下是完整修复方案:
修复后的代码
global main extern printf section .data num_fmt db "%d", 0 comma_fmt db ", %d", 0 array db 2, 4, 3 arrlen equ $ - array section .text main: mov ecx, 0 ; 单独打印第一个元素,避免开头出现逗号 cmp ecx, arrlen je exit movzx ebx, byte [array + ecx] push ebx push num_fmt call printf add esp, 8 inc ecx mainloop: cmp ecx, arrlen je exit ; 调用printf前保存ecx,避免被破坏 push ecx movzx ebx, byte [array + ecx] push ebx push comma_fmt call printf add esp, 8 pop ecx ; 恢复ecx原值 inc ecx jmp mainloop exit: ; 链接libc时用ret退出更规范,符合C程序约定 mov eax, 0 ret
关键修复点
- 保护循环计数器:在调用
printf前将ecx压栈保存,调用完成后弹出恢复;也可以将循环计数器放到esi这类非易失性寄存器(cdecl约定中函数不会修改这类寄存器),无需手动保存。 - 处理逗号分隔:单独打印第一个元素,后续元素使用带逗号的格式串,避免输出开头或结尾出现多余逗号。
- 规范退出方式:链接libc时,用
ret返回main函数比直接调用int 0x80更符合C程序规范,避免潜在资源泄漏。
如果偏好使用非易失性寄存器存储计数器,也可以修改为以下写法:
main: mov esi, 0 ; esi为非易失性寄存器,printf不会修改它 mainloop: cmp esi, arrlen je exit movzx ebx, byte [array + esi] ; 根据是否为第一个元素选择格式串 cmp esi, 0 je print_first push ebx push comma_fmt jmp call_printf print_first: push ebx push num_fmt call_printf: call printf add esp, 8 inc esi jmp mainloop
内容的提问来源于stack exchange,提问作者spyblock
相关产品推荐
相关产品推荐

