「手探りでCUI OS作成に挑む」連載
この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は「手探りでCUI OS作成に挑む」連載目次を御覧下さい。
目的
スタックが壊れ、土日2日間掛けても解決しなかった為、初めから書き直すことにした。
もうはまらないように文字表示をした際にスタックが正常に動くか検証する。
一人でやっていると結構精神的に参るので頑張った記録を載せる。
昨日はまった時はレジスタの値を表示するコードすらまともに動かなかったが今日コードを書き直して確認したところではスタックは崩れていないことが確認できた。
書き直したコード
load.asm
load.asm
[org 0x7E00]
[bits 16]
start:
; セグメント及びスタックの初期化
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ax,2000
mov ss,ax
mov sp,0xFFFE
sti
; 画面モードをテキストモードに設定
mov ah, 0x00
mov al, 0x03
int 0x10
mov si, message1
call print_str
mov si, message2
call print_str
mov si, message3
call print_str
mov si, message4
call print_str
done:
cli
hang:
hlt
jmp hang
; 文字列表示関数
print_str:
push ax
push si
mov ah, 0x0E ; BIOSテレタイプ機能
.loop:
lodsb ; 次の文字をALにロード
test al, al ; ヌル文字チェック
jz .done
int 0x10 ; BIOS文字表示
jmp .loop
.done:
pop si
pop ax
ret
message1 db 'message1', 0x0D, 0x0A, 0
message2 db 'message2', 0x0D, 0x0A, 0
message3 db 'message3', 0x0D, 0x0A, 0
message4 db 'message4', 0x0D, 0x0A, 0
times 512 - ($ - $$) db 0
プログラム中で表示する
QEMUでは以下の命令がうまく効かなかったため、SSは断念してSPの値のみ観察する
mov ax, ss
call print_hex16
load.asm
load.asm
[org 0x7E00]
[bits 16]
start:
; セグメント及びスタックの初期化
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ax,2000
mov ss,ax
mov sp,0xFFFE
sti
; 画面モードをテキストモードに設定
mov ah, 0x00
mov al, 0x03
int 0x10
mov ax, sp
call print_hex16
mov si, message1
call print_str
mov ax, sp
call print_hex16
mov si, message2
call print_str
mov ax, sp
call print_hex16
mov si, message3
call print_str
mov ax, sp
call print_hex16
mov si, message4
call print_str
done:
cli
hang:
hlt
jmp hang
; 文字列表示関数
print_str:
push ax
push si
mov ah, 0x0E ; BIOSテレタイプ機能
.loop:
lodsb ; 次の文字をALにロード
test al, al ; ヌル文字チェック
jz .done
int 0x10 ; BIOS文字表示
jmp .loop
.done:
pop si
pop ax
ret
%include "debug.asm"
message1 db 'message1', 0x0D, 0x0A, 0
message2 db 'message2', 0x0D, 0x0A, 0
message3 db 'message3', 0x0D, 0x0A, 0
message4 db 'message4', 0x0D, 0x0A, 0
times 512 - ($ - $$) db 0
debug.asm
debug.asm
; 使用例:レジスタ表示
; mov ax, si ; SIの値をAXにコピー
; call print_hex16
;---------------------------------------
; AXの値を16進数で表示する (例: "3F20")
;---------------------------------------
print_hex16:
pusha
mov cx, 4 ; 4桁出力
.hex_loop:
rol ax, 4 ; 上位4bitをALに持ってくる
mov bl, al
and bl, 0x0F
call print_hex_digit
loop .hex_loop
mov ah, 0x0E
mov al, 0x0D ; CR(キャリッジリターン)
int 0x10
mov al, 0x0A ; LF(ラインフィード)
int 0x10
popa
ret
;---------------------------------------
; ALの下位4bitを16進文字に変換して出力
; 入力: BL = 0〜15
;---------------------------------------
print_hex_digit:
pusha
cmp bl, 10
jl .digit
add bl, 'A' - 10
jmp .output
.digit:
add bl, '0'
.output:
mov al, bl
mov ah, 0x0E
int 0x10
popa
ret
QEMU+は断念
以下ので順で逆アセンブルをしたが、何度やっても16ビットとして認識されず、EAXのようなレジスタが表示されたのでQEMUを使うことは断念。
32、64ビットモードなら以下の手順でうまく行くと思う。
- QEMUをこのように起動
qemu-system-i386 -fda testdisk.img -s -S
- 別の端末で gdb
gdb
set architecture i8086
target remote localhost:1234 # 接続する
set disassembly-flavor intel # インテル記法へ切り替え
b *0x7e00 # ブレークポイントを貼る
c # ブレークポイントまで進める
x/20i 0x7e00 # 0x7e00から逆アセンブル
明らかに16ビットモードではありえないコードに変換されてしまう。
…
0x7e01: xor eax,eax
0x7e03: mov ds,eax
0x7e05: mov es,eax
0x7e07: mov eax,0xd08e07d0
……
Bochs+も断念
対応していない??
ubuntu@ubuntu:~/kaihatsu/test3$ bochs -f bochsrc
00000000000i[ ] LTDL_LIBRARY_PATH not set. using compile time default '/usr/lib/x86_64-linux-gnu/bochs/plugins'
========================================================================
Bochs x86 Emulator 2.7
Built from SVN snapshot on August 1, 2021
Timestamp: Sun Aug 1 10:07:00 CEST 2021
========================================================================
00000000000i[ ] BXSHARE not set. using compile time default '/usr/share/bochs'
00000000000i[ ] lt_dlhandle is 0x5c0e388b0110