少し前に、
IA-32アーキテクチャをもう少しよく勉強することにしました。 そして、覚えておくべき最善のことは何ですか? もちろん、練習してください。 しかし、OSでプログラミングする場合、干渉なしにハードウェアへの最低レベルのアクセスを得ることはほとんどありません。 したがって、これらの目的のために、オペレーティングシステムの独自の類似性を記述します。 つまり、簡単に言えば、BIOSを読み込んだ直後にコードを実行します。
低レベルでプログラミングしたい人が遭遇する最初の問題は、コードをダウンロードする方法ですか?
エントリー
通常、BIOSには起動を試みるデバイスのリストがあり、順番に並べ替えられます。 このリストは通常、ドライブ、CDドライブ、ハードドライブで構成されます。 フロッピーディスクとCD-ROMからの起動はほぼ同じです。ディスクの起動領域の互換性のために、ディスクイメージが配置され、メモリにコピーされて仮想ドライブとして機能します。 そして以来 フロッピーディスクから起動するのが最も簡単で、これを使用します。
BIOSはすべてのデバイスを検出し、それ自体に必要なすべてを実行した後、ディスケットの最初のセクターをアドレス0000:7C00のメモリーにロードし、そこで制御を渡します。 ここで最初の問題が発生します-フロッピーディスク上のセクタのサイズは512バイトしかないため、このフレームワークに適合して残りのコードをダウンロードする必要があります。 それでもこれがあなたにとって多くのように思えるなら、私は互換性のために〜60人がサービス目的に費やされていると言います。 もちろん、それらを捨てることはできますが、システム上でディスケットが見えない可能性があり、そこにファイルをコピーすることは困難です。
簡単にするために、このデータを後で追加します。 上記のすべてのコードがFASM構文で提供されるように、すぐに予約してください。
それでは、最も簡単なことから始めましょう。コントロールを取得し、テキストを表示します。
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
-
Use16 org 0x7C00 start : cli ; mov ax , cs ; mov ds , ax mov es , ax mov ss , ax mov sp , 0x7C00 ; .. , mov ax , 0xB800 mov gs , ax ; mov si , msg call k_puts hlt ; jmp $ ; k_puts : lodsb test al , al jz . end_str mov ah , 0x0E mov bl , 0x07 ; int 0x10 jmp k_puts . end_str ret msg db 'Hello world' , 0x0d , 0x0a , 0 times 510 - ( $ - $$ ) db 0 db 0x55 , 0xaa
他の数百の例のようにこれで終わると思うなら、私はあなたを失望させるか、多分あなたを喜ばせるでしょう-私たちのブートローダーはディスク上のファイルを探してそれをロードします。
まず、FAT12のフロッピーディスクのレイアウトについて説明します。
最初のセクターはサービスデータ用に予約されています-BIOSパラメーターブロック(BPB)とブートコード。
BIOSパラメータブロック
この場合のBPBは次のようになります。
jmp start; 私たちのコードにジャンプ
db 0
BS_OEMName db 'MicLib'; 任意のテキスト
BPB_BytsPerSec dw 0x200; セクターのバイト
BPB_SecPerClus db 1; クラスター内のセクター
BPB_RsvdSecCnt dw 1; 予約済みセクターの数
BPB_NumFATs db 2; FATテーブルの数
BPB_RootEntCnt dw 0x00E0; ルートツリーのエントリ数
BPB_TotSec16 dw 0x0B40
BPB_Media db 0xF0
BPB_FATSz16 dw 9; セクターのFATサイズ
BPB_SecPerTrk dw 0x12; トラック上のセクター
BPB_NumHeads dw 2; 読み取りヘッドの数
BPB_HiddSec dd 0
BPB_TotSec32 dd 0
フロッピーディスクとファイルをさらに処理するために、いくつかの補助手順を作成します。
それらの最初は、絶対アドレスで1つのセクターを読み取ることです。 セクターは一連のパラメーターヘッド、クラスター、セクターではなく、1つの序数で設定されます。
- ;
- ; 絶対数によるディスクセクターの読み取り手順
- ;
- ; ログイン:
- ; dx-絶対セクター番号
- ; si-バッファアドレス
- ;
- k_read_sector :
- ; S = N mod 18 + 1
- ; T = N / 18
- ; H = T mod 2
- ; C = T / 2
- プシャ
- mov ax 、 dx
- mov cx 、 [ BPB_SecPerTrk ]
- mov bx 、 si
- xor dx 、 dx ; ここから始めて、上記の式に従って再計算を行います
- div cx
- mov ch 、 al
- shr ch 、 1
- mov cl 、 dl
- inc cx
- mov dh 、 al
- および dh 、 1
- mov axe 、 0x0201
- xor dl 、 dl
- int 0x13
- jnc @f ; フラグCが設定されている場合、エラーが発生しています
- mov si 、 msgErrorRead
- k_putsを呼び出します。 お知らせください
- @@ :
- ポパ
- ret
FASMに慣れていない人のために、ジャンプのタグについて説明します。
@@は普遍的なラベルであり、コード内でいつでも使用できます。
@b-コードの最初のマーク@@にジャンプ(戻る);
@f-コードのさらに最初のマーク@@にジャンプします(前方)。
次の手順は、これに対するアドオンであり、一度に複数のセクターを連続して読み取ります。 不満を言うことはできますが、チェックはどこにありますか? スペースを節約するために、セクター番号の正確性をチェックしません。
- ;
- ; 順次セクター読み取り手順
- ;
- ; ログイン:
- ; dx-初期セクター
- ; cx-読み取るセクタの行数
- ; si-読み取るメモリアドレス
- ;
- k_read_sectors :
- プッシュ dx
- cxを プッシュ
- @@ :
- k_read_sectorを呼び出す
- Inc dx
- siを 追加 、 [ BPB_BytsPerSec ]
- dec cx
- jnz @b ; まだ読んでいない0
- ポップ cx
- ポップ DX
- ret
ご覧のとおり、まだ複雑なものはありませんが、機能は追加されています。
次に、ファイルを読むために必要なものを説明します。 まず、メモリ内のFATテーブル全体とルートディレクトリを検討します。
FATテーブルとルートディレクトリ
FAT12テーブル全体は、12ビット(!)のレコードで構成され、それらは一緒にチェーンされています。 数字は、セクターの絶対アドレスを示します。 数値が0xFFFになるまで読み取ります。これがチェーンの終わりです。
つまり ファイルが513バイトを占有する場合、2つのセクターが割り当てられますが、2番目のセクターは1バイトのみで占有されます。
さて、メインディレクトリのテーブルについては-ファイルに関するすべてのデータを含む32バイトのレコードで構成されています。
そのフォーマットは次のとおりです。
+0 11「IIIIIIIIRRR」形式のファイル名
長さが8文字のファイル名は、短い場合はスペースで埋められます。 区切り点はありません。
3バイト拡張
+ 0Bh 1ファイル属性:
01h-読み取り専用
02h-非表示
04h-システム
08h-ボリュームラベル
10h-ディレクトリ
20h-アーカイブ
+ 0Ch 10予約済み
+ 16時間2ファイル時間形式での作成または変更時間
+ 18h 2ファイル時間形式の作成日または変更日
+ 1Ah 2 FATの最初のチェーンエントリの番号
+ 1Ch 4サイズ
1つの機能-ファイルを削除すると、レコード自体は削除されませんが、名前の最初のバイトのみが文字0xE5に置き換えられます。
長さがゼロのファイルを-にすることはできません したがって、フォルダが指定され、オフセット+ 1Ahで、ディレクトリにネストされたファイルの最初のレコードの番号が記録されます。
最初の2つは。 および..は、それぞれ現在のディレクトリの最初のレコードと親を指します。
さらに2つの非常に小さなプロシージャを作成します。これは、メモリ内の両方のテーブルを読み取ります。
- ;
- ; プロシージャは、FATテーブルをメモリに読み込みます
- ;
- k_read_fat :
- mov dx 、 1 ; ブートセクタのすぐ後ろに配置
- mov cx 、 [ BPB_FATSz16 ] ; 9セクター
- mov si 、 FAT
- k_read_sectorsを呼び出す
- ret
- ;
- ; プロシージャは、ルートディレクトリをメモリに読み取ります。
- ;
- k_read_root_dir :
- mov dx 、 19 ; 1 + 9 * 2
- mov cx 、 15
- mov si 、 ROOT
- k_read_sectorsを呼び出す
- ret
ファイルを読む
さて、ファイルのメモリを読み込むために、私たちが書いたすべてを収集すること、つまり ルートディレクトリでそのレコードを見つけ、FATのセクター番号を使用してメモリに読み込みます。
実際、この操作には最も時間とコードがかかりました。
- ;
- ; この手順では、フロッピーディスクからメモリにファイルを読み取ります。
- ;
- ; ログイン:
- ; di-バッファアドレス
- ; si-NNNNNNNNEEE形式の厳密なファイル名
- ; 出力:
- ; ax-ファイルが見つからない場合は0、見つかった場合は1-
- ;
- k_read_file :
- プッシュ ディ
- mov di 、 ROOT
- mov cx 、 0xE0 ; BPB_RootEntCnt
- 。 next_item :
- mov al 、 バイト [ di ]
- cmp al 、 0xE5 ;リモートファイルラベル
- je space_item
- cmp al 、 0 ;空白のエントリ
- je space_item
- プッシュ ディ
- プッシュ si
- cxを プッシュ
- mov cx 、 11 ; 8 + 3
- repe cmpsb ;ファイル名と検索を比較します
- cmp cx 、 0
- ポップ cx
- ポップシ
- ポップディ
- je read_file ;ブレーク
- 。 space_item :
- diを 追加 、 32 、レコード長
- ループ next_item
- xor ax 、 ax
- ; jmp .end_of_file
- ret
- 。 read_file :
- ポップシ
- mov bp 、 word [ di + 0x1A ] ; FAT開始セル番号
- mov bx 、 word [ di + 0x1C ] ;ファイルサイズ
- 。 read_next_claster :
- プシャ
- mov dx 、 bp
- サブ DX 、 3
- dx 、 0x22を 追加
- k_read_sectorを呼び出す
- ポパ
- cmp di 、 0xFFF
- je end_of_file
- mov di 、 bp
- mov axe 、 bp ; パリティのために保存
- mov bx 、 bp ; 0xFFFがある場合に保存
- imul di </ f