SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

MASMとなでしこによるオリジナルコンパイラの制作

MASMとなでしこによるオリジナルコンパイラの制作 1

コンパイラとアセンブラの基礎知識

Hello Word! の表示

 まずは、「Hello Word!」という文字列を標準出力に表示するアセンブリの例(test1)を紹介します。

test1の実行結果
test1の実行結果
test1
.586
.model flat, stdcall

include iolib.inc
includelib iolib.lib
include kernel32.inc
includelib kernel32.lib

.data
    STR0 db "Hello Word!", 0

.code

_start:
    invoke OutputString, NEAR32 PTR STR0
    invoke ExitProcess, 0
end _start

 これには、MASMの基本が全部ではありませんが詰まっています。まず、最初に目に付くのは

.586
.model flat, stdcall

 ですが、この2行はプログラムの進行に特に関係ありませんので、丸暗記してください。

include/includelib

 次の4行は、それぞれインクルードを表しています。すなわち、外部ファイルの内容をアセンブリで利用できるように取り込む作業です。

include iolib.inc
includelib iolib.lib
include kernel32.inc
includelib kernel32.lib

 includeincludelibの違いは、次のとおりです。

  • include
  • ダイナミックリンクライブラリ(以下、DLL)の中の関数を呼び出す部分の機械語(拡張子「.inc」)を取り込む。
  • includelib
  • 上記をプログラム中で使えるようにするテキストデータ(拡張子「.lib」)を取り込む。

 これら4つのファイルがあるディレクトリについては、MASMをインストールしてから説明します。また、libのインクルードについては、アセンブル時にコマンドラインで指定することもできますが、VEFBLやKJではここでインクルードしておきます。

.data

.data
    STR0 db "Hello Word!", 0

 ここではアセンブリ内で使用するデータを宣言します。本稿で使用するデータ型は、次の2つです。

  • dd:数値
  • db:文字列

変数の宣言

 変数の宣言は次のように行います。

変数の宣言
(変数名) (データ型) (変数の最初の内容)

 例えば、上のアセンブリの例で次のように宣言しています。

STR0 db "Hello Word!", 0
  • 変数名は「STR0」
  • データ型は「db」(文字列)
  • 変数の最初の内容は「Hello Word!」に0をつけたもの

 文字列の最後に0を付けるのには理由があります。

 例えば、ファイルを開くプログラムを作ってバイナリデータ(機械語のファイル)を開こうとした際に、途中ですぐに終了してしまい、残りの大半の部分が読み込めなかったという経験はありませんか。

 それは、プログラムで呼び出しているWin32API(OSの機能を直接参照する機能、DLLによって定義されているものがほとんど)が、「ファイルの最後は0である」と定義しているからです(この0は文字としての0ではなく、文字コードの0です)。バイナリには文字コードの0が頻繁に現れるため、Win32APIが「0に到着したからこれで全部だ」と勘違いしてしまい、途中まてしか読めないのです(ちなみに「メモ帳」は違うアルゴリズムを使っているようですのできちんとファイルの最後まで読みます)。

 文字列も同じように、Windowsでは(他のOSでもですが)「0」に到着すると文字列の終わりと判断します。そのため、文字列の終わりをアセンブラに教えるために、最後に0を付け加える必要があります。

 このような面倒な作業はアセンブラが自動的に行ってくれればよさそうですが、アセンブリは、機械語をテキストに置き換えただけの低級言語なので、そうもいきません。

 また、機械語は一句でも間違えると成り立ちません。アセンブリも、同様に気をつける必要があります。例えば、先ほどの文字列の末尾に付ける0を忘れると、その後のバイナリも文字列の一部と判断され、不具合を生じてしまいます。なお、dd(数値)では、最後に0をつける必要はありません。

.code/invoke

 いよいよプログラム部分に到着しました。

.code

_start:
    invoke OutputString, NEAR32 PTR STR0
    invoke ExitProcess, 0
end _start

 先ほどincludeincludelibを利用することで、DLLをアセンブリの中から呼び出せる、と書きました。また、変数宣言の説明では、Win32APIは普通DLLによって定義されていると書きました。つまり、この2つを組み合わせると、MASMからWin32APIを呼び出すことができるのです。

 Win32APIの呼び出しにはinvokeを使います。

invokeの書式
invoke (関数名), (パラメータを「,」で区切る)

 例えば、Win32APIでプログラムの終わりを示すExitProcessは、次のように呼び出します。ExitProcessのパラメータ(引数)は1つです。

invoke
invoke ExitProcess, 0
  • 関数名は「ExitProcess」
  • 第1の引数は「0」
  • 第2の引数以降は、第1の引数の後にコンマ(,)がないのでなし

ラベル

_start:
end _start

 一行目の「_start:」は、プログラマーなら想像ができると思いますが、ラベルといい、プログラムの中の特定の部分に名前を付けています。

メッセージボックス

 次は、メッセージボックスを表示するアセンブリの例(test2)を紹介します。

test2
test2
test2
.586
.model flat, stdcall

include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

.data
    PROJECTNAME db "test2", 0
    STR0 db "Hello Word!", 0

.code

_start:
    invoke MessageBoxA, 0, offset STR0, offset PROJECTNAME, 0
    invoke ExitProcess, 0
end _start

 ライブラリが違いますね。それもそのはず、メッセージボックスを表示するWin32APIのMessageBoxAは、「user32.dll」で定義されているからです。

 「あれ、MessageBoxのあとにAが付いているはなぜ」と思った人は、C++やActiveBasicなどでWin32APIの宣言をした事のない方がほとんどでしょう。一部のWin32APIでは最後にAが付いており、C++のインクルードファイルではAを取り除いた形で提供されています。

 第2の疑問、「MB_OK」です。ここでは値を直接指定しています。C++でも、コンパイル時にMB_OKは数値に変換されてWin32APIに渡されるので、定義せずに最初から0を指定した方が手っ取り早いと思ったからです。

 それに、もう1つ理由があります。MB_OKは、「windows.inc」で定義されているのですが、実はコンソールアプリケーションを作る時に「windows.inc」をインクルードすると、リンクの時にエラーが起きます。理由は筆者にもはっきり分かりませんが、Windowsアプリケーションからインクルードしたら問題なくリンクできました。ということで「windows.inc」はWindowsアプリケーションの作成までお預けにします。

offset

 MessageBoxA関数を呼び出す時のoffsetでは、「変数のアドレス」を渡しています。CPUは、このアドレスが指し示すメモリを参照し、その値を受け取ります。

次のページ
四則演算とスタック

この記事は参考になりましたか?

MASMとなでしこによるオリジナルコンパイラの制作連載記事一覧

もっと読む

この記事の著者

KMY(かみぃ)

とあるごく平凡な中学生。兵庫県在住。日本語プログラミング言語「なでしこ」に惹かれ、たくさんのプログラムを作り利用している。なでしこ以外にも、他の言語を心得ており、HTMLがなでしこの次に得意であり、Perlが第3位(かも)。ベクターにも多彩な作品を残している。作文がど苦手。KMYpage

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/505 2008/09/02 13:02

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー