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

16位实模式汇编CMPS指令始终返回0致误触发关机问题求助

问题描述

我正在用16位汇编开发一个小型操作系统,目前实现了简易终端功能:获取用户输入,若输入为“shutdown”则执行关机函数,否则循环等待下一次输入(后续会扩展其他指令判断)。编译无错误,但在QEMU中运行时,无论输入什么内容都会触发关机,排查后发现CMPS指令始终返回0。


主程序代码

bits 16

section .kernel
global _start_kernel

_start_kernel:
    mov ax, 0x3
    int 10h

    commandLoop:
        mov si, user
        call print

        mov di, input_string
        call input

        mov si, input_string
        call print

        ifCommandShutdown:
            cld
            mov si, C_shutdown
            mov di, input_string
            mov cx, CL_shutdown
            cmpsb
            jz thenCommandShutdown

        elseCommandShutdown:
            call newLine
            jmp commandLoop

        thenCommandShutdown:
            call shutdown

    exit:
        cli
        hlt

%include "lib/console.asm"
%include "lib/system.asm"

user: db "user >> ", 0
input_string:

;- Commands Variables ------------------------------+
;                                                   |
C_shutdown:  db "shutdown", 0 ;                     |
C_reboot:    db "reboot"  , 0 ;                     |
;                                                   |
CL_shutdown: db $ - C_shutdown ;                    |
CL_reboot:   db $ - C_reboot   ;                    |
;                                                   |
;---------------------------------------------------+

times 512-($-$$) db 0

console.asm代码

print:
    mov ah, 0x0e
    characterLoop:
        lodsb
        or al, al
        jz break
        int 10h

    jmp characterLoop

    break:
        ret

input:
    mov ah, 0x0
    int 16h

    ifKeyIsEnter:
        cmp al, 0x0D
        jz enterIsPressed
    elseEnterKey:
        stosb
        mov ah, 0x0e
        int 10h
    jmp input

    enterIsPressed:
        mov al, 0x0
        stosb
        call newLine
        ret

newLine:
    mov ah, 0x0e
    mov al, 13
    int 10h

    mov al, 10
    int 10h

    ret

system.asm代码

shutdown:
    mov ax, 0x1000
    mov ax, ss
    mov sp, 0xf000
    mov ax, 0x5307
    mov bx, 0x0001
    mov cx, 0x0003
    int 0x15

问题分析与修复
  • 命令长度类型错误:CL_shutdown用db定义为字节,但mov cx, CL_shutdown会将16位寄存器CX的高8位填充垃圾值,导致比较长度完全错误。需改为dw(字类型):

    CL_shutdown: dw $ - C_shutdown ;
    CL_reboot:   dw $ - C_reboot   ;
    
  • 单次比较逻辑错误:cmpsb默认仅比较一个字节,需配合repe前缀实现全字符串匹配,只有当所有字节都相等时才触发跳转:

    ifCommandShutdown:
        cld
        mov si, C_shutdown
        mov di, input_string
        mov cx, CL_shutdown
        repe cmpsb           ; 重复比较直到CX为0或字节不相等
        jz thenCommandShutdown  ; 全匹配时跳转执行关机
    
  • 输入缓冲区未分配:input_string仅为标签,无预留空间,输入内容可能覆盖后续命令字符串。需分配足够缓冲区:

    input_string: times 64 db 0  ; 64字节输入缓冲区
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:47:07