いものやま。

雑多な知識の寄せ集め

『OS自作入門』を読んでみた。(その4)

またまた間が空いてしまったけど、前回の続き。

今日は実際のブートコードの部分を見ていく。

Intel構文とAT&T構文

前回も少し触れた通り、本はNASMに似た筆者作のアセンブラを使っていて、その構文はIntel構文になっている。
一方、自分の使っているGNU asは、AT&T構文で、いろいろ違ってくる。
詳細は以下のページなどを参照:

Linux のアセンブラー: GAS と NASM を比較する

基本的なところを押さえておくと、以下のとおり:

  • オペランドのディスティネーションとソースが逆
    • NASMはディスティネーション、ソースの順
    • GNU asは、ソース、ディスティネーションの順
  • 即値の指定の仕方が違う
    • NASMは数字やラベルをそのまま書く
    • GNU asは数字やラベルの前に$をつける
  • レジスタの指定の仕方が違う
  • 数字やラベルによるメモリの参照の仕方が違う
    • NASMは数字やラベルを[]で囲う
      バイト幅の指定が必要な場合、[]の前にbyte(1-byte)、word(2-byte)、dword(4-byte)をつける
      なお、NASMは数字やラベルの前にbyte ptr(1-byte)、word ptr(2-byte)、dword ptr(4-byte)をつけるのでもOKっぽい(※)
    • GNU asは数字やラベルをそのまま書き、バイト幅を示すためにオペコードにb(1-byte)、w(2-byte)、l(4-byte)をつける
  • レジスタによるメモリの参照の仕方が違う
    • NASMは
      [セグメントレジスタ:ベースレジスタ + インデックスレジスタ * スケーラ + オフセット]
      とする(使わないところは省略可能)
      (セグメントレジスタ x 16 + ベースレジスタ + インデックスレジスタ x スケーラ + オフセット)を参照することになる
    • GNU asは
      セグメントレジスタ:オフセット(ベースレジスタ, インデックスレジスタ, スケーラ) とする(使わないところは省略可能)
      (セグメントレジスタ x 16 + ベースレジスタ + インデックスレジスタ x スケーラ + オフセット)を参照することになる

※上記のIBMのページだとこう書かれているけど、なんか怪しい・・・

なお、NASMに関してと、レジスタによるメモリの参照は、ネット上の資料を漁っただけなので、正しくないかも・・・
(しっかりした資料が見つかってないので、自信がない・・・ちなみに、これを調べてたせいで更新が遅くなった)

16ビットモード

まず、x86のCPUには、16ビットモード(リアルモード)と32ビットモード(プロテクトモード)がある。
起動した直後は16ビットモードになっているので、アセンブラで出力されるコードも16ビットモード用のものになっていないと困る。

そこで、次のように、擬似命令を使ってこのコードが16ビットモード用のものであることを示してやる:

    // 16-bit code
    .code16

ブートコード

そして、前回見た通り、ジャンプコード、BIOSパラメータブロックが続いて、そのあとにブートコードが来ることになる。
ジャンプコードでは、このブートコードの先頭に飛んでくるようにジャンプを行なっている。

最初にやっているのは、レジスタの初期化。

entry:
    mov     $0, %ax
    mov     %ax, %ss
    mov     $0x7c00, %sp
    mov     %ax, %ds
    mov     %ax, %es
    // 続く

まずアキュムレータレジスタ(ax)を0で初期化し、さらにスタックのセグメントレジスタ(ss)、データのセグメントレジスタ(ds)、追加のセグメントレジスタ(es)をaxを使って0に初期化。
そして、スタックポインタ(sp)を0x7c00で初期化している。

ここからは文字列の出力。

まず、文字列が置かれているmessageというラベルのアドレスをソースインデックスレジスタ(si)に代入。

    // 続き
    mov     $message, %si
    // 続く

アドレスの内容ではなく、アドレスの値をそのまま入れるので、即値になるように$をつける必要があるのに注意。
(最初、つけるのを忘れて動かなかった)

そしたら、siの指す内容をaxの下位8ビット(al)に読み込む。

    // 続き
putloop:
    movb    (%si), %al
    // 続く

最初はsiの値はmessageのアドレスになっているので、改行文字¥nが読み込まれることになる。
そして、次々と読み込んで出力したいので、siの値を1つずつ増やしていくことになる。

    // 続き
    add     $1, %si
    // 続く

ここで、もし読み込んだ文字がヌル文字¥0だった場合、文字列の終端になっているので、ループを抜け出すことになる。

    // 続き
    cmp     $0, %al
    je      fin
    // 続く

あとは、実際に文字を出力する処理。
これにはBIOSAPIを利用する。

    // 続き
    mov     $0x0e, %ah
    mov     $15, %bx
    int     $0x10
    // 続く

決められたレジスタに値をセットして、ソフトウェア例外を起こしている(int命令)。
これで制御がBIOSに移って、文字を出力したらまた戻ってきてくれる。

最後に、次の文字を出力するために、ループの先頭に戻る。

    // 続き
    jmp     putloop
    // 続く

一つ一つ読み解くと、こんな感じ。

Cで書いてみると、次のようなイメージ:

char* si = message;
while (1)
{
    char al = *si;
    si++;
    if (al == '¥0')
    {
        break;
    }
    putchar(al);
}

文字列の出力が終わったら、あとは無限ループ。

    // 続き
fin:
    hlt
    jmp     fin

hlt命令はCPUを休止状態にする命令で、例外が起きるまでCPUを休ませておいてくれる。


さて、これでブートコードも見たわけだけど、実はこれではまだ正しく動かなかったり。
というのも、ブートセクタはBIOSによってメモリの0x7c00に読み込まれるのだけど、このコードだと先頭が0x0000だと思ってリンクが解決されてしまうから。
なので、アドレスが正しくなっていない。

このアドレスの問題を解決するには、もう一工夫必要になってくる。
それについては、また次で。

今日はここまで!

30日でできる! OS自作入門

30日でできる! OS自作入門

『OS自作入門』を読んでみた。(その3)

前回からだいぶ間が空いてしまったけど、続き。

前回はディレクティブを使ってただデータを作っただけだったけど、それではアセンブラを使ったとは言い難いので、今回はちゃんとしたアセンブラを書いてみる。

ちゃんとしたアセンブラのコード

と言うことで早速、ちゃんとしたアセンブラのコード。

    .file   "hello-os.s"

    // 16-bit code
    .code16

    // partition boot record (1sector)
