[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

コンピュータIIL(情報科学入門)第5回

目次
5.1 機械語(2)
5.1.1 スタックの表現
5.1.2 スタックと演算
5.1.3 アセンブラ
5.1.4 逆アセンブルの例
5.2 演習5
5.3 レポート課題
5.4 参考文献
索引
アセンブラ   アセンブリ言語   アセンブル   逆アセンブル   ニーモニック・コード  

5.1 機械語(2)

5.1.1 スタックの表現

前回はスタックに1つしかデータを格納しませんでした。 今回は複数のデータを格納します。

スタックの状態を表現するために、ここでは、スタックが右に伸びるように要素を列挙します。 まず、空のスタックは {} と書きます。 次に、このスタックに4をプッシュしますと、スタックの要素は {4} になります。 さらに5をプッシュし、6をプッシュしますと、スタックの要素は {4, 5, 6} になります。 そして、ポップしますと6が取り出せ、スタックの要素は {4, 5} になります。

5.1.2 スタックと演算

Java仮想マシンには四則演算の機能があります。 この演算は、スタックの右端のデータに対して行われます。

例えば、9 - 6 を計算したい場合、9と6をスタックにプッシュしてから引き算の命令を実行します。 すると、計算された9と6はポップされ、計算結果3がプッシュされます。 スタックの要素を書きますと、{9, 6} のときに引き算の命令を実行しますと、{3} になります。

スタックを用いた演算には、十分な計算能力があります。 ただし、普通の筆算とは異なる、独特の考え方をします。 例として、20, 30, 40の合計を2通りの方法で計算します。

第1の方法は、すべての数をスタックにプッシュしてから足し算を続けるものです。 20をプッシュし、30をプッシュし、40をプッシュしますと、スタックの要素は {20, 30, 40} となります。 ここで足し算を行いますと {20, 70} となり、もう一度足し算をしますと {90} となります。 最後にポップしますと、計算結果90が取り出せます。

第2の方法は、スタックへのプッシュと足し算を交互に行うものです。 まず、スタックに20をプッシュしておきます。 30をプッシュしますと、スタックの要素は {20, 30} となり、足し算をしますと {50} となります。 40をプッシュしますと {50, 40} となり、足し算をしますと {90} となります。 最後にポップしますと、計算結果90が取り出せます。

5.1.3 アセンブラ

プログラムは命令の系列ですが、命令を16進数で書き表しても、人間にとっては分かりにくいものです。 少しでも分かりやすくするために、アセンブリ言語が考え出されました。 アセンブリ言語assembly language ) とは、命令に覚えやすい文字列(英単語など)を対応させた言語です。 特に、オペコードに対応する文字列を ニーモニック・コードmnemonic code ) と呼びます。

例えば、Java仮想マシンの命令 1009 は、アセンブリ言語では bipush 9 となります。 bipush は、Byte Integer PUSHという意味のニーモニック・コードです。

アセンブリ言語を機械語に置き換えることを、 アセンブルassemble ) と言います。 アセンブルを行うソフトウェアを、 アセンブラassembler ) と呼びます。 逆に、機械語をアセンブリ言語に置き換えることを、 逆アセンブルdisassemble ) と言います。

学内のパソコンには、Java仮想マシンのアセンブラはないようです。 しかし、逆アセンブルならできます。 コマンドjavap -c filename でファイル filename .classが逆アセンブルされ、アセンブリ言語が出力されます。 この機能を使えば、分かりにくい機械語を読む必要がなくなります。 プログラムを逆アセンブルして、分かりやすくなったアセンブリ言語を読めばよいのです。

5.1.4 逆アセンブルの例

今日扱う命令は次の通りです。

表 5.1  Java仮想マシンの命令
ニーモニック 命令長 第1バイト 第2バイト 命令
nop 1バイト 0x00
何もしない。
iconst_0 1バイト 0x03
整数0をスタックにプッシュする。
iconst_1 1バイト 0x04
整数1をスタックにプッシュする。
bipush 2バイト 0x10 byte 整数byteをスタックにプッシュする。
iload 2バイト 0x15 index index変数の値をスタックにプッシュする。
iload_1 1バイト 0x1b
第1変数の値をスタックにプッシュする。
iload_2 1バイト 0x1c
第2変数の値をスタックにプッシュする。
istore 2バイト 0x36 index スタックからポップした値を第index変数に格納する。
istore_1 1バイト 0x3c
スタックからポップした値を第1変数に格納する。
istore_2 1バイト 0x3d
スタックからポップした値を第2変数に格納する。
iadd 1バイト 0x60
整数の足し算を行う。
isub 1バイト 0x64
整数の引き算を行う。
imul 1バイト 0x68
整数の掛け算を行う。
idiv 1バイト 0x6c
整数の割り算を行う。
irem 1バイト 0x70
整数の剰余算を行う。

