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

汇编代码实现DFA状态机时出现段错误的解决方法

x86-64汇编DFA段错误修复方案

核心问题分析

原代码触发段错误及逻辑失效的关键原因:

  • 输入缓冲区溢出:.bss段仅为input分配2字节,输入较长字符串时会越界写入非法内存区域,触发段错误。
  • 字符验证逻辑完全错误:ASCII转二进制后,未正确判断输入是否为0/1,反而用两条cmov指令无条件将%ebx设为%edx,导致状态完全混乱,甚至可能让跳转表索引超出0-3的合法范围,跳转到非法地址。
  • DFA状态转移缺失:当前代码的状态跳转后仅设置%edx,未根据输入的0/1执行正确的状态转移,完全违背DFA核心逻辑。
  • 未处理EOF情况:getchar返回EOF(值为-1)时,未做判断会被当成字符处理,引发后续错误。

修复后的代码

保留跳转表、getchar@PLT/puts@PLT核心结构,修复所有问题:

.section .data
input_prompt:
.asciz "Enter a string of 0s and 1s: "
invalid_message:
.asciz "ERROR: invalid input\n"
EEPrompt:
.asciz "Input accepted\n"
NotEEPrompt:
.asciz "Input rejected\n"
.section .bss
.lcomm input, 256  # 分配256字节缓冲区,避免溢出
.section .text
.globl main

main:
# 打印输入提示
lea input_prompt, %rdi
call puts@PLT

movl $0, %ebx            # 初始状态:EE(0个0,0个1)
lea input, %rsi          # 指向输入缓冲区起始
movl $0, %edx            # 临时变量,用于状态转移

read_loop:
call getchar@PLT

# 处理EOF(用户按Ctrl+D)
cmpl $-1, %eax
je input_finalize

# 处理换行,结束输入
cmpb $0x0A, %al
je input_finalize

# ASCII转二进制:'0'->0,'1'->1
sub $0x30, %al

# 验证输入是否为0或1
cmpb $0, %al
jl invalid_input         # 小于0,非法字符
cmpb $1, %al
jg invalid_input         # 大于1,非法字符

# 保存输入到缓冲区(检查是否溢出)
cmpq %rsi, input+255     # 缓冲区剩余空间判断
je invalid_input         # 缓冲区满,视为非法
movb %al, (%rsi)
inc %rsi

# 根据当前状态和输入,计算下一个状态
# 状态编码:0=EE, 1=OE, 2=OO, 3=EO
# 输入0:状态 ^ 1;输入1:状态 ^ 2
movl %ebx, %edx
cmpb $0, %al
je input_zero
xorl $2, %edx            # 输入1,状态异或2
jmp update_state
input_zero:
xorl $1, %edx            # 输入0,状态异或1
update_state:
movl %edx, %ebx

# 通过跳转表进入对应状态处理
jmp *jump_table(,%rbx,8)

jump_table:
.quad ee_state
.quad oe_state
.quad oo_state
.quad eo_state

# 各状态仅需回到读循环,状态已在update_state中更新
ee_state:
jmp read_loop
oe_state:
jmp read_loop
oo_state:
jmp read_loop
eo_state:
jmp read_loop

invalid_input:
lea invalid_message, %rdi
call puts@PLT
jmp exit_with_code

accepted_input:
lea EEPrompt, %rdi
call puts@PLT
jmp exit_with_code

rejected_input:
lea NotEEPrompt, %rdi
call puts@PLT
jmp exit_with_code

input_finalize:
# 检查最终状态是否为EE(0)
cmpl $0, %ebx
je accepted_input
jmp rejected_input

exit_with_code:
# 根据退出类型设置状态码:成功0,失败1
movq $60, %rax
cmpq $accepted_input, %rsp+8  # 简单判断是否从accepted_input跳转
je exit_success
movl $1, %rdi
syscall
exit_success:
xor %rdi, %rdi
syscall

关键修复点说明

  • 扩大输入缓冲区:用.lcomm input, 256分配256字节缓冲区,同时新增缓冲区溢出检查,避免越界写入。
  • 修复字符验证:新增cmpb判断输入转二进制后是否为0或1,非法字符直接跳转到错误处理。
  • 实现正确DFA状态转移:根据输入的0/1,通过异或操作更新状态(0翻转0的计数奇偶,1翻转1的计数奇偶),确保状态符合EE/OE/OO/EO的定义。
  • 处理EOF情况:新增对getchar返回-1的判断,避免EOF被当成有效字符处理。
  • 简化状态处理逻辑:跳转表的各状态标签仅需回到读循环,状态已在转移时更新,无需重复设置%edx。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:53:12