pbr:
    // jump to boot code
    jmp     entry
    nop

    // OEM name (8byte)
    .ascii  "HELLOIPL"

    // BIOS Parameter Block (FAT12/FAT16)
    .short  512                 // bytes per sector
    .byte   1                   // sectors per cluster
    .short  1                   // reserved sectors
    .byte   2                   // number of file allocation table
    .short  224                 // root directory entries
                                // (32byte/entry * 224entry = 7168byte = 512byte/sector * 14sector)
    .short  2880                // total sectors
    .byte   0xf0                // media type (0xf0: floppy disk, 0xf8: hard disk)
    .short  9                   // sectors per file allocation table
    .short  18                  // sectors per track
    .short  2                   // number of heads
    .int    0                   // hidden sectors
    .int    2880                // large total sectors
    .byte   0x00                // physical disk number
    .byte   0x00                // current head
    .byte   0x29                // extended boot signature (0x29 means DOS 4.0 EBPB)
    .int    0xffffffff          // volume serial number
    .ascii  "HELLO-OS   "       // volume label (11byte)
    .ascii  "FAT12   "          // file sytem type (8byte)

    .skip 18, 0x00

entry:
    mov     $0, %ax
    mov     %ax, %ss
    mov     $0x7c00, %sp
    mov     %ax, %ds
    mov     %ax, %es
    mov     $message, %si
putloop:
    movb    (%si), %al
    add     $1, %si
    cmp     $0, %al
    je      fin
    mov     $0x0e, %ah
    mov     $15, %bx
    int     $0x10
    jmp     putloop
fin:
    hlt
    jmp     fin

message:
    .string "\n\nhello, world\n"

    .org    0x0200 - 0x02
    .byte   0x55, 0xaa  // boot signature

    // file allocation table (9sectors = 512byte/sector * 9sector = 4608byte)
fat:
    .byte   0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    .skip   0x200 * 9 - 8, 0x00

    // file allocation table (copy)
fat_copy:
    .byte   0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    .skip   0x200 * 9 - 8, 0x00

    // root directory entries (14sectors = 512byte/sector * 14sector = 7168byte)
root_directories:
    .skip   0x200 * 14, 0x00

    // data area (2847sectors = 2880 - 1 - 9 * 2 - 14)
files:
    .skip   0x200 * 2847, 0x00

本のコードを参考にしてるけど、だいぶ違ってる。
というのも、まず本はNASMに似たnaskという著者作のアセンブラを使っていて、Intel構文だけど、自分はGNU asを使っているので、AT&T構文になっているから。
それに、いろいろ分からなかったことを調べた結果が盛り込まれているというのもある。

FATファイルシステム

まず、FATファイルシステムについてから。

フロッピーディスクはセクタと呼ばれる区画で区切られていて、セクタ単位でデータを読み書きする。
1つのセクタが512バイトで、フロッピーディスクの場合、2880セクタ用意されている。
このセクタがディスク上にどう並んでいるのかはあとで扱うとして、論理的にはセクタが配列のように一列に並んでいると考えておいていい。
そう考えたときに、このセクタの配列は、FATフォーマットではいくつかの領域に分けられる:

  • ブートセクタ
    PCが起動したときにBIOSによってメモリにロードされて実行されるセクタ
  • FAT(File Allocation Table)領域
    クラスタ(1つ以上のセクタの集まり)の情報を管理するための領域
  • ルートディレクトリ領域
    ルート直下のディレクトリの情報が置かれる領域
  • データ領域
    各ファイルの情報が置かれる領域

上のコードだと、以下のように分けられている:

pbr:

    // ブートセクタ

fat:

    // FAT領域

root_directories:

    // ルートディレクトリ領域

files:

    // データ領域

ブートセクタは1セクタ、FAT領域は1つのFile Allocation Tableが普通9セクタで、冗長化でコピーが用意されているので合計18セクタ、ルートディレクトリ領域はFAT12だと普通は14セクタ、そして、残りがデータ領域となるので、データ領域は2847セクタということになる。

Cでイメージを書いておくと、以下のような感じ:

// セクタは512バイトのデータ
typedef struct sector_ {
    unsigned char data[512];
} sector_t;

// フロッピーディスク
typedef union floppy_ {
    // 2880セクタからなる
    sector_t sectors[2880];

    // 領域
    struct {
        // ブートセクタ
        sector_t boot_sector;

        // FAT領域
        struct {
            // File Allocation Table
            sector_t fat[9];

            // File Allocation Table (copy)
            sector_t fat_copy[9];
        } fat_area;

        // ルートディレクトリ領域
        sector_t root_directories_area[14];

        // データ領域
        sector_t data_area[2847];
    } areas;
} floppy_t;

アセンブラのコードを見てみると、今のところちゃんとしたデータが置いてあるのはブートセクタだけで、他の領域は.skipを使ってほぼ0にしていることが分かると思う。
これは、今書いているのがブート時に読み込まれて実行されるプログラムで、他にファイルをディスク上に作っていないから。

ブートセクタ

さらに、ブートセクタを見てみる。

パーティションが1つの場合、ブートセクタはただ1つなんだけど、ハードディスクとかだと複数のパーティションに分かれている場合があって、その場合、各パーティションの1つめのセクタが論理的にブートセクタになる。
そこで、ディスクの先頭にあるブートセクタを、マスターブートレコードMBR)、各パーティションの先頭にあるブートセクタをパーティションブートレコード(PBR)と言ったりする。
フロッピーディスクの場合、パーティションは分けられていない(=パーティションは1つだけ存在する)ので、MBRがそのままPBRになっている。

そして、MBRとPBRでは微妙に構造が違っていて、MBRはセクタの最後の方にパーティションの情報を持つパーティションテーブルというのが置かれることになっている。
もちろん、フロッピーディスクの場合、パーティションテーブルは不要なので、構造的にはPBRになっている。
ということで、ラベルはmbrではなくpbrにしている。

    // partition boot record (1sector)
pbr:
    ...

PBR(およびMBR)は、以下のような構造になっている:

  • ジャンプコード (3byte)
    以下のデータを飛び越して実際のブートコードに行くためのジャンプ命令+α
  • OEM (8byte)
    ブートセクタの名前とか
  • BIOSパラメータブロック
    ディスクの情報をまとめた領域
  • ブートコード
    ブート処理を行うコード
  • パーティションテーブル (64byte) ※MBRのみ
    パーティションの情報
  • ブートシグニチャ (2byte)
    このセクタがブートセクタであることを示す

まずは、ジャンプコード。

    // jump to boot code
    jmp     entry
    nop

見ての通り、実際のブート処理を行うコード(entry以下)へジャンプを行なっている。
なお、ジャンプ命令には2byteのものと3byteのものがあるので、データの位置を揃えるために、2byteのジャンプ命令の後にはnop命令を入れている。
(本だとニーモニックnopとは書かず、直接機械語DB 0x90と書いている)

次はOEM名で、特に書くことなし。

    // OEM name (8byte)
    .ascii  "HELLOIPL"

その次がBIOSパラメータブロック。

    // BIOS Parameter Block (FAT12/FAT16)
    .short  512                 // bytes per sector
    .byte   1                   // sectors per cluster
    .short  1                   // reserved sectors
    .byte   2                   // number of file allocation table
    .short  224                 // root directory entries
                                // (32byte/entry * 224entry = 7168byte = 512byte/sector * 14sector)
    .short  2880                // total sectors
    .byte   0xf0                // media type (0xf0: floppy disk, 0xf8: hard disk)
    .short  9                   // sectors per file allocation table
    .short  18                  // sectors per track
    .short  2                   // number of heads
    .int    0                   // hidden sectors
    .int    2880                // large total sectors
    .byte   0x00                // physical disk number
    .byte   0x00                // current head
    .byte   0x29                // extended boot signature (0x29 means DOS 4.0 EBPB)
    .int    0xffffffff          // volume serial number
    .ascii  "HELLO-OS   "       // volume label (11byte)
    .ascii  "FAT12   "          // file sytem type (8byte)

ここが正直大変だったところで、本だと「その値にしておくものだから」で片付けられている値がけっこうある(^^;
しかも、ネットで調べても仕様がハッキリしない記述が多くて、かなり困った。

以下のwikipedia(en)の記述が結構役に立った感じ:

BIOS parameter block - Wikipedia

ここから18byteほど隙間を空けて、適当にアラインを揃えたところから、実際のブートコードは始まっている。
その詳細はまた後で。

そして、ブートセクタの一番最後にあるのが、ブートシグニチャ

    .org    0x0200 - 0x02
    .byte   0x55, 0xaa  // boot signature

ブートセクタの最後の方までスキップさせるために、.orgを使っている。
この擬似命令は、ファイルの先頭のアドレスを0として、引数で指定したアドレスまでスキップをしてくれる。
ということで、1セクタが512(= 0x200)バイトなので、そこからブートシグニチャの2バイトを引いたところまで、一気にスキップ。
そして、ブートシグニチャ0x55, 0xaaを書き込んでいる。
BIOSはこのブートシグニチャが入っていないセクタはブートセクタとして扱わないらしい。

さて、あとは肝心のブートコードの部分だけど、けっこう長くなったので、一旦区切り。

今日はここまで!

30日でできる! OS自作入門

30日でできる! OS自作入門

『OS自作入門』を読んでみた。(その2)

前回はVimバイナリエディタとして使って直接フロッピーディスクのイメージを作った。

今回はアセンブラを使ってフロッピーディスクのイメージを作ってみる。

Binutilsのインストー

本ではNASMに似たnaskという著者作のアセンブラを使ってるけど、やっぱりアセンブラでよく知られているのは、GNUアセンブラ(gas)。
ということで、自分はnaskではなくgasを使ってみた。

gasはBinutilsというツール群に含まれている。
そこで、Binutilsをインストール。

GNU Binutils

インストールは簡単で、tarボールを落としてきて展開したら、configureスクリプトを実行してmakeするだけ。

$ tar zxvf binutils-2.28.tar.gz
$ cd binutils-2.28
$ ./configure --program-prefix=i386-elf- --target=i386-elf --disable-nls
$ make
$ sudo make install

configureスクリプト--program-prefixオプションをつけると、各ツールの頭に指定したプレフィクスがつく。
今回はi386-elf用のアセンブラその他を作るので、i386-elf-というプレフィクスをつけている。
(そうしないと、他のアーキテクチャ向けのアセンブラを作ったときに、名前がぶつかる)

また、--targetオプションで対象のアーキテクチャを指定している。

あと、--disable-nlsというオプションをつけているけど、これはNative Language Supportを無効にするもの。
このオプションをつけなかった場合、libintl.hが見つからないというエラーが出たので、つけている。
(このヘッダファイルはMacでQEMUのビルドをしてみた。 - いものやま。に書いたgettextの提供するヘッダファイルなので、同じようにインクルードパスを通してやるのでもOKのはず)

何はともあれ、これでBintuilsのインストールは完了。
i386-elf向けのアセンブラi386-elf-asというコマンドでインストールされている。

アセンブラソースの作成

Binutilsもインストールできたので、次はアセンブラソースの作成。
といっても、アセンブラでコードを書くのではなく、バイナリエディタと同じように、データを直接作ってみる。

gasの場合、.byte.intといった擬似命令(ディレクティブ)を使うことで、バイナリデータを直接書くことが出来る。
また、.skipという擬似命令を使うと、指定したサイズだけ隙間を作ることが出来る。

それらを使って書いたコードが、以下:

    .byte 0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f
    .byte 0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
    .byte 0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
    .byte 0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
    .byte 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
    .byte 0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4f
    .byte 0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41
    .byte 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00

    .skip 16, 0x00

    .byte 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
    .byte 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
    .byte 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
    .byte 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
    .byte 0xee, 0xf4, 0xeb, 0xfd, 0x0a, 0x0a, 0x68, 0x65
    .byte 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72
    .byte 0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00

    .skip 368, 0x00

    .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
    .byte 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00

    .skip 4600, 0x00

    .byte 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00

    .skip 1469432, 0x00

これをhello-os.sというファイルに保存すれば、ソースは完成。

asによるアセンブル

アセンブラソースが出来たので、これをasでアセンブルしてやる。

$ i386-elf-as -o hello-os.o hello-os.s

問題なくアセンブルが終われば、hello-os.oというオブジェクトファイルが生成される。

objcopyによるバイナリファイルの生成

ただ、これでフロッピーディスクのイメージが出来たかというと、そうではなく。

実際、生成されたhello-os.oの内容を表示してみると、以下のとおり:

$ hexdump -C hello-os.o |less
00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 03 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  a4 80 16 00 00 00 00 00  34 00 00 00 00 00 28 00  |........4.....(.|
00000030  07 00 06 00 eb 4e 90 48  45 4c 4c 4f 49 50 4c 00  |.....N.HELLOIPL.|
00000040  02 01 01 00 02 e0 00 40  0b f0 09 00 12 00 02 00  |.......@........|
00000050  00 00 00 00 40 0b 00 00  00 00 29 ff ff ff ff 48  |....@.....)....H|
00000060  45 4c 4c 4f 2d 4f 53 20  20 20 46 41 54 31 32 20  |ELLO-OS   FAT12 |
00000070  20 20 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |  ..............|
00000080  00 00 00 00 b8 00 00 8e  d0 bc 00 7c 8e d8 8e c0  |...........|....|
00000090  be 74 7c 8a 04 83 c6 01  3c 00 74 09 b4 0e bb 0f  |.t|.....<.t.....|
000000a0  00 cd 10 eb ee f4 eb fd  0a 0a 68 65 6c 6c 6f 2c  |..........hello,|
000000b0  20 77 6f 72 6c 64 0a 00  00 00 00 00 00 00 00 00  | world..........|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000230  00 00 55 aa f0 ff ff 00  00 00 00 00 00 00 00 00  |..U.............|
00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001430  00 00 00 00 f0 ff ff 00  00 00 00 00 00 00 00 00  |................|
00001440  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00168050  03 00 01 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00168060  03 00 02 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00168070  03 00 03 00 00 00 2e 73  79 6d 74 61 62 00 2e 73  |.......symtab..s|
00168080  74 72 74 61 62 00 2e 73  68 73 74 72 74 61 62 00  |trtab..shstrtab.|
00168090  2e 74 65 78 74 00 2e 64  61 74 61 00 2e 62 73 73  |.text..data..bss|
001680a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
001680c0  00 00 00 00 00 00 00 00  00 00 00 00 1b 00 00 00  |................|
001680d0  01 00 00 00 06 00 00 00  00 00 00 00 34 00 00 00  |............4...|
001680e0  00 80 16 00 00 00 00 00  00 00 00 00 01 00 00 00  |................|
001680f0  00 00 00 00 21 00 00 00  01 00 00 00 03 00 00 00  |....!...........|
00168100  00 00 00 00 34 80 16 00  00 00 00 00 00 00 00 00  |....4...........|
00168110  00 00 00 00 01 00 00 00  00 00 00 00 27 00 00 00  |............'...|
00168120  08 00 00 00 03 00 00 00  00 00 00 00 34 80 16 00  |............4...|
00168130  00 00 00 00 00 00 00 00  00 00 00 00 01 00 00 00  |................|
00168140  00 00 00 00 01 00 00 00  02 00 00 00 00 00 00 00  |................|
00168150  00 00 00 00 34 80 16 00  40 00 00 00 05 00 00 00  |....4...@.......|
00168160  04 00 00 00 04 00 00 00  10 00 00 00 09 00 00 00  |................|
00168170  03 00 00 00 00 00 00 00  00 00 00 00 74 80 16 00  |............t...|
00168180  01 00 00 00 00 00 00 00  00 00 00 00 01 00 00 00  |................|
00168190  00 00 00 00 11 00 00 00  03 00 00 00 00 00 00 00  |................|
001681a0  00 00 00 00 75 80 16 00  2c 00 00 00 00 00 00 00  |....u...,.......|
001681b0  00 00 00 00 01 00 00 00  00 00 00 00              |............|
001681bc

見てのとおり、アセンブラに書いた内容だけではなく、なんか余計なデータが追加されているのが分かると思う。

これは、オブジェクトファイルが生のバイナリデータではなく、ELF形式のデータになっているため。
どのメモリにロードすべきかや、シンボルの情報、デバッグ情報なんかが一緒に詰め込まれている。
(ちなみに、アセンブラに書いた内容は0x34から始まっている)

普通のプログラムであれば、OSがこれらの情報を読み取って、適切なアドレスにロードしてくれるんだけど、ここではそういったローダはいないので、生のバイナリデータの形に自前で展開してやらないといけない。

ただ、Binutilsにはobjcopyというバイナリファイルの形式を変換するツールが含まれているので、これを使うことでオブジェクトファイルを生のバイナリデータに変換することが出来る。
(※もちろん、リンクされてすべてのシンボルが解決されていないとダメ)

以下のコマンドを実行:

$ i386-elf-objcopy -O binary hello-os.o hello-os.img

-Oが出力形式を決めるためのオプションで、ここでbinaryを指定すると、生のバイナリデータに変換されて出力がされる。

出来上がったイメージファイルの内容を見てみると、以下のとおり:

$ hexdump -C hello-os.img 
00000000  eb 4e 90 48 45 4c 4c 4f  49 50 4c 00 02 01 01 00  |.N.HELLOIPL.....|
00000010  02 e0 00 40 0b f0 09 00  12 00 02 00 00 00 00 00  |...@............|
00000020  40 0b 00 00 00 00 29 ff  ff ff ff 48 45 4c 4c 4f  |@.....)....HELLO|
00000030  2d 4f 53 20 20 20 46 41  54 31 32 20 20 20 00 00  |-OS   FAT12   ..|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  b8 00 00 8e d0 bc 00 7c  8e d8 8e c0 be 74 7c 8a  |.......|.....t|.|
00000060  04 83 c6 01 3c 00 74 09  b4 0e bb 0f 00 cd 10 eb  |....<.t.........|
00000070  ee f4 eb fd 0a 0a 68 65  6c 6c 6f 2c 20 77 6f 72  |......hello, wor|
00000080  6c 64 0a 00 00 00 00 00  00 00 00 00 00 00 00 00  |ld..............|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  f0 ff ff 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001400  f0 ff ff 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00001410  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00168000

