You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:47:27