アセンブラー学習用ひな型プログラム

これからメインフレーム・コンピューターのアセンブラー・プログラミングを覚えようとする方向けに、基本的な命令の動きやレジスターに読み込んだ内容やメモリーに書き込んだ内容を簡単に見るためのひな型プログラムを用意しました。JCLと一体になっているので必要な命令とデータを記述してサブミットすれば、実行結果をSYSOUTに出力できます。
z/OSで実際に動かせるアセンブラープログラムを作るには、単に実行させたい命令やデータを書くだけでは済みません。OSから呼び出された時点での最低限必要な手続きや、実行結果の編集・出力が必要になります。そのためにはMVSやDFSMS(データ管理)のAPIも合わせて学ばねばなりません。あるいは、実行させたい命令の直後でわざとABENDさせてダンプを出力し、そのダンプ・リストからレジスターやメモリーの内容を見るかです。どちらの方法も全くのビギナーには少々敷居が高いです。
このひな型を使えば、純粋に試して見たい命令やデータを書くだけで容易にテストすることができ、基本的な命令の動きを実際に動かして理解してから次のステップへ進むことができます。

上記のひな型プログラムは、アセンブルとバインドによって生成されたロード・モジュールをバッチTSO環境でTESTコマンドによって実行するものです。TESTコマンドのブレーク機能を利用して、指定したブレーク・ポイントを通過した際のレジスターとメモリー(指定した範囲)の内容をSYSOUTに出力します。
実行後のSYSOUT(TESTコマンドの出力内容)を参照することで、自分が書いた命令が実行された結果を具体的に目視して確認することができます。命令によってレジスターやメモリーがどう変化したかを、ひな型プログラム①ではある程度の処理を行った結果をまとめて、ひな型プログラム②では一定範囲の処理を1命令ずつ実行して結果を確認することができます。

ひな型プログラムJCLの使い方

ダウンロードしたひな型プログラムJCLを、任意のPDS/PDSEデータセットに任意のメンバー名で格納します。(FTP、3270エミュレーターのファイル転送あるいはISPFエディターでのコピー&ペースト等でメンバー登録します)
このひな型自身はJCLになっています。JCLのストリーム内データセットとしてアセンブラー言語のプログラムが記述してあり、その中で案内された部分に試してみたい命令とデータを書いてサブミットすれば実行されます。コーディングの構文に誤りがあれば、アセンブルのステップでエラーになり後続ステップは実行されずにジョブは終了します。アセンブルが通れば続いてバインダーが実行されロード・モジュールが作成されてから最後にバッチTSO環境のステップが実行され、JCL内に記述したアセンブラー・プログラムがTSOのTESTコマンドによって実行されます。記述した機械命令の実行経過は、ステップGのSYSTSPRT DDステートメントに出力されます。

1. ひな型プログラムJCLを修正する

下記のJCLは「アセンブラー学習用のひな型プログラムJCL①」の冒頭部分です。必要ならJOBステートメントを使用するシステムの規約に合わせて修正し、ジョブ名も利用するz/OSシステムの利用規約に併せて修正して下さい。呼び出しているカタログ・プロシージャーASMACLはHLASM(高水準アセンブラー)の標準提供プロシージャーです。特定のシステムに依存する部分はありませんので、JOBステートメントだけ修正すれば実行することができます。なお、JOBステートメントのTIMEとLINESパラメーターは削除しないことを勧めます。プログラムがループした場合、S322もしくはS722でABENDさせるために最大CPU時間を20秒、最大出力量を1万行に設定してあります。

なお、最初のEXECステートメントのステップ名ASMACLを変更する場合は、プログラム・コードの後ろに記述されたステップGのEXECステートメントにあるCONDパラメーター内の先行ステップ名も併せて修正しなければなりません。特別な理由が無ければ、最初のEXECステートメントのステップ名ASMACLはそのままにしておくことを勧めます。

