○バイナリエディタを使おう!
何はともあれ、まずはバイナリエディタの用意です。
Linuxで使えるバイナリエディタは
・hex
・hi
・bvi
・GHex
等々たくさんあるようですが、今回は俺の好み(?)で
bviを採用します。
bviとは、viライクのバイナリエディタです。
Linuxをご存じの皆さんには、viの説明は要りませんね。
操作は基本的にviと同じです。ただし、
書き込み操作の前には:set memmoveが必要です。
俺は一応ながらvimerの端くれです。たぶん。
:wq、:q!、a、i、r、xくらいしか使わないので、あとのことは知りません。
まずはbviをインストールします。当方の環境はLinux Mint 11です。
$ sudo apt-get install bvi
初期設定では、編集画面の横幅が16バイトになっておらず、
とても見づらいので設定します。
$ vi ~/.bvirc
(~/.bvircの内容)
set cm=16
set memmove
bviもvi同様、ホームフォルダの.bvircに書き込めば設定できます。
cmは一行に表示されるバイト数です。16にします。
さらに、.bvircでmemmoveをセットしておけば、編集時に入力する必要がなく、
非常に助かります。
○OSを作ろう!
続いて、自作本通り0x168000バイトを手で入力しましょう^^;
完成図
ちゃんと最後まで入力したんですよ
と言いたいところですが、ハッキリ言って俺には0x168000バイトも手で入力する
根気もありませんし、たとえセロテープで「0」キーをはりつけたとしても、
入力が終わるまで待つ忍耐力はありません。
チートします。
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv) {
FILE *fp;
char null[1] = "\0";
// open file
if(!(fp = fopen(argv[1], "ab"))) {
printf("Error to open file.\n");
return 0;
}
long pos, max = 0xFF << 1;
// get file size
pos = ftell( fp );
if( argc > 2 ) {
max = atoi( argv[2] );
}
// write null data
printf("Fill %ld to %ld\n", pos, max);
int i;
for( i = pos; i < max; i++ ) {
fwrite( null, 1, 1, fp );
}
printf("Succeeded!\n");
return 0;
}
これをコンパイルします。ソースの解説は省略。。。
$ gcc -o fat fat.c
$ ./fat helloos.img 1474560
Fill xxx to 1474560
Suceeded!
あ、ソースファイルの名前はfat.cにしておきました。こういうファイル肥大化ソフトは
fatって名前のことが多い気がします。
helloos.imgは、あのバイナリです。
0x001400辺りを過ぎるとすべて00になるので、そこまでは手入力して
あとはfatを使って残りを0x168000まですべて00で自動で埋めます。
ちなみに、1474560は何かというと、0x168000の10進数表記です。
$ python
>>> 0x168000
1474560
で調べました。python便利。
本来は、この程度はC言語じゃなくてスクリプト言語を使うべきなんでしょうが、
まともに使えるのがC言語くらいしかないので…(汗
さて、無事にバイナリイメージができたので、起動します。
そうか、QEMUの準備か。
○QEMUを使おう!
とりあえずインストールしましょう。
$ sudo apt-get install qemu-kvm
$ qemu -fda helloos.img
無事、起動できました。
○GASでアセンブルしてみよう!
まずは、nask用に書かれたソースをGAS用に直します。
.code16
.globl _start
_start:
.byte 0xeb, 0x4e, 0x90
.ascii "HELLOIPL"
.word 512
.byte 1
.word 1
.byte 2
.word 224
.word 2880
.byte 0xf0
.word 9
.word 18
.word 2
.int 0
.int 2880
.byte 0, 0, 0x29
.int 0xffffffff
.ascii "HELLO-OS "
.ascii "FAT12 "
.skip 18, 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
.byte 0x0a, 0x0a
.ascii "hello, world"
.byte 0x0a
.byte 0
.org 0x1fe, 0x00
.byte 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
naskとの対応は以下のようになります。
DB -> .byte
DW -> .word
DD -> .int
また、.asciiは文字列を置くときに使います。機能的には.byteと同じです。
.skipは
.skip [バイト数], [データ]と使う事で、指定したデータで指定バイト数だけ埋めます。
そのほかの説明は省略します。
これをアセンブルします。アセンブラはGCC付属のasを使います。
ところが、GCCは自動的にELFフォーマットで出力するので、
これをバイナリ出力にするために、リンカスクリプトを書きます。
$ vi lnk.ls
(lnk.lsの内容)
OUTPUT_FORMAT("binary")
リンカスクリプトとは、GCCでコンパイルするときに読み込むと、
バイナリレベルでいろいろと弄ることのできる設定ファイルみたいなものです。
OUTPUT_FORMAT("binary")で、ELFではなくバイナリをそのまま吐きます。
では、コンパイルしましょう。
$ gcc -nostdlib -o os.img temp.s -Tlnk.ls
-nostdlibオプションは、標準ライブラリをリンクしないという意味です。
今回は、temp.sという名前で保存したソースから、os.imgというバイナリを得ます。
-Tオプションでリンカスクリプトを指定します。
このように、アセンブリに移行することができました。
これでアセンブリが使えるようになりました。
1日目はこれくらいで終了ー。
何か間違いやご要望等がありましたら、遠慮なくご指摘お願いします。
PR
COMMENT