ちゃんと出来上がっているのが分かると思う。

Makefileの作成

これでとりあえずフロッピーディスクのイメージが出来たわけだけど、このコマンドを毎回打つのは面倒。
打ち間違いとかも怖いし。
(昔、ShellのTabによる補完でgcc -o hoge.c hoge.cを実行してしまって、せっかく書いたソースを空にしてしまったことがある・・・)

そこで、簡単なMakefileも用意してみた:

.PHONY: all clean do

all: hello-os.img

hello-os.img: hello-os.o
  i386-elf-objcopy -O binary $< $@

hello-os.o: hello-os.s
  i386-elf-as -o $@ $<

clean:
   -rm *.img *.o

do: hello-os.img
  qemu-system-i386 -fda $<

実行するコマンドの前にあるのは必ずタブでないといけないので、そこだけは注意。

これで、makeとすれば、イメージが作成されるし、make doとすれば、qemuが立ち上がって実行もされる。

今日はここまで!

『わかばちゃんと学ぶ Git使い方入門』を読んでみた。

ツイッターを見ていたら、社畜ちゃんで有名なビタワンさんの次のツイートが。

そういえば以前CodeIQ MAGAZINEで連載してたよなぁ、と。

知らぬ間に冊子になっていたとは。

これは読んでみたいと、自分も早速hontoで検索。
電子書籍にもなってたので、サクッとゲット出来た。
しかも、500円引きのクーポンがちょうど使えたので、1,600円くらいでw
ビタワンさんのように本屋に駆け込む必要もないし、すぐに読めるし、場所も取らないし、そのうえさらに安いとか、やはり電子書籍はいいねw

内容と感想

それはさておき、内容と読んでみての感想。

内容は、分散型バージョン管理システムの1つであるGitの使い方(そう、「使い方」)を、マンガを交えながら学んでいくものとなっている。
Gitというと何やら難しいイメージがあるけど、この本ではマンガのおかげもあって、そういった難しさは全く感じられないようになっている。
これはいいw

ツールとしては、コマンドラインベースではなく、GUISourceTreeを使っている。
しかも、操作手順をちゃんと画像を入れながら説明してくれるという親切設計w
プログラマならコマンドラインでも何も問題ないと思うけど(というか、自分は基本的にはコマンドラインXcodeからしか使わないけど)、これはコマンドに慣れていない人にすごくいいと思う。
(逆にいうと、コマンドの説明は全然ないので、コマンドで使うつもりの人はちょっと注意)

