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

汇编实现递归DFS函数出现段错误,请求问题定位

排查x86汇编DFS实现的段错误原因

以下是导致段错误的核心问题及修复建议:

1. 递归调用参数传递完全错误

这是最致命的问题:

  • 初始时ebx存储的是expand函数指针,但后续检查邻居是否被访问时,你把ebx重写成了visited的地址:
    ; 错误覆盖了ebx中保存的expand函数指针
    mov ebx, visited
    cmp byte [ebx + edx * 4], 0
    
  • 递归调用dfs时,你push了edx(邻居节点)和ebx(此时是visited地址),但dfs的第二个参数要求是expand函数指针,不是visited。传递错误的指针给dfs,后续调用call ebx时会跳转到非法地址,直接触发段错误。

修复方案:
提前把expand函数指针存到不会被覆盖的位置,比如使用被保护的寄存器esi(你已经push了esi,所以可以安全使用):

; 函数开头,保存expand指针到esi
mov eax, [ebp+8]            ; node
mov esi, [ebp+12]           ; expand函数指针(用esi存储,避免被覆盖)

; 检查邻居是否访问时,改用其他寄存器
mov ecx, visited
cmp byte [ecx + edx * 4], 0

; 递归调用时,传递正确的expand指针
push edx
push esi
call dfs
pop esi
pop edx

2. visited数组存在越界风险

  • visited定义为resd 10000,仅能容纳节点ID范围0~9999。如果expand返回的邻居节点ID超过9999,访问[visited + edx*4]会直接越界访问非法内存,触发段错误。

修复方案:

  • 限制节点ID在0~9999范围内;
  • 或扩大visited数组的大小;
  • 或在访问visited前增加ID范围检查:
    mov edx, [edi + eax*4]
    cmp edx, 10000
    jge dfs_next_neighbour ; ID超出范围,跳过
    

3. 未检查expand函数的返回值有效性

  • 代码直接假设expand返回的neighbours_t*是有效非空指针,但如果expand返回NULL(比如节点无邻居或执行出错),后续访问[esi + neighbours_t.num_neighs]会访问NULL指针,触发段错误。

修复方案:
调用expand后立即检查返回值:

call esi                    ; 调用expand函数(此时esi存的是expand指针)
pop eax                     ; 恢复current node
test eax, eax
jz dfs_end                  ; 如果返回NULL,直接跳过循环

4. 寄存器保存不规范(printf破坏寄存器)

  • printf遵循cdecl调用约定,会破坏eax、ecx、edx寄存器。你调用printf前仅push了edx,但eax和ecx的值会被破坏,虽然当前代码后续重新赋值了这些寄存器,但属于不规范写法,可能引发潜在问题。

修复方案:
调用printf前push所有需要保留的寄存器,或者调用后重新加载所需值:

; 调用printf前,保存eax、ecx、edx
push eax
push ecx
push edx
push eax
push fmt_str
call printf
add esp, 8
; 恢复寄存器
pop edx
pop ecx
pop eax

内容的提问来源于stack exchange,提问作者Alexandra Dinu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:31:01