x86リアルモードでモニターを作ろうシリーズです。
Windows11+wsl2で構築しています。
バグ
まずはバグの話です。前回メモリのアロケーターを導入したのはいいのですが、いろんなバグに悩まされました。例えばこんなやつ。
二週目でハングする
一週目は正常に動作するのですが、2週目でハングしました。
あるいは無限ループに入るとか。
これは比較的楽な方で、2週目投入時のセグメントがずれていたので誤動作していました。修正して一応治ったと思います。
三週目でハングする
一週目、二週目は正常に動くのですが三週目でハングしました。
ゴミがたまって限界を超えるパターンですね。使っているバッファとかを念入りに初期化して退治しました。
nopを入れると動作が変わる
極めつけはこれ。nopという『なにもしない』命令を入れると動作が変わるというやつ。
もう意味わかんない。
制御系でタイミングをとるために……じゃなくて、サブルーチンとサブルーチンの間のなにも動作しないところにnopをいれたら動作が変わってしまうという。
アドレス配置が換わって問題になるのはわかるのですが『どこ』を直せばいいか、まったく手掛かりがないという最悪のバグ。
スタック不整合、スタックリーク、各変数のアドレス確認など色々やってなんとか落ち着きました。
でも、一番厄介なのは
バグがなくなったわけじゃない
ってことですね。バグがなくなったと言い切れないところが辛いところです。
そんなこんなで時間がかかったのでした。
誰が居る?
さて今回の開発するのはlsです。そもそもメモリアロケータを導入するきっかけになったネタです。ソースはこんな感じ。
; ===== BUFとして1ページを割り当て =====
mov ah, svc_page_alloc
int 0x80
jc .alloc_error
; バッファ情報を控えておく
shl dx, 12
mov [BUF_SEG], dx
mov [BUF_OFF], ax
xor ax, ax
mov es, ax
; 各種パラメータの取得
; -----------------------------------
; Bootドライブ
; -----------------------------------
mov al, es:[BOOT_DRV_OFF]
mov [BOOT_DRIVE], al
; -----------------------------------
; DIR_LBA
; -----------------------------------
mov ax, es:[DIR_START_LBA]
mov [DIR_LBA], ax
; -----------------------------------
; ROOT_ENT_CNT
; -----------------------------------
mov ax, es:[ROOT_ENT_CNT_OFF]
mov [ROOT_ENT_CNT], ax
; -----------------------------------
; BYTE_PER_SEC
; -----------------------------------
mov ax, es:[BYTE_PER_SEC_OFF]
mov [BYTE_PER_SEC], ax
; -----------------------------------
; rootのセクタ数を算出
; -----------------------------------
mov ax, [ROOT_ENT_CNT]
mov bx, 32
mul bx
mov bx, [BYTE_PER_SEC]
div bx
mov [DIR_ENT_SEC_CNT], ax
mov bx, BUF_SEG
mov es, bx
; ヘッダのの表示
mov si, ._s_head1
mov ah, svc_write
int 0x80
mov si, ._s_head2
mov ah, svc_write
int 0x80
.dir_ent_sec_loop:
; -----------------------------------
; Dir Entを読み込む
; -----------------------------------
mov si, dap
mov word [si + DAP.NumBlocks], ENT_SECTORS ; sectors
mov word [si + DAP.BufferOff], BUF_OFF ; buffer offset
mov word [si + DAP.BufferSeg], BUF_SEG ; buffer segment
mov ax, [DIR_LBA]
mov word [si + DAP.LBA_Low], ax ; LBA low Low
mov dword [si + DAP.LBA_High], 0 ; LBA high
mov dl, ds:[BOOT_DRIVE]
mov ah, 0x42
int 0x13
jc .disk_error
mov di, BUF_OFF
mov cx, 16 ; Byte/Ent
.entry_loop:
; ファイル、ディレクトリ以外を除外
mov al, es:[di]
cmp al, 0x00
je .not_found
cmp al, 0xE5
je .next_entry
mov al, es:[di+11]
test al, 0x08 ; Volume
jnz .next_entry
; ファイル名の表示
mov dx, 11
push di
.file_name_loop:
; mov ah, svc_putchar
; mov al, es:[di]
; int 0x80
; mov ah, 0x0e
; mov al, es:[di]
; int 0x10
mov al, es:[di]
call pc
inc di
dec dx
cmp dx, 0
jne .file_name_loop
mov al, ' '
call pc
pop di
; ディレクトリなら<DIR>を表示
mov al, es:[di+DIR_ENTRY.Attr]
test al, 0x10 ; dir
jz .dir_skip
mov ax, ._s_dir
call ps
jmp .file_skip
.dir_skip:
mov al, ' '
call pc
; ファイルならサイズを表示
test al, 0x20 ; file
jz .file_skip
mov ax, es:[di+DIR_ENTRY.FileSize]
call ph4
.file_skip:
mov ah, svc_newline
int 0x80
.next_entry:
add di, 32
loop .entry_loop
.next_sec:
mov ax, [DIR_LBA]
inc ax
mov [DIR_LBA], ax
mov ax, [DIR_ENT_SEC_CNT]
dec ax
mov [DIR_ENT_SEC_CNT], ax
cmp ax, 0
jnz .dir_ent_sec_loop
jmp .skip
.alloc_error:
PUTC 'E'
PUTC 'r'
PUTC 'r'
jmp .skip
.disk_error:
PUTC 'E'
PUTC 'r'
PUTC 'r'
.not_found:
.skip:
; ===== BUFを開放 =====
mov dx, [BUF_SEG]
shr dx, 12
mov bx, [BUF_OFF]
mov ah, svc_page_free
int 0x80
ret
._s_head1: db ' NAME SIZE', 0x0d, 0x0a, 0x00
._s_head2: db '-----------+------', 0x0d, 0x0a, 0x00
._s_dir: db '<DIR>', 0x00
実行結果はこうなります。

オプションとかは対応してません。
このソースはgithubで公開しています。よろしければどうぞ。
https://github.com/CbWB-Inc/software/tree/main/laboratory/lab02/hyfax-09-ls
《2026/01/31 16:37:23》
コメント