Gitを個人のバックアップツールとして使うところから始まって、複数人で使う基本的な使い方、それに、GitHubやBitbacketを使ったソーシャルコーディングまで、基本的な話はちゃんと入っている感じ。
とりあえずこれを読んで、あとは必要に応じて調べれば、一通り使えるんじゃないかな。

ただ、自分は一応Gitを知っているので、その観点での感想なのが気になるところ。
Gitを全然知らない人が、この本を読んで理解できるのかは、正直ちょっと分からない。
すごく分かりやすそうに書いているので、たぶん大丈夫だと思うんだけど、その「分かりやすそう」が本当に分かりやすいのか、マンガのせいでそう感じさせられているだけなのか、そのあたりが、すでにGitを知っている自分からは判断できなかった。

例えばだけど、「『Git』をどう読むのか」という割と典型的な部分の説明がなかったり。
「ギット」と読むわけだけど、GIF(ジフと発音されることが多い)に慣れてると、「ジット」と読んでしまってもおかしくないわけで。
(実際、自分は昔、間違えて「ジット」だと思ってた)
まぁ一応、表紙のタイトルの「Git」にそっと添えるように「ギット」と書かれていたり、初めて「Git」という単語を聞いた(主人公の)わかばちゃんが次のコマで「ギット?」というセリフを言ってたりはするけど。

そんな感じで、Gitに慣れ親しんでしまった身には当然になりすぎてしまっていて、初心者には実はよく分からないという内容が紛れ込んでしまってるんじゃないかなぁ、というのが、気になるところ。

あと、個人的に気になったところがいくつか。

マージすべきかリベースすべきかという話があるけど、その両方に触れてはいるものの、実際にどちらにすべきかについては言及していなかったり。
自分も昔はリベースすげぇとリベース大好きだったけど、次のスライドを見てからは、リベースではなくマージを行う運用を使うようにしている。

Subversionに慣れていて、branchはtrunkへマージするものという意識があったので、その逆の、trunkをbranchにマージする(Gitの場合、masterブランチをtopicブランチにマージする)という発想はかなり衝撃的だった。
ただ、このスライドのいうとおり、マージをmasterブランチ側ではなくtopicブランチ側で行うようにすれば、マージの記録が残る上に、masterブランチへの反映のタイミングでは絶対にコンフリクトが発生しないので、とてもいい。

それと、これは自分がGitHubでforkを行なったことがないからなんだけど、forkしたリポジトリでfork元のリポジトリの変更をどうやって取得するのかなぁ、と。
これについて、本では言及なし。
こういうところがあるので、最初に書いた「Gitを知らない人がホントに理解できるのか分からない」という感想も出てきたのだけど・・・
おそらく、fork元のリポジトリをremoteリポジトリとしてローカルのリポジトリに追加した後、ローカルのリポジトリにfork元のコミットをfetchしてきて、そこから自分がforkしたリポジトリにpushするのかなぁ、と思っているけど、そんなメンドイ手順が必要なんだろうか・・・?

まぁ、上記の2つは、基本というよりかは実際の運用上の問題なので、この本には書いてなくても当然という気もするけど。

何はともあれ、こうやって気軽にGitの使い方を学べるのは、とてもいいなと思った。
Gitを使える人がもっと増えるといいなw

今日はここまで!

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

わかばちゃんと学ぶ Git使い方入門〈GitHub、Bitbucket、SourceTree〉

『OS自作入門』を読んでみた。(その1)

前回、『30日でできる! OS自作入門』を読んでいることをちょこっと書いた。

30日でできる! OS自作入門

30日でできる! OS自作入門

この本では、小さなプログラムから始めて、少しずつOSっぽい機能をつけていき、最終的にはOSが出来上がるようにしている。
最初からしっかりと全体を設計して作っていくというわけではなく(もちろん、筆者の中ではやってるのかもしれないけど)、少しずつ継ぎ足し継ぎ足しでプログラムを成長させていくのが面白い。

そんな本なので、実際に手を動かしながら、自分でも動くものを作っていくのが面白いかな、と。

最初のOS?

ということで、最初のOSっぽいプログラム。
まぁ、ブートして文字列を出力するだけのプログラムなんだけどw
しかも、それをアセンブラで書くというわけではなく、イメージをバイナリエディタで作るというw

本ではBzというバイナリエディタを使っているんだけど、自分はMacなので、これは使えず。
そこで、RubyVimを使って同じバイナリイメージを作ってみた。

空データのファイルの作成

フロッピーディスクのディスクイメージを作るんだけど、そのサイズは1440KBで、しかもそのほとんどは空のデータ(0x00)。
これを全部手打ちするのは無駄なので、まずは全部0x00で埋まった1440KBのファイルを作ることにした。
そして、あとで必要な部分を修正していく。

全部0x00で埋まった1440KBのファイルは、Rubyを使ったワンライナーでサクッと。

$ ruby -e 'print "\x0" * 1440 * 1024' > hello-os.img

出来たファイルの中身を見てみると、次のような感じ:

$ hexdump -C hello-os.img
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00168000

1440Kは1474560(=1440x1024)で、これを16進数にすると0x168000なので、これでOK。

Vimを使ったバイナリファイルの編集

空データのファイルは出来たので、あとはこれをVimで編集していく。

Vimでバイナリファイルを編集する場合、-bオプションをつけて起動する:

$ vi -b hello-os.img

起動すると、こんな感じ:

f:id:yamaimo0625:20170422161403p:plain

^@(=0x00)がたくさん並んでいるのが分かると思う。

このままではさすがに編集できないので、編集しやすいようにする。
そのとき使うのが、xxdというコマンド。
このコマンドは、バイナリデータを見やすい16進数表示のテキストに変換してくれたり、逆に、16進数表示のテキストをバイナリデータに変換してくれたりする。

exモードで、以下を実行:

:%!xxd -c 16 -g 1

すると、こんな表示になる:

f:id:yamaimo0625:20170422162012p:plain

ちなみに、-c 16 -g 1はオプションで、なくてもOK。
-cは1行に何バイトずつ表示させるかを指定するオプションで、-gは1列に何バイトずつ表示するのかを指定するオプションになっている。
デフォルトだと1列に2バイトずつ表示され、リトルエンディアンなのかビッグエンディアンなのか分からず戸惑ったので、1列には1バイトずつ表示するようにしている。
(ちなみに、デフォルトだとビッグエンディアンなので、例えば0102 0304 ...と表示されていたら、メモリ上も0x01 0x02 0x03 0x04 ...とデータは並んでいる)

