
■ コードファイル説明1 ■
前回は簡単な関数を呼出すプログラムを作成し、新しくコンパ
イラオプション「-cod」を付けてコードファイルを作成してみ
ました。
以下にC言語で作成した簡単なプログラム「func1.c」を示し
ます。
─↓ここから──────────────────────
#include <stdio.h>
void main(void);
void sub(void);
void main()
{
_asm{
call near ptr sub
}
}
void sub()
{
_asm{
}
}
─↑ここまで──────────────────────
これをビルド&実行しても何も目立った処理は行なわれません
が、あえてこの様な無意味なプログラムを作成しました。
このプログラムを新しいコンパイラオプションを付けてビルド
してみます。
sc func1.c -j -cod
 ̄ ̄
↑
新しいコンパイラオプション
これにより新しく「func1.cod」というファイルが出来る事は
前回説明しました。
「func1.cod」の中身を以下に示します。
─↓ここから──────────────────────
_TEXT segment dword use32 public 'CODE' ;size is 13
_TEXT ends
_DATA segment dword use32 public 'DATA' ;size is 0
_DATA ends
CONST segment dword use32 public 'CONST' ;size is 0
CONST ends
_BSS segment dword use32 public 'BSS' ;size is 0
_BSS ends
FLAT group
includelib SNN.lib
extrn __acrtused_con
public _main
public _sub
_TEXT segment
assume CS:_TEXT
_main:
push EBX
push ESI
push EDI
call near ptr _sub
pop EDI
pop ESI
pop EBX
ret
_sub:
ret
_TEXT ends
_DATA segment
_DATA ends
CONST segment
CONST ends
_BSS segment
_BSS ends
end
─↑ここまで──────────────────────
初めて見る方にとっては、一見難しく感じると思います。
しかし、1つ1つじっくり見ていくとそれほど難しい物ではな
い事が分かります。
メールヘッダを見るよりは簡単だと思います。
上記の表現だと少し分かりにくいので、分かりやすくする為に
分割して表現してみます。
分割した物はそれぞれ罫線で囲み、1つ1つに簡単な説明も付
けておきました。
それでは以下をご覧ください。
─↓ここから──────────────────────
●領域の「宣言」
┌────────────────────────────┐
│_TEXT segment dword use32 public 'CODE' ;size is 13 │
│_TEXT ends │
│_DATA segment dword use32 public 'DATA' ;size is 0 │
│_DATA ends │
│CONST segment dword use32 public 'CONST' ;size is 0 │
│CONST ends │
│_BSS segment dword use32 public 'BSS' ;size is 0 │
│_BSS ends │
└────────────────────────────┘
●領域を「1つにまとめる」指定
┌────────────────────────────┐
│FLAT group │
└────────────────────────────┘
●「ライブラリ(便利な機能の集まり)」指定
┌────────────────────────────┐
│includelib SNN.lib │
│ extrn __acrtused_con │
└────────────────────────────┘
●「関数」の「宣言」
┌────────────────────────────┐
│ public _main │
│ public _sub │
└────────────────────────────┘
●プログラムコード領域の実体定義
┌────────────────────────────┐
│_TEXT segment │
│ assume CS:_TEXT │
│_main: │
│ push EBX │
│ push ESI │
│ push EDI │
│ call near ptr _sub │
│ pop EDI │
│ pop ESI │
│ pop EBX │
│ ret │
│_sub: │
│ ret │
│_TEXT ends │
└────────────────────────────┘
●その他領域の実体定義
┌────────────────────────────┐
│_DATA segment │
│_DATA ends │
│CONST segment │
│CONST ends │
│_BSS segment │
│_BSS ends │
└────────────────────────────┘
●終了
┌────────────────────────────┐
│ end │
└────────────────────────────┘
─↑ここまで──────────────────────
まず、1番最初の部分を見てみます。
●領域の「宣言」
┌────────────────────────────┐
│_TEXT segment dword use32 public 'CODE' ;size is 13 │
│_TEXT ends │
│_DATA segment dword use32 public 'DATA' ;size is 0 │
│_DATA ends │
│CONST segment dword use32 public 'CONST' ;size is 0 │
│CONST ends │
│_BSS segment dword use32 public 'BSS' ;size is 0 │
│_BSS ends │
└────────────────────────────┘
この中の1番最初の2行、
_TEXT segment dword use32 public 'CODE' ;size is 13
_TEXT ends
これはメモリ領域の「宣言」です。
アセンブラはこれを見てこのアプリケーションはどんなメモリ
領域を使用するのかを知ります。
ここでは1番右側に「'CODE'」というのが付いているので「コ
ード領域」の宣言である事が分かります。
通常、コード領域にはプログラムの実行コードが入り、読み出
す事と実行は出来ますが、書き込む事は出来ないようになって
います。
また「use32」というのが付いているので、アセンブラはこの
領域には32ビットモードで実行出来るように機械語コードを
出力します。
「use16」と記述がしてあればアセンブラはこの領域には16
ビットモードで実行出来るように機械語コードを出力しますが、
今となっては「use16」が使用される事は殆ど無いでしょう。
1番左端にある「_TEXT」というのは、この領域に付けられた
名前です。
名前なので「_ONAKAHETTA」とかでも良いのですが、通常は
「_TEXT」等と付けられます。
インテルのプロセッサでは実行コードが格納される領域の事を
「コード領域」と呼ぶ事もありますが、インテル以外のプロセ
ッサでは一般的に「テキスト領域」と呼びます。
以上で最初の2行の説明は終わりです。
他の領域の宣言も殆ど同じなので、見てみるとすぐに分かると
思います。
_DATA segment dword use32 public 'DATA' ;size is 0
 ̄ ̄ ̄  ̄ ̄ ̄
