SHOEISHA iD

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

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

インラインアセンブラで学ぶアセンブリ言語

インラインアセンブラで学ぶアセンブリ言語 第1回

Visual C++を用いたアセンブラプログラミング体験


  • このエントリーをはてなブックマークに追加

本稿では、敷居が高く実用性も乏しいことから手が出しにくいとされるアセンブリ言語を、Microsoft Visual C++(以降 VC++)のインラインアセンブラを用いて体験していただきます。知識としてアセンブリ言語に興味があるものの、何から始めて良いのか分からないという方も多いと思いますが、VC++を使えばC言語の中にアセンブリ言語を組み込むことができます。

  • このエントリーをはてなブックマークに追加

はじめに

 アセンブリ言語は、コンピュータのCPUが直接理解することができる命令である機械語を記号化した言語であり、機械語と対の関係にあります。アセンブリ言語の1文は1つの機械語に置き換わります。機械語は2進数だけで構成されるバイナリデータで、命令の意味を表すオペコードと呼ばれる値でCPUに指示を出しています。人間が直接機械語を読み書きする場合は、16進数を使うのが一般的です。どちらにしても、数値だけで表現されるプログラミングは人間が読み書きするには不向きなので、数値の代わりにアルファベットによる記号を与えたものがアセンブリ言語なのです。マシン後に対応したアセンブリ言語の記号のことをニーモニックと呼びます。

 しかし、ニーモニックを学習するだけではアセンブリ言語は使えません。問題は、CPUがメモリと通信を行う際に発生するさまざまなアドレスの計算です。機械語の世界では変数や関数という概念は存在せず、式や識別子という概念すら存在しません。単純な加算演算を行うにも、メモリからCPUに値を読み込ませ、加算命令を実行し、実行結果を適切なメモリ領域に戻すという作業を実行する必要があります。

 このとき、機械語の世界では、メモリから読み込むデータをメモリアドレスで指定しなければなりません。本来のアセンブリ言語でも変数という概念は存在しないのでアドレスの計算が必要になりますが、アセンブリ言語をさらに拡張したマクロアセンブラを使えば、アドレスの計算を識別子を使って自動化することができます。

 VC++のインラインアセンブラであれば、C言語内にアセンブリ言語を組み込む形になるため、C言語の識別子をそのまま利用することができます。複雑なアドレスの計算が不要になるため、C言語が使えるのであれば、インラインアセンブラを利用して比較的容易にアセンブリの世界へ入門することができます。本稿では、32ビットのIntel x86互換プロセッサを想定してアセンブリの解説を行います。

Microsoft Visual C++

 VC++のC言語プロジェクトでは、C言語のコードの途中にアセンブリ言語を組み込むことができます。これをインラインアセンブラと呼びます。C言語とアセンブラであれば古いVC++でも利用することができるので、本稿はVC++ 6.0などのユーザーでもご利用いただけます。VC++を持っていない場合は、本稿をきっかけにMicrosoft Visual Studio 2005 Express Editionをお試しください。Visual Studio 2005 Express Editionは、MicrosoftのWebサイトから無償でダウンロードして利用することができます。

 Visual C++ 2005 Express Editionは、プロフェッショナル向けの機能の一部が制限されていますが、通常の C/C++言語のプロジェクトであれば十分に利用することができる統合開発環境です。本稿のサンプルはVisual Studio 2005 Professional Editionを使って開発していますが、Express Editionでもインラインアセンブラを試すことができます。

 アセンブラを試すには、VC++で空のプロジェクトを作成してC言語のソースファイルを追加してください。Express Editionの場合、[ファイル]-[新規作成]-[プロジェクト]メニューを選択して[新しいプロジェクト]のダイアログを開きます。

空のプロジェクト
空のプロジェクト

 左側の[プロジェクトの種類]ツリーから[Visual C++]を選択し、右側の[テンプレート]から[emptyproj]を選択してください。その後、任意のプロジェクト名、およびソリューション名を指定して[OK]ボタンを押します。

 作成したプロジェクトにはソースファイルが何も無い状態なので、[ソース ファイル]フォルダを右クリックして[追加]-[新しい項目]を選択します。[新しい項目の追加]ダイアログボックスが表示されるので、左側の[カテゴリ]ツリーから[コード]を選択して、右側の[テンプレート]から[C++ファイル (cpp)]を選択してください。

C++ファイルの選択
C++ファイルの選択

 後は、任意のファイル名を指定して[追加]ボタンを押せばソースファイルが追加されます。本稿ではC言語しか使わないので、.cファイルでかまいません。作成したソースファイルを選択して、任意のコードを記述することができます。

