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

汇编Hangman游戏异常:下划线打印7次并触发段错误求助

汇编版Hangman游戏:重复打印与段错误问题排查

我正在编写汇编版Hangman(刽子手)游戏,初期需求为:输入一个字符,与目标单词'SPARTA'的首字符比对,匹配则打印该字符,否则打印下划线。但运行程序时,下划线被打印7次,随后触发段错误。7这个数字十分异常,它既不是2的倍数,也不等于目标单词的字符数。附上我的代码,恳请帮忙排查问题所在。另外,我认为这是我目前写得最好的程序之一。

;obešenec hra
SECTION .data
zahadneslovo db 'SPARTA' 
;info db 'pokusy:'
;pokusy db 5 
linefeed db 0xA
podtrzitko db '_' 

SECTION .bss
pismenkoin resb 1
stav resb 1 
misto resb 1                                                                                    

SECTION .text
global _start

 _start:
 ;kod:

 call zeptatsenapismenko
 call zjisteni
 call upravenistavu
 call zobrazeni

;deklerace subrutin:

zeptatsenapismenko: 
mov edx,1
mov ecx,pismenkoin
mov ebx,0
mov eax,3
int 80h
ret


zjisteni: ;subrutina
mov eax,pismenkoin
mov ecx,0
porovnat:cmp eax,[zahadneslovo+ecx]
jz ulozitpismenkoktereserovna
zpet:
cmp ecx, 5
jz konecc
inc ecx
jnz porovnat
dal:
ret
ulozitpismenkoktereserovna:
;mov edi,[zahadneslovo+ecx] 
mov [misto],ecx 
jmp zpet


upravenistavu: 
mov ebx,6
sub ebx,[misto]
mov edx,2
mov ecx,0
ebxkratnasobitdvojkou:
mul edx 
inc ecx
cmp ecx,ebx
jz hihi
jnz ebxkratnasobitdvojkou
hihi:
;add al,[misto] 
mov [stav],al
ret



zobrazeni: 
mov eax,0
testy:
bt [stav],eax  
jnc podtrzitkoaznovu
jc vytisknipismenkokterejenatomhleporadiveax
hemh:
cmp eax,6
jz konecc
jnz znovu

znovu:
inc eax
jmp testy

konecc:
ret


podtrzitkoaznovu:
push eax
push ebx
push ecx
push edx
mov edx,1
mov ecx,podtrzitko
mov ebx,1
mov eax,4
int 80h
pop edx
pop ecx
pop ebx
pop eax
jmp hemh

vytisknipismenkokterejenatomhleporadiveax:
push eax
push ebx
push ecx
push edx
mov eax,[misto]
mov edx,1
mov ecx,[zahadneslovo+eax]
mov ebx,1
mov eax,4
int 80h
pop edx
pop ecx
pop ebx
pop eax
jmp hemh

核心错误点分析

  1. 字符比对逻辑错误
    zjisteni子程序中,mov eax,pismenkoin是把输入缓冲区的地址存入eax,而非读取缓冲区里的字符值。正确做法是用mov al, [pismenkoin]读取输入的ASCII字符,后续比对也应该用al而非eax,否则会拿内存地址和字符ASCII码做无效比对,永远无法匹配目标字符。

  2. 标签重名导致流程混乱
    代码中konecc标签在zjisteni和zobrazeni中重复定义,汇编会将其解析为最后出现的实例(即zobrazeni中的konecc)。当zjisteni中循环到ecx=5时,会直接跳转到zobrazeni的ret指令返回,导致upravenistavu和zobrazeni可能被跳过,或者后续逻辑使用未初始化的垃圾值。需给不同子程序的终止标签重命名,比如zjisteni_konec。

  3. upravenistavu初始化缺失
    进入该子程序时,eax未被初始化就执行mul edx,而eax此时残留的是pismenkoin的地址,导致计算出的stav值完全错误。此外stav仅定义1字节,但计算2的N次方时很容易溢出,破坏其他内存区域。应先将eax初始化为1(因为2^0=1),再执行乘法循环。

  4. 循环次数错误(打印7次的原因)
    zobrazeni中循环终止条件是cmp eax,6,eax从0开始计数,会循环0-6共7次。目标单词SPARTA是6个字符,应改为cmp eax,5,循环0-5共6次。

  5. Write系统调用参数错误(段错误的直接原因)
    vytisknipismenkokterejenatomhleporadiveax中,mov ecx,[zahadneslovo+eax]把字符的ASCII值存入ecx,但Linux的Write系统调用(eax=4)要求ecx是字符串的内存地址,而非字符值。这会导致系统尝试访问以该ASCII值为地址的非法内存,直接触发段错误。正确写法是mov ecx, zahadneslovo+eax,传入字符的地址。

  6. 未初始化变量的垃圾值问题
    如果输入字符不在目标单词中,ulozitpismenkoktereserovna不会执行,misto会保留未初始化的垃圾值,后续upravenistavu中的计算会基于错误值,导致整个逻辑混乱。需在程序初始化时将misto设为无效值(比如0xFF),并在后续逻辑中判断是否匹配成功。

关键修正示例

修正后的zjisteni子程序:

zjisteni: ;subrutina
mov al, [pismenkoin]  ; 读取输入字符
mov ecx,0
mov byte [misto], 0xFF  ; 初始化misto为无效值
porovnat:
cmp al,[zahadneslovo+ecx]
jz ulozitpismenkoktereserovna
zpet:
cmp ecx, 5
jz zjisteni_konec  ; 使用专属终止标签
inc ecx
jnz porovnat
zjisteni_konec:
ret
ulozitpismenkoktereserovna:
mov [misto],ecx 
jmp zpet

修正后的upravenistavu子程序:

upravenistavu:
cmp byte [misto], 0xFF  ; 判断是否匹配成功
jz nenalezeno  ; 未匹配则设置stav为0(全下划线)
mov ebx,6
sub ebx,[misto]
mov eax,1  ; 初始化eax为1(2^0)
mov edx,2
mov ecx,0
ebxkratnasobitdvojkou:
mul edx 
inc ecx
cmp ecx,ebx
jz hihi
jnz ebxkratnasobitdvojkou
hihi:
mov [stav],al
ret
nenalezeno:
mov byte [stav],0
ret

修正后的vytisknipismenkokterejenatomhleporadiveax子程序:

vytisknipismenkokterejenatomhleporadiveax:
push eax
push ebx
push ecx
push edx
mov ecx, zahadneslovo  ; 基地址
add ecx, eax  ; 加上偏移量,得到当前字符的地址
mov edx,1
mov ebx,1
mov eax,4
int 80h
pop edx
pop ecx
pop ebx
pop eax
jmp hemh

内容的提问来源于stack exchange,提问作者IlikeAssemblyButIsuck-sorry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:37:07