2. アセンブラー・プログラムを記述する

ひな型の40行目前後にある「MAINPROC」というラベル以降の部分に試したい命令や実行したい処理を書いて下さい。「ここに実行したい機械命令コードを書いて下さい。」という日本語のコメントが書いてある部分です(ファイル転送やISPFエディターでの貼り付け時に文字化けしている場合は、元のテキスト・ファイルを見て下さい)。データに関しては、ひな型の60行目辺りにある「DATAAREA」というラベル以降の部分にDCやDS命令でのデータ定義を書いて下さい。「ここに機械命令で参照するデータを書いて下さい。」という日本語のコメントが書いてある部分です。

下記に追加した命令とデータのサンプルを示します。

3. ひな型プログラムJCLを実行する

下記のJCLは「アセンブラー学習用のひな型プログラムJCL①」の終盤部分です。2つ目のEXECステートメントが、JCL内に記述したアセンブラー・プログラムを実行するステップです。このステップのSYSTSIN DDステートメントで、TSOのTESTコマンドを起動してJCL内に記述したアセンブラー・プログラムを実行します。

SYSTSIN内の1行目がTESTコマンドの起動です。*(GO)は、標準探索ライブラリー(STEPLIBやLINKLIB等)内のメンバーGOを実行することを示します。’ABCDEFGH・・・STUVWXYZ0123456789’は、プログラムへ渡すパラメーター文字列です。EXECステートメントのPARMパラメーターに相当します。
2行目と3行目のATサブコマンドは、ブレーク・ポイントの設定です。プログラム内のラベルMAINPROCとEXECPROCの位置にそれぞれブレーク・ポイントを設定します。()で囲まれたATサブコマンドの2つ目のパラメーターは、ブレーク・ポイントに到達した際に実行するTESTのサブコマンドです。Lサブコマンドはレジスターやメモリー内容を出力します。続くGOサブコマンドは、プログラムの実行開始とブレーク・ポイントからの再開を指示します。最初のTESTコマンドと続く2つのATサブコマンドに対応して全部で3つのGOサブコマンドを指定しています。

下記にサンプルの実行結果(SYSTSPRT)を示します。

レジスターとメモリー内容の出力は2箇所で行われていますが、1つ目のものはラベルMAINPROCの箇所に到達した時点の内容です。プログラム冒頭の入口点処理を行い、渡されたパラメーター文字列の長さをレジスター0に、アドレスをレジスター1に格納した状態でここに到達します。2つ目のものがラベルMAINPROCからラベルEXITPROC迄の間に実行された一連の命令によって変更された最終の内容で、ラベルEXITPROC到達時の状態です。

途中で異常終了した場合は、TESTコマンドによって実行が打ち切られます。SYSTSPRT内容ではABENDしたことしかわからないので、ジョブ・ログに出ている徴候ダンプを見てABENDした命令とABEND時のレジスター内容を確認します。

徴候ダンプ内の「OFFSET=00000xxx」部分がABENDした命令の位置を示します。上記例のようにOFFSET=000000A6であれば、プログラムの先頭からxA6番地の命令かその1つ前の命令です。基本的にはオフセット値が示す命令の1つ前の命令ですが、OFFSET=の1つ前の行に出ている「ILC ? INTC ??」が「ILC 4 INTC 10」又は「ILC 4 INTC 11」ならオフセット値が示す命令でエラーが起きています。(命令の位置はアセンブリー・リスト左端のLocフィールドと照らし合わせます:下記リスト例参照)
何故エラーになりABENDしたかは、「SYSTEM COMPLETION CODE=xxx」が示すABENDコードをマニュアルで調べます。上記例ではS0C7でデータ例外(誤ったデータを指定して命令を実行した)です。

ステップ走行による命令動作の確認

