アセンブラー学習用ひな型プログラム
これから汎用機のアセンブラーに関してプログラミングを覚えようとする方向けに、基本的な命令の動きや、レジスターやメモリーに設定した内容を簡単に見るためのひな型プログラムを用意しました。JCLと一体になっているので必要な命令とデータを記述してサブミットすれば、実行結果をSYSOUTに出力できます。
z/OS(MSPやVOS3を含む)で実際に動かせるアセンブラープログラムを作るには、単に実行させたい命令やデータを書くだけでは済みません。OSから呼び出された時点での最低限必要な手続きや、実行結果の編集・出力が必要になります。そのためには、OSやデータ管理のAPIも合わせて学ばねばなりません。あるいは、実行させたい命令の直後でわざとABENDさせてダンプを出力し、そのダンプリストからレジスターやメモリーの内容を見るかです。どちらの方法も、全くのビギナーには少々敷居が高いです。
このひな型を使えば、純粋に試して見たい命令やデータを書くだけでテストすることができます。そのため、基本的な命令の動きを実際に動かして理解してから次のステップへ進むことが出来ます。書いたプログラムに誤りがあればそのプログラムは異常終了しますが、どの命令が誤っているのかなどを調べるにはダンプの解析が必要で、これも面倒な作業です。このひな型では基本的な機械命令の使用誤りに関しては、異常終了をトラップしてメッセージで通知します。正常であれ、エラーであれ、記述した命令とデータによってCPUが何を行い、メモリー内容がどう変わったかを簡単に見ることができるようにしてあります。
z/OSの他、フリーで利用できるMVS3.8、MSPおよびVOS3でも実行できます。z/OS以外で試したい方は、ダウンロード後にJCLのアセンブラーとローダーのステップを、各OSに合わせて修正してください。制御部分のコードが使っているOSのAPIは古典的なものなので互換OSであるMSPとVOS3でもプログラム自体はそのまま動かすことができます。
ひな型プログラムJCLの使い方
このひな型自身はJCLになっています。JCLのストリーム内データセットとしてアセンブラー言語のプログラムが記述してあり、その中の指定された部分に試してみたい命令とデータを書いてサブミットすれば実行されます。コーディングの構文に誤りがあれば、アセンブルのステップでエラーになりジョブは終了します。アセンブルが通れば続いてローダーが実行されロードモジュールが作成されてプログラムが実行されます。
予め用意されたひな型コードの先頭、最後の命令の直後、プログラムの終わり、の3箇所にアセンブラー学習用として動くための制御コードを埋め込むマクロ命令が記述されています。このマクロ命令の記述は変更しないで下さい。マクロ命令とひな型プログラムJCLのメンバー・データをダウンロードして適当なデータセットに格納すれば実行できます。
ひな型プログラムとひな型プログラムが使用する制御用マクロ命令を格納するソース・データセットを用意する
ソース・データセット名は、使用するシステムの規約に従って決めます。自由に決めてよいなら、TSOのユーザーIDを第1修飾子にして、第2修飾子をASMにします。このDSNは、ひな型のJCLが想定したものです。DSORGは、区分データセットまたはPDSEです。容量とDIRブロック数は適当でかまいません。10TRKで10DIRもあれば十分でしょう。
最初に、ひな型プログラム制御用マクロ命令をダウンロードして下さい。それをソース・データセットにメンバー名 @EDUCNTL で格納します。その後に、ひな型プログラムJCLをダウンロードして使用します。
ひな型プログラムJCLを修正する
以下のJCLは「アセンブラー学習用のひな型プログラムJCL(z/OS用)」の内容です。
JOBステートメントを使用するシステムの規約に合わせて修正して下さい。次に、SYSLIB DDステートメントの先頭に定義した「DSN=&SYSUID..ASM」のDSNを@EDUCNTLマクロを格納した区分データセットの名前に変更します。z/OSでは、&SYSUID.の部分がTSOのユーザーIDに自動的に置き換わります。
//MYASMJOB JOB (ACCT),NAME,CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1) //********************************************************************* //ASMCG PROC //ASM EXEC PGM=ASMA90, // PARM='OBJ,NODECK,XREF(SHORT),TERM' //SYSLIB DD DISP=SHR,DSN=&SYSUID..ASM // DD DISP=SHR,DSN=SYS1.MACLIB //SYSUT1 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSLIN DD DISP=(,PASS),UNIT=SYSALLDA,SPACE=(TRK,(1,1),RLSE), // DCB=(RECFM=FB,BLKSIZE=3120,LRECL=80) //SYSPRINT DD SYSOUT=* //SYSTERM DD SYSOUT=* //GO EXEC PGM=LOADER,COND=(5,LT,ASM), // PARM='LIST,LET,MAP,XREF' //SYSLOUT DD SYSOUT=* //SYSLIN DD DSN=*.ASM.SYSLIN,DISP=(OLD,DELETE) //SYSPRINT DD SYSOUT=* //SYSUDUMP DD SYSOUT=* // PEND //********************************************************************* //MYASMPGM EXEC ASMCG,PARM.GO='/PARAMETER STRING' //ASM.SYSIN DD * : :
z/OS以外でひな型プログラムを試す場合は、JOBステートメントの修正とSYSLIB DDステートメントの先頭に定義する@EDUCNTLマクロ格納データセットの名前変更だけでなく、各OS用のアセンブラーに合わせて修正を追加する必要があります。以下に示す例を見て使用するOS用に修正を追加します。太字部分が修正箇所です。
MVS 3.8およびMSP用 ================== //MYASMJOB JOB (ACCT),NAME,CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1) //********************************************************************* //ASMCG PROC //ASM EXEC PGM=IFOX00, // PARM='OBJ,NODECK,XREF(SHORT),TERM' //SYSLIB DD DISP=SHR,DSN=userid.ASM,DCB=BLKSIZE=32720 // DD DISP=SHR,DSN=SYS1.MACLIB //SYSUT1 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSUT2 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSUT3 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSGO DD DISP=(,PASS),UNIT=SYSALLDA,SPACE=(TRK,(1,1),RLSE), // DCB=(RECFM=FB,BLKSIZE=3120,LRECL=80) //SYSPRINT DD SYSOUT=* //SYSTERM DD SYSOUT=* //GO EXEC PGM=LOADER,COND=(5,LT,ASM), // PARM='LIST,LET,MAP,XREF' //SYSLOUT DD SYSOUT=* //SYSLIN DD DSN=*.ASM.SYSGO,DISP=(OLD,DELETE) //SYSPRINT DD SYSOUT=* //SYSUDUMP DD SYSOUT=* // PEND //********************************************************************* //MYASMPGM EXEC ASMCG,PARM.GO='/PARAMETER STRING' //ASM.SYSIN DD * : : VOS3用 ========= //MYASMJOB JOB (ACCT),NAME,CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1) //********************************************************************* //ASMCG PROC //ASM EXEC PGM=JLAX00, // PARM='OBJ,NODECK,XREF(SHORT),TERM' //SYSLIB DD DISP=SHR,DSN=userid.ASM,DCB=BLKSIZE=32720 // DD DISP=SHR,DSN=SYS1.MACLIB //SYSUT1 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSUT2 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSUT3 DD UNIT=SYSALLDA,SPACE=(TRK,(10,10)) //SYSLIN DD DISP=(,PASS),UNIT=SYSALLDA,SPACE=(TRK,(1,1),RLSE), // DCB=(RECFM=FB,BLKSIZE=3120,LRECL=80) //SYSPRINT DD SYSOUT=* //SYSTERM DD SYSOUT=* //GO EXEC PGM=LOADER,COND=(5,LT,ASM), // PARM='LIST,LET,MAP,XREF' //SYSLOUT DD SYSOUT=* //SYSLIN DD DSN=*.ASM.SYSLIN,DISP=(OLD,DELETE) //SYSPRINT DD SYSOUT=* //SYSUDUMP DD SYSOUT=* // PEND //********************************************************************* //MYASMPGM EXEC ASMCG,PARM.GO='/PARAMETER STRING' //ASM.SYSIN DD * : :
MVS3.8およびMSP用は、ここ「アセンブラー学習用のひな型プログラムJCL(MVS3.8,MSP用)」からダウンロードできます。VOS3用は、どちらかを選んでダウンロードして修正して下さい。オブジェクト・モジュールの出力先DD名に注意します。z/OSとVOS3はSYSLINですが、MVS3.8とMSPはSYSGOです。
各OS毎のアセンブラーJCLの作り方については「アセンブラープログラムの作成(アセンブルJCL)」にも解説があります。
ひな型プログラムに試したい命令とデータを書いてサブミットする
JCLの準備ができたら、//ASM.SYSIN DD * に記述されたひな型コード内の「ここに実行したい機械命令コードを書いて下さい。」のところに、試してみたい機械命令を書いて下さい。命令が参照するデータは「ここに機械命令で参照するデータを書いて下さい。」のところに定義します。
※@EDUCNTLマクロ命令の記述部分はいじらないで下さい。意味がわからなくてもかまいません。そのままにしておいて下さい。それから、このひな型プログラムではレジスター13番はいじらないようにします。このプログラムに関する決まり事だと思ってください。
命令とデータを書いたら、サブミットします。ジョブが開始すると、最初にアセンブラーが実行されて記述したアセンブラー・プログラムが翻訳されてオブジェクト・モジュールが作成されます。続けてローダーが実行されてオブジェクト・モジュールをロード・モジュールに変換してメモリーに読み込み実行します。
: : //MYASMPGM EXEC ASMCG,PARM.GO='/PARAMETER STRING' //ASM.SYSIN DD * @EDUCNTL BEGIN EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *********************************************************************** * AVAILABLE YOUR ASSEMBLER LANGUAGE CODE AT HERE. * * ===================================================== * * GR1 ---> AS ENTRY POINT(PLIST FOR EXEC PARAMETER) * * GR13 --> BASE REGISTER AND OUR REGISTER SAVEAREA * *********************************************************************** * ここに実行したい機械命令コードを書いて下さい。 *=====================================================================* EXITPROC DS 0H EXIT PROCEDURE AT HERE @EDUCNTL EXIT EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *=====================================================================* YOURDATA DS 0D USER DATA AREA START AT HERE DC C'BGN OF YOUR DATA' * ここに機械命令で参照するデータを書いて下さい。 DC C'END OF YOUR DATA' *********************************************************************** @EDUCNTL END EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *********************************************************************** *------- YREGS , EXPAND GPR EQUATIONS(z/OS ONLY) END // //
このひな型プログラムは、基本的な命令の動きを学習するレベルのプログラムを前提に作ってあります。OSのAPIを呼び出したり、データセットのアクセスをしたりの少しレベルの高いプログラムも記述は可能ですが、そのような箇所でエラーが起きても正しくトラップしたり、実行結果を出力させたりすることはできません。自力でABENDダンプなどを解析する必要があります。おそらくそのようなプログラムが書けるレベルになればこのひな型はもう不要でしょう。また、このひな型で制御できるのは24ビット・モードのプログラムです。ひな型をそのまま使えば24ビット・モードのプログラムになります。プログラム内で直接アドレッシング・モードを変更するような命令を使わない限りアドレッシング・モードは気にしなくてもいいです。
アセンブル・リストと実行結果の見方
アセンブラー言語でのプログラミングにおいてはアセンブル・リストは非常に重要です。細かな見方はマニュアルを見るとして、まずは自分が書いた命令やデータがプログラム内のどの位置に置かれ、どのようなバイナリーコードに変換されたかぐらいはわかるようにしてください。このぐらいはマニュアルを見なくてもリストを見れば簡単にわかります。COBOLやC言語などと違ってアセンブラーではアセンブル・リストがなければデバッグできないと言っても過言ではありません。アセンブル・リストはASMステップのDD名SYSPRINTのSYSOUTに出力されます。
このひな型プログラムにおける実行結果は、プログラム(@EDUCNTL EXITマクロの直前の命令)の終了時点における完了コード(GR15の値)、汎用レジスターの内容とメモリーの内容です。
メモリー内容は、書かれた命令コードとデータの部分がダンプ形式で出力されます。出力先はGOステップのDD名SYSPRINTのSYSOUTです。
YOUR PROGRAM ENDED, COMP CODE(GR15:0000) PSW = 078D2000 00029764 OFFSET(+0764)
GPR 0-3 00000010 0001C10E 22222222 33333333
GPR 4-7 44444444 55555555 66666666 77777777
GPR 8-11 88888888 99999999 AAAAAAAA BBBBBBBB
GPR 12-15 83C48870 00029000 00000067 00000000
STORAGE >>>>> +00 +04 +08 +0C +0---4---8---C---
00029700(+0700) 58101000 48001000 41101002 18E049E0 * .. . ....\ \*
00029710(+0710) D7EC47D0 D71A41E0 002006E0 44E0D724 *P. .P. \ ..\ \P.*
00029720(+0720) 47F0D72A D200D790 100058E0 D78C5AE0 * 0P.K P . \P !\*
00029730(+0730) D7C050E0 D7884EE0 D7805820 D7C45830 *P.&\Ph+\P. .PD .*
00029740(+0740) D7C85840 D7CC5850 D7D05860 D7D45870 *PH P. &P. -PM .*
00029750(+0750) D7D85880 D7DC5890 D7E058A0 D7E458B0 *PQ .P. P\ .PU .*
00029760(+0760) D7E81FFF 3D000000 00000000 00000000 *PY... *
00029770(+0770) C2C7D540 D6C640E8 D6E4D940 C4C1E3C1 *BGN OF YOUR DATA*
00029780(+0780) 00000000 0000103C 00000067 00000064 * .. . .*
00029790(+0790) D7C1D9C1 D4C5E3C5 D940E2E3 D9C9D5C7 *PARAMETER STRING*
000297A0(+07A0) 00000000 00000000 00000000 00000000 * *
000297B0(+07B0) C5D5C440 D6C640E8 D6E4D940 C4C1E3C1 *END OF YOUR DATA*
000297C0(+07C0) 00000003 22222222 33333333 44444444 * ......... *
000297D0(+07D0) 55555555 66666666 77777777 88888888 * ........hhhh*
000297E0(+07E0) 99999999 AAAAAAAA BBBBBBBB 00200000 *rrrr . *
プログラムが異常終了した場合
プログラムに誤りがあって異常終了(ABEND)すると、プログラムの実行は停止されます。
YOUR PROGRAM ABENDED(S0C7) OFFSET(+073A)
PSW = 078D2000 0002973A ILC=4 INTC=07
GPR 0-3 00000010 0001C10E 00006D28 0001104F
GPR 4-7 0001204E 000101F4 80006FE9 0000810C
GPR 8-11 0000004E 00010368 03C4A86E 03C4986F
GPR 12-15 83C48870 00029000 00000067 00029000
STORAGE >>>>> +00 +04 +08 +0C +0---4---8---C---
00029700(+0700) 58101000 48001000 41101002 18E049E0 * .. . ....\ \*
00029710(+0710) D7EC47D0 D71A41E0 002006E0 44E0D724 *P. .P. \ ..\ \P.*
00029720(+0720) 47F0D72A D200D790 100058E0 D78C5AE0 * 0P.K P . \P !\*
00029730(+0730) D7C050E0 D7884FE0 D7805820 D7C45830 *P.&\Ph|\P. .PD .*
00029740(+0740) D7C85840 D7CC5850 D7D05860 D7D45870 *PH P. &P. -PM .*
00029750(+0750) D7D85880 D7DC5890 D7E058A0 D7E458B0 *PQ .P. P\ .PU .*
00029760(+0760) D7E81FFF 3D000000 00000000 00000000 *PY... *
00029770(+0770) C2C7D540 D6C640E8 D6E4D940 C4C1E3C1 *BGN OF YOUR DATA*
00029780(+0780) 00000000 00000000 00000067 00000064 * . .*
00029790(+0790) D7C1D9C1 D4C5E3C5 D940E2E3 D9C9D5C7 *PARAMETER STRING*
000297A0(+07A0) 00000000 00000000 00000000 00000000 * *
000297B0(+07B0) C5D5C440 D6C640E8 D6E4D940 C4C1E3C1 *END OF YOUR DATA*
000297C0(+07C0) 00000003 22222222 33333333 44444444 * ......... *
000297D0(+07D0) 55555555 66666666 77777777 88888888 * ........hhhh*
000297E0(+07E0) 99999999 AAAAAAAA BBBBBBBB 00200000 *rrrr . *
ABENDEDに続くS0CxがABENDコードです。システム・コードのマニュアルを見て原因を調べます。S0C4ならメモリーのアクセス違反、S0C7はデータ例外、S0C9なら0で除算しようとしたです。OFFSETが示す値はプログラムのどこでABENDしたかを示すオフセット値です。+073Aであれば、プログラムの先頭からx73A番地の直前の命令でABENDしたことを示します。分岐命令を間違えプログラム外のとんでもない所へジャンプしたような場合、オフセットは正しく表示されない場合があります。飛び先をラベルでなくレジスターで指定する場合は十分に注意して下さい。オフセットがどの命令に対応するかはアセンブル・リストを見れば簡単にわかります。なぜそれがエラーになるのかは、機械語命令のマニュアルやリファレンスなどを参考にして調べます。
ABENDして実行が停止しても実行結果は出力されています。汎用レジスター2から15の値やメモリーの内容はABENDした時点の内容です。
簡単なサンプル①(太字の部分が記述したコードとデータ)
*********************************************************************** * AVAILABLE YOUR ASSEMBLER LANGUAGE CODE AT HERE. * * ===================================================== * * GR1 ---> AS ENTRY POINT(PLIST FOR EXEC PARAMETER) * * GR13 --> BASE REGISTER AND OUR REGISTER SAVEAREA * *********************************************************************** L 2,F100 LOAD +100 A 2,=F'3' ADD +3 ST 2,WORK SAVE RESULT(+103) CVD 2,DOUBLE CONVERT IT TO PACKED DECIMAL LA 3,3 LOAD FIXED VALUE TO GPRS LA 4,4 LA 5,5 LA 6,6 LA 7,7 LA 8,8 LA 9,9 LA 10,10 LA 11,11 LA 14,14 SLR 15,15 *=====================================================================* EXITPROC DS 0H EXIT PROCEDURE AT HERE @EDUCNTL EXIT EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *=====================================================================* YOURDATA DS 0D USER DATA AREA START AT HERE DC C'BGN OF YOUR DATA' F100 DC F'100' CONSTANT VALUE +100 WORK DC F'0' RESULT AREA(BINARY) DOUBLE DC D'0' RESULT AREA(PACKED DECIMAL) DC C'END OF YOUR DATA' *********************************************************************** @EDUCNTL END EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *********************************************************************** *------- YREGS , EXPAND GPR EQUATIONS(z/OS ONLY) END レジスターを数字ではなく、R2やR10のように頭にRを付けて表記したい場合は、 L R2,F100 LOAD +100 A R2,=F'3' ADD +3 EQUステートメントをプログラムの後ろ(END命令の前)に定義します。 R2 EQU 2 R10 EQU 10 z/OSであれば、OSが提供するYREGSマクロを利用できます。 ひな型内の以下の部分のコメントを外して、マクロ命令を有効にします。 YREGS , EXPAND GPR EQUATIONS(z/OS ONLY) z/OS以外ではYREGSマクロは提供されていないので、 自分でEQUステートメントを定義します。 R0 EQU 0 GENERAL REGISTER 0 R1 EQU 1 GENERAL REGISTER 1 R2 EQU 2 GENERAL REGISTER 2 R3 EQU 3 GENERAL REGISTER 3 R4 EQU 4 GENERAL REGISTER 4 R5 EQU 5 GENERAL REGISTER 5 R6 EQU 6 GENERAL REGISTER 6 R7 EQU 7 GENERAL REGISTER 7 R8 EQU 8 GENERAL REGISTER 8 R9 EQU 9 GENERAL REGISTER 9 R10 EQU 10 GENERAL REGISTER 10 R11 EQU 11 GENERAL REGISTER 11 R12 EQU 12 GENERAL REGISTER 12 R13 EQU 13 GENERAL REGISTER 13 R14 EQU 14 GENERAL REGISTER 14 R15 EQU 15 GENERAL REGISTER 15
-
MVS3.8での実行結果リスト(実行結果はリストの最後尾に出ています)
簡単なサンプル②(ABENDする例)
*********************************************************************** * AVAILABLE YOUR ASSEMBLER LANGUAGE CODE AT HERE. * * ===================================================== * * GR1 ---> AS ENTRY POINT(PLIST FOR EXEC PARAMETER) * * GR13 --> BASE REGISTER AND OUR REGISTER SAVEAREA * *********************************************************************** L 2,F100 LOAD +100 A 2,=F'3' ADD +3 ST 2,WORK SAVE RESULT(+103) CVB 2,DOUBLE CONVERT IT TO PACKED DECIMAL (本来ならCVD命令なのを誤ってCVBとしたもの) (DOUBLE領域には正しいパック10進数が入って いないためS0C7でABENDする) LA 3,3 LOAD FIXED VALUE TO GPRS LA 4,4 LA 5,5 LA 6,6 LA 7,7 LA 8,8 LA 9,9 LA 10,10 LA 11,11 LA 14,14 SLR 15,15 *=====================================================================* EXITPROC DS 0H EXIT PROCEDURE AT HERE @EDUCNTL EXIT EXPAND CNTL CODE, NEVER CHANGE/MODIFY THIS STMT *=====================================================================* YOURDATA DS 0D USER DATA AREA START AT HERE DC C'BGN OF YOUR DATA' F100 DC F'100' CONSTANT VALUE +100 WORK DC F'0' RESULT AREA(BINARY) DOUBLE DC D'0' RESULT AREA(PACKED DECIMAL) DC C'END OF YOUR DATA' ***********************************************************************
-
MVS3.8での実行結果リスト(実行結果はリストの最後尾に出ています)