インラインアセンブラの書き方

 C言語のコード中にアセンブリ言語を記述するには__asmキーワードを使います。__asmキーワードは、VC++専用のMicrosoft独自のキーワードで、C 言語標準のものではありません。アセンブラはC言語コード内では文として扱われるので、__asmは文を記述できる場所であればどこにでも記載できます。__asmは、次のように使います。

__asm アセンブリ文
__asm { アセンブリ文のリスト }

 __asmキーワードの直後にアセンブリ言語の単一の文が続きます。記述するアセンブリ言語の文が複数ある場合は { } のブロック内に任意の数のアセンブリ文を記述します。ただし、ここで記述したアセンブリ言語は前後するC言語のコンパイル結果となる機械語に影響を与えるので注意が必要です。本来ならば、十分なアセンブリ言語の知識を持っている開発者が必要に応じて利用するのが__asmキーワードです。

 早速、アセンブリ言語で「Hello world」を出力するコードを書きたいところですが、文字列を出力する概念を機械語レベルで理解するには相応の基礎知識が必要となり、C言語のprintf()関数を呼び出すだけのプログラムのように単純ではありません。この場では、まず、C言語で宣言した変数にアセンブリ言語から値を代入するサンプルを作成します。

サンプル1 __asmキーワード
#include <stdio.h>

int main() {
    int i;

    __asm mov i, 100

    printf("i=%d\n", i);

    return 0;
}
実行結果
i=100

 __asm mov i, 100という文が、C言語内に組み込んだアセンブリ言語です。アセンブリ言語はC言語のように文を入れ子にすることはできないので、末尾をセミコロン;で終わらせる必要はありません。アセンブリ言語は、ニーモニックから自動的にオペランドを決定することができます。

 上記のコードでは、C言語で宣言した変数iに対して100を代入するプログラムです。アセンブリ言語の用語を使うのであれば、「変数iのメモリアドレスに即値100をストアする」と表現します。単純に転送と呼んでも通用すると思われますが、一般的には、メモリからCPUに値を読み込むことを「ロード」と呼び、CPUからメモリにデータを書き込むことを「ストア」と呼びます。また、定数のことは「即値」と呼びます。ただし、インラインアセンブラであれば、C言語に内包されているものなので定数と呼んでも違和感はありません。

 このように、インラインアセンブラではアセンブリ言語内でC言語の識別子を利用することができます。変数iは実質的にはデータをストアするべきメモリアドレスに変換されますが、開発者がそれを意識する必要はありません。

 複数のアセンブリ文を記述する場合は{ } __asmキーワードに続いてブロックを指定します。これによって、長文のアセンブリ言語を記述することができます。アセンブリ言語の文は改行で区切られるので、複数の文を記述する場合は文の最後で必ず改行しなければなりません。

サンプル2 __asmブロック
#include <stdio.h>

int main() {
    char ch1, ch2;
    __asm {
        mov ch1, 0x41
        mov ch2, 0x42
    }

    printf("ch1=%c, ch2=%c\n", ch1, ch2);

    return 0;
}
実行結果
ch1=A, ch2=B

 サンプル2は、文字型の変数ch1ch2にアセンブリ言語で値を代入しています。ch1には0x41、ch2には0x42を代入していますが、これらはASCIIコードの「A」と「B」を表しているため、結果はAとBが表示されます。このプログラムのアセンブリ言語は__asmブロック内に記述しています。多くの場合、アセンブリ言語によるプログラムは長くなるので、ブロックが利用されることになるでしょう。

 サンプル2のコードでは、アセンブリ言語からch1ch2に代入する値を0x41や0x42というようにC言語の定数で指定しています。このように、インラインアセンブラで利用する定数はC言語の定数を使うことができます。例えば、上記のコードは数値ではなく'A''B'という形で文字定数を指定することも可能です。

mov ch1, 'A'

 これは有効なコードです。ch1変数に'A'定数に相当する値0x41が格納されることに変わりはありません。

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
コメント

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

  • このエントリーをはてなブックマークに追加
インラインアセンブラで学ぶアセンブリ言語連載記事一覧

もっと読む

この記事の著者

赤坂 玲音(アカサカ レオン)

平成13年度「全国高校生・専門学校生プログラミングコンテスト 高校生プログラミングの部」にて最優秀賞を受賞。2005 年度~ Microsoft Most Variable Professional Visual Developer - Visual C++。プログラミング入門サイト WisdomSoft の管理人。

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

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

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/393 2006/08/08 20:47

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング