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

x86-64汇编实现数组反转打印时退出码24异常排查

问题根因

退出码24对应EMFILE错误,即进程打开的文件描述符超出系统上限,这个错误和你代码里的内存越界写直接相关,核心bug有两个:

  1. 反转函数的内存读写位宽完全错了
    你的数组是用dd定义的32位int数组,每个元素占4字节,但_reverse里交换元素时用了64位寄存器r8、r9做内存操作:
    mov r8, [rdi]
    mov r9, [rsi]
    mov [rdi], r9 
    mov [rsi], r8
    
    64位的mov一次会读写整整8字节,除了你要交换的4字节int,还会越界覆盖元素旁边高4字节的内存。你的数组定义在.data段,后面紧跟着的就是格式字符串、以及C标准库标准IO依赖的stdout流内部结构体。这块内存被你写坏之后,stdout保存的文件描述符被改成了无效值,后续每次调用printf都会尝试新建文件流,没几次就会把进程的文件描述符配额耗光,最后抛24号错误退出。
  2. 调用约定遵守错误
    你以为_printy退出时会还原传入的rdi值,实际上你在两个自定义函数的收尾处都硬编码把rdi改成了全局array的地址,根本没管调用者传入的原始值。另外你也没按x86-64 SysV(macOS用的就是这套调用约定)要求,保存函数内修改过的被调用者保存寄存器,这属于潜在隐患,只是当前代码里还没触发崩溃而已。
    你调试器看到的“无法创建返回地址断点”提示,就是内存被越界写改坏之后,对应内存段的权限、内容不符合预期导致的,不是故障根源。
修复方法

按下面几点改就能正常跑:

  • 把反转函数里的64位交换改成32位操作,用32位子寄存器存取元素,从根源上避免越界:
    mov r8d, [rdi]   ; r8d是r8的低32位,一次只读4字节
    mov r9d, [rsi]
    mov [rdi], r9d 
    mov [rsi], r8d
    
  • 删掉两个函数末尾硬编码lea rdi, [rel array]的逻辑,改成函数入口把传入的rdi入栈保存,退出前出栈恢复,不要硬写死全局地址。
  • 补全寄存器保存逻辑:函数内用到的rbp、rbx、r12~r15这类被调用者保存寄存器,全部在入口入栈,退出前还原,避免破坏C库的运行上下文。
修复后的_reverse参考实现
_reverse:
    push rbp
    mov rbp, rsp
    push rdi  ; 保存传入的数组起始地址
    lea rsi, [rdi + 4 * (length - 1) ]
    
.LOOP2:
    cmp rdi, rsi
    jge .DONE2
    
    mov r8d, [rdi]
    mov r9d, [rsi]
    mov [rdi], r9d 
    mov [rsi], r8d   

    add rdi, 4 
    sub rsi, 4 
    jmp .LOOP2

.DONE2:
    xor rax, rax
    pop rdi  ; 还原调用者传入的rdi值
    pop rbp
    ret

_printy函数也按同样逻辑,把收尾处硬改rdi的代码删掉,入口保存rdi、退出时恢复即可。你之前连续两次调用_printy不报错,是因为没有越界写破坏C库的内部结构,等反转函数踩了stdout的内存,后续printf调用必然异常。

内容的提问来源于stack exchange,提问作者great coconut

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:39:20