この状態で、バイト列の16進数を本に書かれた通りに修正していく。
これは、テキストファイルを修正しているだけなので、普通に編集すればいい。
すると、以下のような感じ:

f:id:yamaimo0625:20170422162910p:plain

あとは、このテキストファイルをバイナリデータとして書き戻してやるだけ。
それには、xxdコマンドに-rオプションをつけて実行すればいい。

ということで、exモードで以下を実行:

:%!xxd -r -c 16 -g 1

すると、こんな感じ:

f:id:yamaimo0625:20170422163401p:plain

データが書き換わっているのが分かると思う。

保存して中身を確認してみると、次のようになっている:

$ hexdump -C hello-os.img
00000000  eb 4e 90 48 45 4c 4c 4f  49 50 4c 00 02 01 01 00  |.N.HELLOIPL.....|
00000010  02 e0 00 40 0b f0 09 00  12 00 02 00 00 00 00 00  |...@............|
00000020  40 0b 00 00 00 00 29 ff  ff ff ff 48 45 4c 4c 4f  |@.....)....HELLO|
00000030  2d 4f 53 20 20 20 46 41  54 31 32 20 20 20 00 00  |-OS   FAT12   ..|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000050  b8 00 00 8e d0 bc 00 7c  8e d8 8e c0 be 74 7c 8a  |.......|.....t|.|
00000060  04 83 c6 01 3c 00 74 09  b4 0e bb 0f 00 cd 10 eb  |....<.t.........|
00000070  ee f4 eb fd 0a 0a 68 65  6c 6c 6f 2c 20 77 6f 72  |......hello, wor|
00000080  6c 64 0a 00 00 00 00 00  00 00 00 00 00 00 00 00  |ld..............|
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200  f0 ff ff 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001400  f0 ff ff 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00001410  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00168000

これでイメージは完成。

動作確認

イメージが完成したので、さっそく動作確認。
前回QEMUをビルドしてあるので、そのQEMUを使って起動してみた。

$ qemu-system-i386 -fda hello-os.img 

なお、hello-os.imgはフロッピーディスクのイメージなので、-fdaオプションを指定している。

起動すると、以下のような感じ:

f:id:yamaimo0625:20170422164442p:plain

OS?が起動して、"hello, world"が表示されているのが分かると思う。

今日はここまで!

30日でできる! OS自作入門

30日でできる! OS自作入門

MacでQEMUのビルドをしてみた。

最近、『30日でできる! OS自作入門』を読んでる。

この本自体はだいぶ昔に買っていたんだけど、分厚いので完全に積読になってた。
ただ、毎度おなじみのhontoで検索してみたら、電子書籍版が出てて、これなら手軽に読めるなとポチり。
ちょうどキャンペーンをやっていたので、かなりお得だったし。

で、この本ではPC/AT互換機で動くOSを実際に作っていくんだけど、使っているのはMacだし、フロッピーディスクからの起動を想定しているので、実機を用意するのはちょっと面倒。
ということで、仮想環境で試してみようかなと。

Macで使える仮想環境としては、QEMUの他にも、無料のVirtualBoxや、有料のParallels DesktopVMware Fusionなどもある。
ただ、仕事で今後QEMUと関わってくる機会が増えそうなので、せっかくだからQEMUをインストールしてみることにした。

大まかな流れ

QEMUの公式ページを見てみると、Macの場合はHomebrewを使えば簡単にインストール出来るみたい。
ただ、せっかくなので、ソースからビルドしてみようかなと。
ページを見る限り、普通に./configureしてmakeすればいいだけのようだったから。

ただ、当然というか、実際にはこんな簡単にはいかなくて。

具体的には、以下のような手順が必要だった:

  1. autotoolsのビルド
    1. autoconfのビルド
    2. automakeのビルド
    3. libtoolsのビルド
  2. pkg-configのビルド
  3. glibのビルド
    1. libffiのビルド
    2. gettextのビルド
    3. libpcreのビルド
    4. glibのビルド
  4. QEMUのビルド

すごく大変だった・・・

autotoolsのビルド

まずはautotoolsのビルドから。

UNIX系だと、ビルドするときにtarボールをダウンロードしてきて解凍し、./configureしてmakeするのが定番だけど、この仕組みを支えているのがautotools。
具体的には、このconfigureスクリプトを設定ファイルから生成してくれたりする。

もちろん、普通は生成済みのconfigureスクリプトがtarボールには入っているので、このautotoolsを普通のユーザが使うことは基本的にはない。
けど、QEMUのGitリポジトリの場合、その下に他のGitリポジトリをサブモジュールとして取り込んでいるようなので、そのサブのリポジトリでのconfigureスクリプトを生成するのに必要っぽい。

ちなみに、autotoolsにもGitリポジトリはあるんだけど、configureスクリプトは入ってない。
じゃあ、どうやってビルドするのかといえば、autotoolsを使ってconfigureスクリプトを作るw
卵が先か、鶏が先かw

まぁ、こういう開発ツールの根幹になるツールには、よくあること。
Cコンパイラとかもそうだし。

ということで、素直にtarボールをダウンロードしてきて、ビルドする。

autoconf

まずはautoconfから。

Autoconf - GNU Project - Free Software Foundation

FTPからtarボールをダウンロードしてきて、普通にビルド。

$ tar zxvf autoconf-2.69.tar.gz
$ cd autoconf-2.69
$ ./configure
$ make
$ sudo make install

automake

続いて、automake。

Automake - GNU Project - Free Software Foundation

これも同じ。

$ tar zxvf automake-1.15.tar.gz
$ cd automake-1.15
$ ./configure
$ make
$ sudo make install

libtools

最後にlibtools

GNU Libtool - GNU Project - Free Software Foundation

$ tar zxvf libtool-2.4.6.tar.gz
$ cd libtool-2.4.6
$ ./configure
$ make
$ sudo make install

簡単w

pkg-configのビルド

autotoolsのビルドが出来たら、次はpkg-configのビルド。

pkg-config

このツールは、configureスクリプトを走らせときに、ライブラリの情報を得るのに使われるツール。

ただ、実はここでも循環した依存関係が存在していて、pkg-configを動かすには後述のglibが必要なんだけど、glibのビルドにはpkg-configが必要というw

この循環依存を断ち切る一つの方法としては、あらかじめビルドされたglibをインストールしておいて、それでpkg-configをビルドするという方法が考えられる。
ただ、それでは面倒なので、pkg-configのtarボールの中には、最近の安定版のglibのコピー(のおそらく一部だけ)が入っていて、configureで指定すれば、このglibを使ってビルドが出来るようになっている。

tarボールをダウンロードしてきたら、以下のようにすればいい:

$ tar zxvf pkg-config-0.29.2.tar.gz
$ cd pkg-config-0.29.2
$ ./configure --with-internal-glib
$ make
$ sudo make install

これでOK。

