「手探りでCUI OS作成に挑む」問題解決篇　スタックの変化を観察

## 「手探りでCUI OS作成に挑む」連載

この記事は「手探りでCUI OS作成に挑む」連載の一部です。
全体の目次は[「手探りでCUI OS作成に挑む」連載目次](https://qiita.com/earthen94/items/b5d77f98f0cf85a13346)を御覧下さい。

## 目的
スタックが壊れ、土日２日間掛けても解決しなかった為、初めから書き直すことにした。
もうはまらないように文字表示をした際にスタックが正常に動くか検証する。
一人でやっていると結構精神的に参るので頑張った記録を載せる。
昨日はまった時はレジスタの値を表示するコードすらまともに動かなかったが今日コードを書き直して確認したところではスタックは崩れていないことが確認できた。

## 書き直したコード

<details>
<summary>load.asm</summary>

```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
```
</details>

## プログラム中で表示する
QEMUでは以下の命令がうまく効かなかったため、SSは断念してSPの値のみ観察する
```
    mov ax, ss
    call print_hex16
```

<details>
<summary>load.asm</summary>

```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
```
</details>

<details>
<summary>debug.asm</summary>

```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
```
</details>

![678a203586ef9da170215b90013875e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4054974/6b52f214-ef72-43aa-b89c-37533614eca7.png)

## QEMU+は断念

以下ので順で逆アセンブルをしたが、何度やっても16ビットとして認識されず、EAXのようなレジスタが表示されたのでQEMUを使うことは断念。
32、64ビットモードなら以下の手順でうまく行くと思う。
1. QEMUをこのように起動
```
qemu-system-i386 -fda testdisk.img -s -S
```

2. **別の端末**で 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
```