汇编实现递归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
相关产品推荐
相关产品推荐

