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

16位x86汇编内核调用输入函数后卡顿问题求助

自研OS字节码解释器输入后卡顿问题排查

问题描述

出于兴趣自研操作系统,参考JVM设计实现了内核级字节码解释语言,添加基础I/O功能后编写了一个询问用户名并输出问候的程序,但输入姓名后代码卡顿,光标无响应,修改相关函数后问题仍存在。

编译与运行环境

  • 编译:使用NASM编译boot.asm和kern.asm,命令:nasm -f bin filename.asm -o filename.bin
  • 生成镜像:用dd命令生成单文件镜像:dd if=filename.bin of=filename.img,再合并为最终镜像:cat boot.img kern.img > main.img
  • 运行:在QEMU中加载main.img运行

相关代码

boot.asm

[org 0x7c00]
[bits 16]

    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax

    ; Set up the stack.
    mov ss, ax
    mov sp, 0x7c00

    mov ah, 0x01
    mov cx, 0x0007
    int 0x10

    mov si, ntgos_bootld_msg
    call out

    mov si, bootld_started_msg
    call out

    mov si, disk_reading_msg
    call out

    ; Read two sectors from the disk.
    mov si, KERN_ADDR
    call disk

    ; Handle disk reading error.
    jc disk_error

    mov si, disk_done_msg
    call out

    mov si, kern_starting_msg
    call out

    ; Jump to kernel.
    jmp KERN_ADDR

    jmp $

disk_error:
    mov si, disk_error_msg
    call out

    jmp $

%include "boot-libs/out.asm"
%include "boot-libs/disk.asm"

ntgos_bootld_msg:
    db "ENTEEG OS BOOTLOADER", 0x0a, 0x0d, 0x00
bootld_started_msg:
    db "    Started.", 0x0a, 0x0d, 0x00
disk_reading_msg:
    db "    Reading and loading disk at address 0x7e00...", 0x0a, 0x0d, 0x00
disk_done_msg:
    db "    Disk reading done successfully.", 0x0a, 0x0d, 0x00
disk_error_msg:
    db "    (!) ERROR! Error reading disk. Cannot continue booting. Please restart the computer.", 0x0a, 0x0d, 0x00
kern_starting_msg:
    db "    Starting kernel...", 0x0a, 0x0d, 0x00

KERN_ADDR equ 0x7e00

times 510-($-$$) db 0x00
dw 0xaa55

boot-libs/out.asm

out:
    pusha
    mov ah, 0x0e

out_loop:
    mov al, [si]
    cmp al, 0x00
    je out_end
    int 0x10

    inc si
    jmp out_loop

out_end:
    popa
    ret

boot-libs/disk.asm

disk:
    pusha
    mov ah, 0x02

disk_loop:
    mov al, 0x02
    mov ch, 0x00
    mov dh, 0x00
    mov cl, 0x02
    mov bx, 0x0000
    mov es, bx
    mov bx, si
    int 0x13

    jnc disk_end

disk_err_:
    popa
    stc
    ret

disk_end:
    popa
    ret

kern.asm

[org 0x7e00]
[bits 16]

    mov si, ntgos_kern_msg
    call out

    mov si, kern_started_msg
    call out

    ; Clear the screen.
    mov ah, 0x00
    mov al, 0x03
    int 0x10

    mov si, code
    call exec

    jmp $

%include "kern-libs/ioutils.asm"
%include "exec.asm"

ntgos_kern_msg:
    db "ENTEEG OS KERNEL", 0x0a, 0x0d, 0x00
kern_started_msg:
    db "    Started.", 0x0a, 0x0d, 0x00

INPUT_ADDR equ 0xd000

code:
    db 0x25, "Type in your name:", 0x0a, 0x0d, 0x00, 0x27, 0x25, "Hi, ", 0x00, 0x26, 0xd0, 0x00, 0x00

times 1024-($-$$) db 0x00

exec.asm

exec:
    mov al, [si]
    cmp al, 0x25 ; Out
    je _0x25
    cmp al, 0x26 ; Outaddr
    je _0x26
    cmp al, 0x27 ; In
    je _0x27
    cmp al, 0x00 ; Exit program
    je _0x00

    jmp exec

_0x25:
    call print_out_prompt
    inc si
    call out
    jmp exec_ret

_0x26:
    call print_out_prompt
    inc si
    call outaddr
    jmp exec_ret

_0x27:
    pusha
    mov si, in_prompt
    call out
    popa
    call in
    jmp exec_ret

_0x00:
    ret


exec_ret:
    inc si
    jmp exec

print_out_prompt:
    pusha
    mov si, out_prompt
    call out
    popa
    ret

in_prompt:
    db "{?} ", 0x00
out_prompt:
    db "{.}     ", 0x00

kern-libs/ioutils.asm

out:
    mov ah, 0x0e

out_loop:
    mov al, [si]
    cmp al, 0x00
    je out_end
    int 0x10
    inc si

    jmp out_loop

out_end:
    ret

outaddr:
    mov ah, 0x0e
    mov bl, [si]
    inc si
    mov bh, [si]

outaddr_loop:
    mov al, [bx]
    cmp al, 0x00
    je outaddr_end
    int 0x10
    inc bx

    jmp outaddr_loop

outaddr_end:
    ret

in:
    mov cx, 0x004c

in_loop:
    mov ah, 0x00
    int 0x16
    mov ah, 0x0e
    int 0x10
    cmp cx, 0x0000
    je in_full_buff
    cmp al, 0x0d
    je in_end
    mov [si], al
    inc si
    dec cx

    jmp in_loop

in_full_buff:
    stc

in_end:
    mov byte [si], 0x00
    mov al, 0x0a
    int 0x10
    ret

问题根源与修复

1. 输入函数in的SI寄存器未初始化

在exec.asm的_0x27分支中,调用in函数前未指定输入数据的存储地址,此时si指向字节码流中的指令位置,输入数据会覆盖字节码,导致后续解释逻辑混乱。

修复:调用in前将si设置为预定义的INPUT_ADDR:

_0x27:
    pusha
    mov si, in_prompt
    call out
    popa
    mov si, INPUT_ADDR  ; 指定输入存储地址
    call in
    jmp exec_ret

2. outaddr函数地址解析字节顺序错误

字节码中0x26指令后的地址是0xd0, 0x00,对应0x00d0,但INPUT_ADDR是0xd000,同时outaddr先读低字节再读高字节,导致地址解析错误。

修复:调整字节码中的地址顺序为0x00, 0xd0:

code:
    db 0x25, "Type in your name:", 0x0a, 0x0d, 0x00, 0x27, 0x25, "Hi, ", 0x00, 0x26, 0x00, 0xd0, 0x00

3. in函数缓冲区满时无退出逻辑

当输入缓冲区满(cx减为0)时,in_full_buff仅设置进位标志,未跳转到结束逻辑,会继续执行越界写入操作。

修复:添加跳转指令到结束逻辑:

in_full_buff:
    stc
    jmp in_end  ; 跳转到输入结束处理

4. 内核out函数未保存寄存器

内核的out函数未保存si等寄存器,调用后会破坏字节码解释器的si指针,导致执行流程中断。

修复:给out函数添加寄存器保存与恢复:

out:
    pusha  ; 保存寄存器
    mov ah, 0x0e

out_loop:
    mov al, [si]
    cmp al, 0x00
    je out_end
    int 0x10
    inc si

    jmp out_loop

out_end:
    popa  ; 恢复寄存器
    ret

验证修复

应用上述修改后,重新编译生成镜像并运行,输入用户名按回车后将正常输出问候语,不再出现卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:28:15