ちなみに、QEMUのビルドではこうやってビルドしたpkg-configで十分なんだけど、もし後からインストールしたglibを使うようにしたいなら、--with-internal-glibの指定を外して、もう一回ビルドし直した方がいいのかもしれない。
GCCのビルドで、まず最小限のGCCを作った後、そのGCCでCライブラリを作った後、フルのGCCを作るというのに似てるかも)
(動的リンクなら大丈夫?)

glibのビルド

次はglibのビルド。

正直、これが一番大変だった・・・
というのも、依存しているライブラリが多いから。

glibはGTK+ツールキットの根っことなる機能を提供しているライブラリで、CocoaでいうFoundationフレームワークのようなもの。(のはず)
そんな根っことなるライブラリが、他のいろいろなライブラリに依存してるのもどうなんだと思うんだけど・・・

libffiのビルド

まずはlibffiのビルドから。

libffi

libffiは、ある言語から他の言語で書かれたライブラリを呼び出したりするのに使われるライブラリ。

ビルドは普通。

$ tar zxvf libffi-3.2.1.tar.gz
$ cd libffi-3.2.1
$ ./configure
$ make
$ sudo make install

gettextのビルド

続いて、gettextのビルド。

gettext - GNU Project - Free Software Foundation (FSF)

gettextは多言語化に使われるライブラリ。

これもビルドは普通。

$ tar zxvf gettext-0.19.8.1.tar.gz
$ cd gettext-0.19.8.1
$ ./configure
$ make
$ sudo make install

libpcreのビルド

次はlibpcreのビルド。

これはPerl正規表現と同じ文法の正規表現を提供するライブラリ。
なんでこんなのが必要なんだろう・・・

このビルドは以下のとおり:

$ tar zxvf pcre-8.40.tar.gz
$ cd pcre-8.40
$ ./configure --enable-unicode-properties
$ make
$ sudo make install

気をつけないといけないのが、configureスクリプト--enable-unicode-propertiesというオプションを指定していること。

最初、configureスクリプトのヘルプを見て、--enable-utfというオプションはつけてビルドしたんだけど(これがないとUTF8/16/32のサポートも有効にならない)、それだけだと不足で、glibのビルドに失敗した。
--enable-unicode-propertiesというオプションをつけておけば、--enable-utfも有効になり、glibのビルドも問題なくなる。

glibのビルド

ここまでやって、やっとglibのビルド。

まず、glibのtarボールを落とすのが大変w
もちろん、Gitリポジトリをcloneしてビルドしてもいいんだけど、configureスクリプトが入ってないので、ちょっと面倒。

自分は以下のFTPから落としてきた:

https://ftp.gnome.org/pub/gnome/sources/glib/2.52/

ビルドは以下のとおり:

$ tar Jxvf glib-2.52.1.tar.xz
$ cd glib-2.52.1
$ CFLAGS="-I/usr/local/include -L/usr/local/lib" ./configure
$ make
$ sudo make install

ちなみに、configureの前でCFLAGSを指定しているのは、こうしないとgettextの提供するヘッダファイルとライブラリをなぜか見つけられなかったから。

長かったけど、これでやっとglibのビルドが完了。

QEMUのビルド

残すはQEMUのビルドのみ。

まずは、QEMUのGitリポジトリをローカルにcloneしてくる:

$ git clone git://git.qemu-project.org/qemu.git
$ cd qemu
$ git submodule init
$ git submodule update --recursive

前述したとおり、QEMUのGitリポジトリは、その下に他のGitリポジトリをサブモジュールとして取り込んでいるので、その初期化とアップデートも行なっている。

これであとは./configureしてmakeすれば終わり・・・ならよかったんだけど、そうは問屋が卸さず。

Macの場合、pixmanというサブモジュールに問題があるらしく、makeすると以下のエラーが出てしまった:

pixman-mmx.c:100:20: error: constraint 'K' expects an integer constant expression

調べて見ると、以下のスレッドで議論がされていて、よく分からないけど、なんとなく新しいバージョンにすれば直ってそう。

The Pixman October 2015 Archive by thread

ということで、pixmanを0.33.6のブランチに切り替えてみた。

$ git checkout topic/local_bugfix   # 適当な名前でバグフィクス用のブランチを用意
$ cd pixman
$ git checkout pixman-0.33.6
$ cd ..
$ git add pixman
$ git commit
$ git submodule update

そのあと、./configuremake

これで先ほどのエラーは出なくなったんだけど、これでも以下のエラーが出た:

Undefined symbols for architecture x86_64:
  "_prng_state", referenced from:
      _main in region-test.o
  "_prng_state_data", referenced from:
      _main in region-test.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

ただ、これは調べてみるとテストコードの問題らしく、とりあえず実害はないっぽい。
なので、エラーが起きた後にtouchコマンドで仮のファイルを作ってやれば、ビルドがスキップされて大丈夫とのこと。
(なぜかエラーが起きる前にtouchコマンドを使うとファイルが削除されてしまったので、エラーが起きた後にやった方が確実かもしれない)

$ touch pixman/test/region-test
$ touch pixman/test/scaling-helpers-test

