-
Notifications
You must be signed in to change notification settings - Fork 5
Babystep2
- 簡単な復習
- BIOSによって読み込まれるブートセクタの大きさは512Bytes
- ブートセクタの読み込まれるアドレスは0000:7c00
- 最初はリアルモードで起動する
- CLI命令を実行するまで、CPUは割り込みを受け続けることを忘れないように
(全てではないが)多くのBIOS割り込みは、DSレジスタにリアルモードのセグメントセレクタが代入されていることを期待しています。これが、BIOS割り込みが保護モードで動作しない理由です。そのため、もしもINT 10h / AH=0x0e
を使用して画面に出力したいなら、出力したい文字を指すアドレスseg:offsetが正しいものかどうか確認しなければなりません。
リアルモードでは、アドレスはsegment * 16 + offset
として計算されます。offsetが16よりも大きくなることがあるために、同じアドレスを指すseg:offsetの組は複数存在します。たとえば、ブートローダーが読み込まれるアドレスは0000:7C00とも、07C0:0000とも言えます。これらは、実際に全く同じアドレス0x7C00を指します。(16 * 0x0000 + 0x7C00 = 16 * 0x07C0 + 0x0000 = 0x7C00)
0000:7C00と07C0:0000のどちらを使ってもよいのですが、ORG疑似命令を使用する際に、何が起きるのか気をつけなければなりません。デフォルトでは、生バイナリの開始オフセットは0であるとされています。しかし、必要であればそれを変更することができます。
たとえば以下のコードは、セグメントを0x7C0としたときに変数msgにアクセスする例です。
; boot.asm
mov ax, 0x07c0
mov ds, ax
mov si, msg
ch_loop:lodsb
or al, al ; zero=end or str
jz hang ; get out
mov ah, 0x0E
int 0x10
jmp ch_loop
hang:
jmp hang
msg db 'Hello World', 13, 10, 0
times 510-($-$$) db 0
db 0x55
db 0xAA
もう一つの例は、ORGを使用したバージョンです。このとき、msgはセグメントを0とした状態でアクセスされます。ここで注意しなければならないのは、この場合においても、DSは好きな値に設定可能であるということです。
[ORG 0x7c00]
xor ax, ax ; make it zero
mov ds, ax
mov si, msg
ch_loop:lodsb
or al, al ; zero=end of string
jz hang ; get out
mov ah, 0x0E
int 0x10
jmp ch_loop
hang:
jmp hang
msg db 'Hello World', 13, 10, 0
times 510-($-$$) db 0
db 0x55
db 0xAA
典型的な「サブルーチン」は、以下のコードのように、たいていCALLとRETを使って、元々のコードの流れから切り離されます。
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
mov si, msg
call bios_print
hang:
jmp hang
msg db 'Hello World', 13, 10, 0
bios_print:
lodsb
or al, al ;zero=end of str
jz done ;get out
mov ah, 0x0E
int 0x10
jmp bios_print
done:
ret
times 510-($-$$) db 0
db 0x55
db 0xAA
いくつかの理解しがたい理由のために、SIに代入してそしてサブルーチンに飛ぶと、私の環境ではうまくいきませんでした。NASMのマクロを利用することで、パラメーターを渡すふりができます。(マクロ定義は呼び出しより前になければいけません。)
%macro BiosPrint 1
mov si, word %1
ch_loop:lodsb
or al, al
jz done
mov ah, 0x0E
int 0x10
jmp ch_loop
done:
%endmacro
[ORG 0x7c00]
xor ax, ax
mov ds, ax
BiosPrint msg
hang:
jmp hang
msg db 'Hello World', 13, 10, 0
times 510-($-$$) db 0
db 0x55
db 0xAA
もしもソースコードが長くなってきて、読みにくくなってきたら、別ファイルに分けることも可能です。別ファイルに分けたら、以下のようにメインのコードの最初で読み込んでください。
jmp main
%include "othercode.inc"
main:
; 残りのコードが続く…
最初のjmp命令を忘れないようにしてください。忘れてしまうと、othercode.incの最初の関数が実行されてしまうでしょう。