今日の演習は次のJavaプログラムから始めます。

/*  1*/ class Ex5 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int x;
/*  4*/         int y = 6;
/*  5*/         x = 9 - y;
/*  6*/         System.out.println(x);
/*  7*/     }
/*  8*/ }
b04a001@AsiaA1:~/comp2l% javac Ex5.java
b04a001@AsiaA1:~/comp2l% java Ex5
3
b04a001@AsiaA1:~/comp2l%

バイナリ・ファイルEx5.classを開きますと、下から4行目にプログラム 1006 3d10 091c 643c が見えます。 このプログラムは、上記の4行目と5行目に対応します。

00000150: 0010 1006 3d10 091c 643c b200 021b b600  ....=...d<......

このプログラムを逆アセンブルします。

b04a001@AsiaA1:~/comp2l% javap -c Ex5
...
   0:   bipush  6
   2:   istore_2
   3:   bipush  9
   5:   iload_2
   6:   isub
   7:   istore_1
...
b04a001@AsiaA1:~/comp2l%

このアセンブリ言語を読んでみます。

命令 bipush 6 でプッシュされ、スタックの要素は {6} になります。 命令 istore_2 でポップされ、スタックの要素は {} になり、第2変数の値は6になります。 命令 bipush 9 でプッシュされ、スタックの要素は {9} になります。 命令 iload_2 で第2変数の値がプッシュされ、スタックの要素は {9, 6} になります。 命令 isub で計算 9 - 6 = 3 が行われ、スタックの要素は {3} になります。 命令 istore_1 でポップされ、スタックの要素は {} になり、第1変数の値は3になります。 したがって、第1変数の値3が出力されます。

例題1. プログラム 1007 3d1c 1003 6c3c を実行すると何が出力されるかを答えてください。 出力だけではなく、プログラムの動作についても説明してください。 バイナリ・ファイルEx5.classのプログラムの部分を置き換え、javaコマンドを実行すると、答えが確認できます。

解答する前に、バイナリ・ファイルEx5.classを次のように書き換え、逆アセンブルします。

00000150: 0010 1007 3d1c 1003 6c3c b200 021b b600  ....=...l<......
b04a001@AsiaA1:~/comp2l% javap -c Ex5
...
   0:   bipush  7
   2:   istore_2
   3:   iload_2
   4:   bipush  3
   6:   idiv
   7:   istore_1
...
b04a001@AsiaA1:~/comp2l%

解答例1. 命令 bipush 7 でスタックの要素は {7} になる。 命令 istore_2 でスタックの要素は {} になり、第2変数の値は7になる。 命令 iload_2 でスタックの要素は {7} になる。 命令 bipush 3 でスタックの要素は {7, 3} になる。 命令 idiv で割り算 7 / 3 = 2 が行われ、スタックの要素は {2} になる。 命令 istore_1 でスタックの要素は {} になり、第1変数の値は2になる。 したがって、第1変数の値2が出力される。

確認のため、javaコマンドを実行します。

b04a001@AsiaA1:~/comp2l% java Ex5
2
b04a001@AsiaA1:~/comp2l%

5.2 演習5

次のプログラムを実行すると何が出力されるかを答えてください。 出力だけではなく、プログラムの動作についても説明してください。 バイナリ・ファイルEx5.classのプログラムの部分を置き換え、javaコマンドを実行すると、答えが確認できます。

  1. 1008 1002 6c3c 0000
  2. 1009 3d1c 1c68 3c00
  3. 0404 6004 6004 603c

5.3 レポート課題

今日の演習5の答案をメールで提出してください。 メールの差出人は学内のアドレス(b04a001@twcu.ac.jpなど)とし、メールの宛先はkonishi@twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(10月28日)を明記してください。


5.4 参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2005年10月28日更新
小西 善二郎 <konishi@twcu.ac.jp>
Copyright (C) 2005 Zenjiro Konishi. All rights reserved.