ここんとこアセンブリばっかりやってる訳ですが、プログラム全体を大きな塊として見てみると、分からないとこはないのだが、レジスタの使い方とか割り込みとか、その他もろもろについてちゃんと理解してなかったら、ほんとの意味で分かってないし、それだとアセンブリ言語をやってる意味がないんじゃないかな~と思ったわけだ。
30日でできるOS自作入門をやっているとその辺りをひしひしと感じるのね。そして、あんまり分からないから全然面白くない。
まえふり
まずは過去を振り返ってみる。
最初にアセンブリ言語に取り組んだときに作ったのが、Hello Worldを表示させるプログラム。
<strong>.global main
main:
mov $1, %ebx
mov $4, %eax
mov $message, %ecx
mov $15, %edx
int $0x80
mov $100, %eax
mov $100, %ebx
cmp %eax, %ebx
je hello
end:
mov $1, %eax
int $0x80
hello:
mov $1, %ebx
mov $4, %eax
mov $messages_2, %ecx
mov $15, %edx
int $0x80
jmp end
.data
message: .ascii "Hello, World!!\n"
messages_2: .ascii "Goog evening!!\n"
面白くないことはやりたくない!という事で、アセンブリ言語の基本からやるぞと。まずはやっぱり計算機だから基本的なこととなると足し算、引き算だ!と思ってマニュアル的なものを探そうとググったんだけど、・・・ない。
アスキーコードでAを表示しましょう系はよくあるんだけど、1+1=2をやってみようというサイトは意外にもぜんぜん出てこない。
ないなら自分で・・と自分で作ってみてもやっぱりうまくいかないので、やっぱりちゃんとわかってなかった事はよく分かった。
Hello Worldはできても足し算ができないのはダメだ。ダメだ。全然ダメだ。
いろいろ巡って簡単な足し算をするプログラムを書いているサイトをやっとこさ見つけたんだけど、イメージはできるんだけど、根本的なところはやっぱり理解できないでいた。
どういう事かというと、PUSHとPOP、システムコールの使い方だ。
となれば話は簡単でやはり基礎からやらないといけない。
何回同じことを書くんだ(笑)。
レジスタってなんぞ
レジスタとはCPUの中のほにゃらら~(ry な事とかよりもどう使うんだという事が重要だと思うんでそこだけやろうと思います。
少量しかないって事を考えると、もっと載せたらいいやんということになるんで、でも増えるわけないし、どうしようもないのでやりません。
とにかくちょっとだけしかないんだよ。
参考サイト
KENJI’S HOMEPAGE 「アセンブリ言語の教科書」の原稿
インプレス社 INT 21Hファンクション
目指せプログラマー アセンブラ入門
数回目の登場ですが、KENJI’S Homepageさんのサイトは事あるごとに登場してますね。ありがたいことです。
サーバー構築をひたすらやってた頃の、CentOSで自宅サーバー構築 さんみたいなもんだ。
まずはDOSでやると分かりやすそうだったんで、VMで昔のWindowsを立ち上げてちょこっとやってみました。
Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-2000 Microsoft Corp.
C:\Documents and Settings\Administrator>DEBUG
マイクロソフトかな漢字変換 バージョン 2.51
(C)Copyright Microsoft Corp. 1992-1993
-A 0100
2C9B:0100 MOV AX,50
2C9B:0103
-G=0100 0103
AX=0050 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=2C9B ES=2C9B SS=2C9B CS=2C9B IP=0103 NV UP EI PL NZ NA PO NC
2C9B:0103 0000 ADD [BX+SI],AL DS:0000=CD
簡単に補足すると、DOS窓を立ち上げてDEBUGと打つと16BITモードとなり、アセンブリが入力できるようになるらしい。
COMは0100オクテットかららしいので、まずはA0100を入れてます。
すると任意のアドレスが表示されて、入力モード?となります。
左側の2C98は番地で右側がオクテットです。
最後に空行でエンターして、最後にG=0100 0103でそのアドレス間を実行しなさいという事になるようです。
この辺は簡単やね。
そして画面の下を注目してみると、これはレジスタたちが表示されてるよと。どのレジストに何が入っているのか分かるので、こうしてみると非常に分かりやすそうです。
パッと見たときにこの表示があったので、まずはDOSでやることを選択しました。
名前ってのはそれほど重要ではないと思うけど、重要だとも思うので、各レジスタの説明についても書いてかな。
(だいたいWikipediaから引用)
レジスタは大きく分けて、汎用レジスタ、セグメントレジスタ、フラグ、命令ポインタという4個に分類される。
1行目は汎用レジスタになっとるのよ。
AX :アキュムレータレジスタ。算術演算操作の結果が格納される。
BX :ベースレジスタ。セグメントモードでのDS(後述)に格納されたデータを指し示すために使用される。
CX :カウンタレジスタ。シフトローテート命令とループ命令に使用される。DX :データレジスタ。算術演算操作とI/O操作に使用される。
SP :スタックポインターレジスタ。スタックのトップを指し示すポインタ。
BP :スタックベースポインタレジスタ。スタックのベースを指し示すのに使用される
SI :ソースレジスタ。ストリーム操作でのソースへのポインタとして使用される。
DI :デスティネーションレジスタ。ストリーム操作でのデスティネーションへのポインタとして使用される。
てな感じです。あとのレジスタはぼちぼちやろう。
加算・減算・乗算・除算やら、排他的なんやらとかは問題ない。
原理は分かってる(はず)だし。
DOS窓だと、レジスタの状態が分かりやすいのでなかなかいいね。
やっぱりボトルネックは割り込みだ。
システムコールとレジスタ
システムコールの話になります。
マニュアルをちゃんと見てなかったたけけんが悪いんだけど、レジスタの解釈を間違えてました。
たとえばこんなコード場合は
mov $1, %ebx mov $4, %eax mov $message, %ecx mov $15, %edxint$0x80
eax = システムコール番号 ebx = 第1引数 ecx = 第2引数 edx = 第3引数 int $0x80
という事らしいね。
入門サイトを読んでても(ちゃんと読んでなかったのかもしれないが・・)
割り込みする時は汎用レジスタに大きな役割が出来るってことが書いてないので
Writeが4、Exitが1とかはレジスタの事は考えないで
全部コールしてるだけと思い込んでた。この思い込みが混乱の元凶だったようだ。
だから↑のソースだと、eaxが4なので、Writeをコール。あとのebx、ecx、edxは引数だったらしい。
1行目でなぜExitしてるのか疑問に思わなかったのも相当痛いのだが。
ついでにこれもね(笑)
cat /usr/include/asm/unistd_32.h | grep " 15$"
#define __NR_chmod 15
少なくとも参考サイトにはさらっと書いてあったので、ちゃんと読んでなかったみたいだが、読んでなかったというよりも、やっぱりExitをコールしてると思い込んでたのがいけなかった。
ただたけけんはこの事をフォントを大にして言いたいのでMAXで書いた。
これで疑問に思ってたことは90%は解決したので、次回はPUSHとPOP、スタックとかをやろうと思います。
じゃあの。