_DATA ends
異なる部分には下線を引いてあります。
右側の部分は'DATA'となっています。
これはメモリ上の「データ領域」の宣言です。
「データ領域」には、その名の通り「データ」が格納されます。
データ領域は読み込んだり書き込んだりする事は可能ですが、
実行する事は出来ません。
また、DATA領域に格納されるデータには必ず初期値が与えられ
ます。
このプログラムではデータは何も使用しないので1番右端のコ
メントの部分が「size is 0」となっています。
CONST segment dword use32 public 'CONST' ;size is 0
CONST ends
この領域は'CONST'となっています。
これはメモリ上の「コンスタント領域」の宣言です。
「コンスタント領域」というのは「定数」を格納する為の領域
です。
「定数」というのは、変更する事が出来ない「固定値のデータ」
の事です。
この領域は読み込みのみ可能であり、書き込んだり実行したり
する事は出来ません。
'CONST'領域もこのプログラムでは使用される事はないので、
1番右端のコメントの部分が「size is 0」となっています。
_BSS segment dword use32 public 'BSS' ;size is 0
_BSS ends
'BSS'領域というのは、「初期値が与えられていない」データ
を格納する為の領域です。
この領域もデータ領域と同じく、読み込んだり書き込んだりす
る事は可能ですが、実行する事は出来ません。
先ほど出てきた「データ領域」ととても似ていますが、初期値
が与えられているか、いないかが異なります。
'BSS'領域もこのプログラムでは使用される事はないので、1
番右端のコメントの部分が「size is 0」となっています。
以上で領域の説明は終わりですが、何故この様な複数の領域に
分けなければならないかと疑問に思われた方も多いかもしれま
せん。
領域の種類を覚えるのも面倒ですし、考え方が複雑になってし
まうような気がして、とても大変です。
しかし、これはしょうがないことなのです。
ちょっと考えてみましょう。
大きな領域が1つしかないとします。
この中にプログラムやデータが全て収まっている事を想像して
みてください。
この1つしかない領域にはデータも格納されているので、当然
読み出したり、書き込んだりする事が可能でなければなりませ
ん。
領域が1つしかないので、それに引きずられる形でプログラム
コード部分も読み出したり書き込んだりする事が可能となって
しまいます。
もしプログラムコードが格納されている部分に、間違った内容
を書き込んでしまうようなバグ(プログラムの誤り)があった
場合、これを止める事は誰も出来なくなってしまいます。
何故ならば領域が1つしかなく、読み書きを自由に行なっても
良い場所だからです。
また、領域が1つしかないので、ここにはOSも格納されてい
るはずです。ある1つのプログラムの誤りが原因で、OSのプ
ログラムコードを誤って書き換えてしまったら、どうなるでし
ょうか。
もしこの様な事になってしまったら、もうどうしようもありま
せん。
リセットボタンを押すしかなくなってしまいます。
こういう事にならないように、「プログラムを格納する場所は
こからここまでですよ。そしてこの領域は読み出しと実行だけ
出来て、書き込みは出来ない場所ですよ。」等と決めてあげる
必要があるのです。
これらの決まりを守らない、バグを含んだプログラムは強制的
に終了してもらえば良いのです。
どうやって強制的に終了してもらうのか、という疑問が起こる
ので、少しだけ説明します。
これらの「領域の設定」はOS(オペレーティング・システム)
が行ないます。
例えば、「メモリ上の何番目から何番目まではアプリケーショ
ンAのプログラムコードを格納する領域ですよ。この領域は読
み出しと実行は出来ますが、書き込みは出来ませんよ。」等と
OSが1つ1つの領域に対して設定してあげるのです。
この「領域の設定」というのは、インテルプロセッサがハード
的に参照出来る特別な場所に設定され、決まりを守らないプロ
グラムはハード的に検知され、強制的に終了させる事が出来る
ようになっているのです。
これ以上の説明は「簡単なアセンブラ言語」講座としてはテー
マが異なってしまうので、また別の機会に取り上げようと思い
ます。
さて、領域の説明が長くなってしまいましたが、ここが分かれ
ばあともう少しです。
続きは次回に行ないます。