OS自作入門 on Ubuntu 16.04 (2日目)

2日目の内容は,1日目で作成したアセンブラコード(helloos2.s)のプログラム本体をちゃんとアセンブラで実装するようです.プログラム本体は DB 命令でよくわからない16進数のデータを打ち込んでいますが,これは言わば機械語のプログラムです.この機械語のプログラムをちゃんとアセンブラコードとして書いていきましょう.

ツールのインストール

1日目に使ったツール以外にインストールするものはありません.


helloos5.s への書き換え

16ビットバイナリの生成
2日目のアセンブラの説明を読むと分かるのですが,ここで出てくるアセンブラコードは 16 ビットの命令を前提としています.AX レジスタが 16 ビットというところから分かると思います.ただ,Ubuntu 16.04 で x86_64 版は 64 ビット OS ですので,16 ビット命令として機械語を生成する必要があります.ですので,アセンブラコードの先頭に

.code16

という行を追加する必要があります.

レジスタの書き方
NASK(NASM)では AX レジスタは単に AX と記述すればよかったのですが,GAS では % をつける必要があります.AX レジスタであれば,%axという具合です.

数値の書き方
NASK(NASM)では単に 0 と書けばよかったのですが,GAS では $ をつけて $0 とします.16進数の場合も同じで,0x0e を GAS では $0x0e と書きます.
ORG 命令
コードの最初に出てくる ORG 命令ですが,これに対応する GAS の命令ないようです.無いってどういうこと?と疑問が膨らみますが,どうやら NASK(NASM)と GAS は構文が異なるだけでなく,細かい違いもあるようです.

NASK の ORG 命令はプログラムの本体がどこにあるかを指定しますが,GAS ではプログラム中に書くのではなく,アセンブラにオプションとして与える方針です.とりあえずスキップして先に進みましょう.後でこれに対応する方法を書きます.

JMP 命令
ORG 命令の下には JMP 命令があります.これは GAS でも同じように

jmp entry

と書けばOKです.ところで, helloos2.s では JMP 命令の部分は

.byte 0xeb, 0x4e

となっていました.これが jmp 命令を機械語に翻訳した機械語だったんですね.jmp 命令より下からプログラム本体までは変更がないので,プログラム本体までスキップします.

MOV 命令
プログラム本体の最初に出てくる MOV 命令は,GASだと微妙に違っています.GAS では場合によって movw と movb の2種類を使い分けます.movw の w はワードを意味していて,オペランドが2バイト(16ビット)の場合です.一方,movb の b はバイトを意味していて,オペランドが1バイト(8ビット)の場合です.GAS 用に変換するときは注意深く使い分けましょう.

さらに,代入元(ソース)と代入先(デスティネーション)の位置が反対になっています.

MOV AX, 0

は AX レジスタに 0 を代入するという意味ですから,

AX ← 0

というイメージです.一方,GAS では

movw $0, %ax

と書きます(AXレジスタは16ビットなので movw を使います).つまり,

0 → AX

というイメージです.ソースとデスティネーションが反対になっていることが分かると思います.

movb の場合も見てみましょう.

MOV AH, 0x0e

というのがありますが,AHレジスタは8ビットですので,

movb $0x0e, %ah

となります.NASK(NASM)ではどちらも同じ MOV 命令を使っていましたが,GAS では区別していることに注意しましょう.

もうひとつ,MOV 命令の中には

MOV AL, [SI]

という書き方があります.これはメモリアクセスですが,GAS では [] の代わりに () を使いますので,

movb (%si), %al

となります(AL レジスタが8ビットなので movb を使います).

ADD 命令

ADD 命令も MOV 命令と同じで addw と addb があります.また,ソースとデスティネーションが入れ替わるのも同じです.したがって,

ADD SI, 1



addw $1, %si

となります.

CMP 命令
CMP 命令にも cmpw と cmpb があります.ソースとデスティネーションも入れ替わっています.

CMP AL, 0

は,AL レジスタを使っているところからも分かるように,以下のように cmpb を使います.

cmpb $1, %al

JE 命令, JMP 命令, INT 命令, HLT 命令
これらの命令には違いがありません.

アセンブラコード
以下は helloos5.s です.

.code16
        jmp entry

.byte 0x90
.ascii "HELLOIPL"
.word 512
.byte 1
.word 1
.byte 2
.word 224
.word 2880
.byte 0xf0
.word 9
.word 18
.word 2
.long 0
.long 2880
.byte 0,0,0x29
.long 0xffffffff
.ascii "HELLO-OS   "
.ascii "FAT12   "
.org .+18

# プログラム本体
entry:
        movw    $0,             %ax
        movw    %ax,            %ss
        movw    $0x7c00,        %sp
        movw    %ax,            %ds
        movw    %ax,            %es

        movw    $msg,           %si
putloop:
        movb    (%si),          %al
        addw    $1,             %si
        cmpb    $0,             %al
        je      fin
        movb    $0x0e,          %ah
        movw    $15,            %bx
        int     $0x10
        jmp     putloop
fin:
        hlt
        jmp     fin

# メッセージ部分
msg:
        .byte 0x0a, 0x0a
        .ascii "hello, world"
        .byte 0x0a
        .byte 0

.org 0x1fe

.byte 0x55, 0xaa

実行

Makefile は後回しにして,とりあえず実行してみます.

リンカオプション
OS のイメージを作成するにあたり,上の ORG 命令でスキップした「プログラムの開始地点」をオプションで与えなければなりません.これを与えるのがリンカオプションです.以下の記述を binary.ls として与えます.

OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)

SECTIONS
{
  . = 0x7c00;
  .text : {*(.text)}
}

OS イメージの作成
以下の手順で OS イメージを作ります.

$ as -32 helloos5.s -o helloos5.o
$ ld helloos5.o -T binary.ls -o helloos5.bin
$ mformat -f 1440 -C -B helloos5.bin -i helloos5.img ::

OS の起動
これは1日目と同じで

$ qemu-system-x86_64 -fda helloos5.img

とすればOKです.

Makefile
できるだけ忠実に Makefile を書いてみました.ただし,install は不要ですので書いてありません.

# コマンド

helloos5.bin: helloos5.s Makefile
 as -32 helloos5.s -o helloos5.o
 ld helloos5.o -T binary.ls -o helloos5.bin

helloos5.img: helloos5.bin Makefile
 mformat -f 1440 -C -B helloos5.bin -i helloos5.img ::

img:
 make -r helloos5.img

asm:
 make -r helloos5.bin

run:
 make img
 qemu-system-x86_64 -fda helloos5.img


この Makefile を使って,

$ make run

とすれば実行まで一気にやってくれます.


今日はここまで.

コメント

このブログの人気の投稿

第1回 ラムダ抽象と関数適用

パソコンの Arch Linux に Emacs をインストール

パソコンの Arch Linux に Chrome をインストール