(参考: Qemu 2.3.0 released! - Fun with virtualizationFun with virtualization

これでQEMUのビルドも完了!

ちなみに、デフォルトの設定でビルドすると、全部のアーキテクチャがビルドされる。
なので、特定のアーキテクチャだけビルドしたい場合には、configureスクリプト--target-list=LISTオプションを指定してやるといい。
(LISTをビルドしたいアーキテクチャにする)

利用可能なアーキテクチャは、./configure --helpをやれば見ることが出来る:

$ ./configure --help

Usage: configure [options]

(省略)

  --target-list=LIST       set target list (default: build everything)
                           Available targets: aarch64-softmmu alpha-softmmu 
                           arm-softmmu cris-softmmu i386-softmmu lm32-softmmu 
                           m68k-softmmu microblaze-softmmu microblazeel-softmmu 
                           mips-softmmu mips64-softmmu mips64el-softmmu 
                           mipsel-softmmu moxie-softmmu nios2-softmmu 
                           or1k-softmmu ppc-softmmu ppc64-softmmu 
                           ppcemb-softmmu s390x-softmmu sh4-softmmu 
                           sh4eb-softmmu sparc-softmmu sparc64-softmmu 
                           tricore-softmmu unicore32-softmmu x86_64-softmmu 
                           xtensa-softmmu xtensaeb-softmmu

(以下略)

動作確認

これでやっとQEMUのビルドも終わったので、動作確認をしたいところ。

以下のページでテスト用のイメージがいくつか用意されていた:

Testing/System Images - QEMU

なので、それを使って動作確認してみた:

とりあえずlinux-0.2.img.bz2というイメージをダウンロードしてきて解凍し、以下のようにして動作確認:

$ qemu-system-i386 linux-0.2.img

すると、次のような画面が現れる:

f:id:yamaimo0625:20170417000323p:plain

これで問題なく動作してることが確認できた。

ちなみに、ウィンドウ内をクリックするとマウスの制御がゲスト側に取られてしまうけど、Ctrl+Alt(Macの場合、Ctrl+Option)を押すことで、マウスの制御はホスト側に戻ってきてくれる。
終わらせるときは、メニューから終了を選べばOK。

今日はここまで!

手帳ネクロで遊んでみた。

またまたシャドウバースの話w

3月末に新カードパックの「神々の騒嵐」がリリースされて、環境もガラッと変わって面白いことになってる。

アグネクの活躍

特に驚いたのが、アグネク(アグロネクロ)の活躍。

リリース直前は、ドラゴンに「ライトニングブラスト」とかいうネクロ殺しのカードが追加されることが発表され、それに対してネクロ勢が最後の最後に期待していたシルバーレアのカードが「骨の貴公子」というかなり地味な印象のカードだったので、もうお葬式も同然の空気だった。
これはもう新カードパックがリリースされたら、ネクロは息してないんじゃないかな、と多くの人が思ってた。

が、蓋を開けてみれば、アグネクが環境で一番使われているというw
その原因は、何を隠そう、かなり地味な印象だった「骨の貴公子」の活躍で、このカードのおかげで盤面にフォロワーが残りやすくなって、バフを効かせて殴りにいったり、息切れせずに攻めが続くようになった。
「ゾンビパーティ」「破魂の少女」「骨の貴公子」「オルトロス」といった、書かれていることは確かに弱くはないんだけど、他のクラスに追加された派手で強力なカードと比べると一段も二段も見劣りするような追加カードたちが、恐ろしいまでのシナジーを発揮して、アグロデッキとして強烈なまでの破壊力、戦闘継続能力を発揮するようになっている。
(だが、「魂の番人・ミント」、お前はダメだ・・・可愛いのに・・・)

手帳ネクロ

さて、そんな環境トップで活躍しているアグネクはさておき、自分がよく使って遊んでいるのが、手帳ネクロというデッキ。

これは、やはり新カードパックで追加された「死神の手帳」というカードを軸にしたミドルレンジ〜コントロール寄りのデッキで、かなり面白い動きをするw
勝てるかは別としてw

f:id:yamaimo0625:20170406233615p:plain

「死神の手帳」の効果は、ターンの終わりに、今のPPよりコストの低いネクロマンサーのフォロワーを自分のデッキからランダムに1体出して、それを破壊する、というもの。
それが2ターンほど続く。
フォロワーを出してもすぐに破壊されてしまうんじゃ、意味なさそうだけど、ネクロマンサーのフォロワーはラストワード持ちーーすなわち、破壊されたときに能力を発揮するフォロワーがいるので、その効果を引き出すことが出来る。
もちろん、そういうフォロワーが引けるようにしておかないといけないので、構築には少し工夫が必要だけど。

ということで、組んでみたのが、次のデッキ。

ネクロマンサーのフォロワーは、「闇の従者」「地獄の解放者」「デュエリスト・モルディカイ」に絞ってあって、死神の手帳では基本的に「闇の従者」か「地獄の解放者」が引かれるようになっている。
この2つのフォロワーは、破壊されると「リッチ」という4/4(攻撃力4、体力4ということ)のフォロワーを出すので、なかなか強い。
(ちなみに、「デュエリスト・モルディカイ」は、破壊されると「デュエリスト・モルディカイ」を出す。つまり、消滅させられない限り、ずっと残るw)

あとポイントとなるのが、「ウリエル」。
このカードはアミュレットをデッキから手札に引っ張ってきてくれるので、これで「死神の手帳」を確定で手に入れることが出来る。
なので、結構な確率で「死神の手帳」をプレイできるようになっている。

プレイしてみて

ちなみに、プレイしてみると、「死神の手帳」を出す瞬間がめちゃくちゃ弱いw
最速で4ターン目だけど、そこはもう進化が可能になっているターンなので、進化を使って盤面の取り合いが行われるのが普通なんだけど、そこで進化を使えないでただ4/4のフォロワーを出すだけだから、ホントに弱い(^^;

けど、その分、次のターンに強い動きが出来るというのがかなり面白い。
そのターンのPPを使い切った上で、無料で4/4のフォロワーが追加で出てくるわけで、実質+4PPの動きが出来ている。
このおかげで、一度は盤面を取られても、取り返してさらに「リッチ」を場に並べるなんてことも可能。

例えば、こんな盤面になったりするw

f:id:yamaimo0625:20170407003054p:plain

f:id:yamaimo0625:20170407003103p:plain

これは楽しいw

あと、「死神の手帳」はフォロワーを破壊をしてくれるので、墓地が増えるというのも嬉しかったり。
ビショップ相手だと、消滅させられて墓地が増えず、結果、「ファントムハウル」や「死の祝福」といった、墓地を使って強力な効果を発揮するカードが使えなかったりすることが多いのだけど、この手帳ネクロなら、墓地がちゃんと増えてくれるので、これらのカードを有効に活用できたり。
それに、消滅させられるのは体力3以下のフォロワーであることが多いので、体力が4あるリッチは消滅させられにくいというメリットもあったりする。

さらには、デッキからフォロワーを召喚して破壊するので、デッキの圧縮にもなっているのが嬉しいところ。
デッキの枚数が減れば、それだけ欲しいカードの引ける確率も上がってくる。

そんななかなか面白いデッキなんだけど、弱点も。

まず、相手を指定せずに除去を行うカードがない。
なので、潜伏を使ったデッキ(特に「旅ガエル」デッキ)には、めっぽう弱い。
一応、構築で「よろめく不死者」とかを入れれば、対処は出来なくはないんだけど、「死神の手帳」で出る効果がランダムになってしまって、狙った効果が出ないとかなりキツい。

次に、どうしても速度が遅いので、下手すればアグネクに轢き殺される(^^;
特に、後攻になってしまうとかなりツラい。

さらに、今アグネクとトップを争っているドラゴンに対しても、ターンが遅くなってくれば強力なカードを持つドラゴンが圧倒的に強くなってくるので、かなり厳しい。
特に、「ライトニングブラスト」を打たれると、リッチ軍団もモルディカイも死神の手帳それ自体も消滅させられてしまうので、もう無理。

そんな感じで、決して弱いわけではないんだけど、今の環境ではなかなか勝てない感じではある・・・
楽しくはあるんだけど。


まぁ、なにはともあれ、「リッチ」を並べて盤面を圧倒するというのは、実現できればかなり気持ちがいいので、ぜひお試しあれ。

今日はここまで!

シャドウバース (Shadowverse)

シャドウバース (Shadowverse)

  • Cygames, Inc.
  • ゲーム
  • 無料