プログラム終了時のレジスターとメモリーの内容ではなく、命令を実行しながら都度都度確認することもできます。ステップ走行と呼ばれ、1命令実行してはブレークします。TSOのTESTコマンドでは、ATサブコマンドによるブレーク・ポイントの設定を範囲で行うこともできます。ブレーク・ポイントが範囲設定された場合は、その範囲内の各命令実行毎にブレークします。ループする場合も1命令ずつブレークしながらループします。

4. ステップ走行を設定してひな型プログラムJCLを実行する

ステップ走行を行う場合は、「アセンブラー学習用のひな型プログラムJCL②」を使用します。(冒頭のJOBステートメント部分は、ひな型プログラムJCL①同様に修正して下さい)
下記のJCLは「アセンブラー学習用のひな型プログラムJCL②」の終盤部分です。ひな型プログラムJCL①同様に、2つ目のステップのSYSTSIN DDステートメントに、TSOのTESTコマンドを記述して実行します。

ひな型プログラムJCL①同様に、SYSTSIN内にTESTコマンドとサブコマンドを記述します。2行目でブレーク・ポイントの設定をMAINPROC:EXITPROCと範囲指定で行っています。プログラム内のラベルMAINPROCとEXECPROCの間の各命令にブレーク・ポイントが設定され、ブレーク時は命令毎にレジスター内容とDATAAREAとWORKAREA間及びWORKAREA領域の先頭32バイト分のメモリー内容が出力されて次の命令の実行に進みます。
ATサブコマンドの次、4行目のGOサブコマンドは、TESTコマンドによって読み込まれたプログラムの実行を開始するためのものです。ブレーク後の再開用GOサブコマンドは、ATサブコマンド内に記述してあります。バッチTSOでのステップ走行では、ATサブコマンド内に再開用のGOサブコマンドも定義しておかないと、実際に実行される命令数であるダイナミック・ステップ数に合わせたGOサブコマンドをSYSTSIN内に何十行以上も繰り返し定義する必要があります。プログラム処理の中でループがあるとループ回数なども考慮して実行される命令数を計算しなければならずとても面倒です。GOコマンドの数が実際に実行される命令数より少ない場合は、途中で実行が打ち切られてしまいます。

下記にサンプルのステップ走行実行結果(SYSTSPRT)を示します。

次に実行される命令の位置は「IKJ57024I AT +50 FROM MAINPROC」のメッセージに変位が16進数で示されるので、先行したアセンブラーのステップで出力されたアセンブリー・リストと照らし合わせれば具体的にどの命令が実行されるかがわかります。ひな型プログラムJCL②では、命令位置を照らし合わせ易くするため、ラベルMAINPROCがプログラムの先頭から16進の100、x100番地になるように調整しています。「IKJ57024I AT +2C FROM MAINPROC」ならアセンブリー・リスト左端のLocが00012Cの命令、「IKJ57024I AT +40 FROM MAINPROC」ならアセンブリー・リスト左端のLocが000140の命令です。IKJ57024Iメッセージ中の16進変位の値にx100を足せば、アセンブリー・リスト左端のLocフィールドの値に換算できます。

ひな型プログラムJCLは汎用的なバッチ処理として作ってあるので、全ての命令実行に対して全汎用レジスターとDATAAREA~WORKAREA間及びWORKAREAの先頭32バイトのメモリー内容を固定した範囲で無条件に出力していますが、プログラムの実行内容に合わせて出力範囲を変えることも可能です。その場合JCLでの記述はかなり面倒なので、命令毎にレジスター番号や範囲、メモリー範囲を変えて内容を見たい場合はTSO端末からの対話型での実行が便利です。ただし、TESTコマンドはISPFのコマンド・シェルでは実行できないので、TESTコマンド起動用のREXXを作って実行するかISPFを終了させて実行しなければなりません。
TESTコマンドの使い方は、別記事として掲載しますので参考にしてみて下さい。より詳細はマニュアル「TSO/Eコマンド解説書」(SA88-7049)を参照して下さい。