HELLO WORLD sobre el OS/360MVT

![DSCF2527.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449377/755f4794-54e9-ee14-c4c9-ec8d59bd8668.jpeg)

ジョブを実行したときのメインコンソールの様子

# はじめに
今は昔、メインフレームありけり。ビルの1フロアを占領し、プログラムがこけると大量のABENDダンプを吐き出す怪物なり。

こないだ家で本を積みなおしていたらIBMメインフレームのアセンブラプログラミングの本が出てきました。アメリカの大学で学生が使う教科書のようで、電話帳なみに分厚い本です。

この本を読んでいて久しぶりにアセンブラでプログラムを書きたくなったので再チャレンジすることにしました。もっとも、実機はないのでNanoPi-NEO上で動くHercules上のOS/360MVT上でですが....。

# やること
※Hercules上でのOS/360MVTシステム生成についてはここでは触れません。
パンチカードリーダ上のデータカード(HELLO, WORLD)を読み取り、ラインプリンタに出力する。

# メインフレームの入出力
これから登場するIBM System/360の周辺機器を紹介します。

## カードリーダ
データをパンチしたパンチカードをむしゃむしゃ食べる(読み取る)、なんとも地球に優しくない機械。1枚のパンチカードには80文字が記録できます。今でも端末の桁数にその名残があります。

Hercules上ではただのテキストファイルだけど、カードリーダがばりばりとパンチカードを食べてる様子を妄想しながら実行します。

## ラインプリンタ
ジョブの実行結果を打ち出す、なんとも地球に優しくない機械。1行132文字。古い機械だと機械式だけど、私が大学で見たのは畳2畳分くらいある巨大なレーザープリンタだったなぁ。

プログラムがエラーすると大量のABENDダンプがここから吐き出され、プログラマを悩ませることに....。

## コンソール
怪物と神官(オペレータ)のコミュニケーションツール。実機ではごく限られた人しか触れない。

## 磁気テープ
オープンリールの磁気テープを読み書きする機械。前のふたを開けてテープをセットし、ふたを閉めてから緑のボタンを押すとぐるぐる回る。
計算の途中結果やアセンブルされた機械語を一時保存したりするのに使用される。

# プログラム
カードリーダにセットされた(HELLO, WORLDがパンチしてある)データカードをGETマクロで読み取り、MVC命令で出力領域にコピーし、ラインプリンタにPUTマクロで打ち出します。

```ASMFCLG.JCL
//HELLO  JOB CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1)
// EXEC ASMFCLG,REGION.ASM=256K
//ASM.SYSUT1 DD UNIT=SYSDA
//ASM.SYSUT2 DD UNIT=SYSDA
//ASM.SYSUT3 DD UNIT=SYSDA
//ASM.SYSGO  DD UNIT=SYSDA
//ASM.SYSIN DD *
         PRINT NOGEN
PRINTOUT START
         STM   14,12,12(13)
         BALR  12,0
         USING *,12
         ST    13,SAVEAREA+4
         LA    13,SAVEAREA
*
         OPEN  (INFILE,INPUT,OUTFILE,OUTPUT)
         MVC   OUTAREA(132),SPACES
         GET   INFILE,RECORD
         MVC   OUTTEXT(80),INTEXT
         PUT   OUTFILE,OUTAREA
EOF      CLOSE (INFILE,,OUTFILE)
*
         L     13,SAVEAREA+4
         LM    14,12,12(13)
         BR    14
*
SAVEAREA DS    18F
INFILE   DCB   DDNAME=INFILE,MACRF=GM,BLKSIZE=80,LRECL=80,             *
               DSORG=PS,EODAD=EOF
OUTFILE  DCB   DDNAME=OUTFILE,MACRF=PM,BLKSIZE=132,LRECL=132,          *
               DSORG=PS
RECORD   DS    0CL80
INTEXT   DS    CL80
SPACES   DC    CL1' '
OUTAREA  DS    0CL132
OUTTEXT  DS    CL132
         END
/*
//GO.OUTFILE DD SYSOUT=A
//GO.SYSUDUMP DD SYSOUT=A
//GO.INFILE DD *
HELLO, WORLD!!
/*
//
```
上記リスト中第1桁が'//'ではじまっているのはJCL(ジョブ制御言語、今でいうシェルスクリプトみたいなもの)の構文です。DDコマンドはプログラム内部のファイル名(DD名)と実際の入出力機器を結びつけるコマンドです。

実際のプログラムは"//ASM.SYSIN DD \*"以下"/*"までの行です。

## 解説

### プログラムの始まりと終わり

OS/360上ではプログラムはOSのイニシエータから呼び出されるサブルーチンのように書きます。
プログラムの始まりの部分はこういう風に書くのがお約束。

```
PRINTOUT START
         STM   14,12,12(13)
         BALR  12,0
         USING *,12
         ST    13,SAVEAREA+4
         LA    13,SAVEAREA
```
呼び出されたときのレジスタの内容をSTM命令でメモリにセーブします。レジスタ12番にはこのプログラムのベースアドレスをBALR命令で入れます。その後自分自身のレジスタ保存領域の番地をレジスタ13番に入れます。

プログラムの終わりの部分はこういう風に書きます。

```
         L     13,SAVEAREA+4
         LM    14,12,12(13)
         BR    14
```

保存してあるレジスタをLM命令で戻し、レジスタ14番に入っている戻り番地にジャンプします。

これを見て気づいた人もいるかもしれませんが、ARMのサブルーチンの呼び出し方はこれとほぼ同じです。違いはSystem/360の場合メモリの番地はベースレジスタ(上の例ではレジスタ12番)相対なのに対し、ARMの場合はプログラムカウンタ相対で指定するといった程度です。

なお、今回は大丈夫ですが、ベースレジスタ相対でアクセスできるのは4096バイトに限られています。

### ファイルのオープンとクローズ

OS/360上ではUNIX系のOSと同様、入出力機器を「ファイル」として扱います。(コンソールだけは特別扱いで、WTO/WTORマクロで直接アクセスします)

これにより、入出力機器の違いを吸収しています。UNIX系OSでは当たり前の「なんでもファイル」の発想の原点がこんなところにあります。

ファイルの特性はDCB疑似命令で次のように書きます。

```
INFILE   DCB   DDNAME=INFILE,MACRF=GM,BLKSIZE=80,LRECL=80,             *
               DSORG=PS,EODAD=EOF
OUTFILE  DCB   DDNAME=OUTFILE,MACRF=PM,BLKSIZE=132,LRECL=132,          *
               DSORG=PS
```
行の後ろのアステリスク('\*')は文が1行に収まらないときに72桁目に書きます。これは絶対に72桁目でないといけません。間違えるとアセンブラがエラーを出します。

'INFILE'、'OUTFILE'がこのプログラム上でのファイルの名前、いわゆるDD名です。MACRFはそのファイルに対しどういう入出力方式をとるかの指定です。GMだとGETマクロによる入力、PMだとPUTマクロによる出力です。LRECLはレコード長、1回のマクロ呼び出しで入出力される文字数、BLKSIZEはブロックサイズです。今回はカードリーダとラインプリンタなのでレコード長にひとしいですが、磁気テープのように1回の動作で複数レコードの読み書きができる場合はLRECLより大きい値になります。

ファイルは使用する前にオープンする必要があります。UNIX系のOSであれば標準入出力とエラー出力は常時オープンされていますが、OS/360の場合は明示的にオープンします。

```
         OPEN  (INFILE,INPUT,OUTFILE,OUTPUT)
```

使用が終わったファイルはCLOSEマクロでクローズして後始末します。

```
EOF      CLOSE (INFILE,,OUTFILE)
```

### ファイルの入出力

```
         MVC   OUTAREA(132),SPACES
         GET   INFILE,RECORD
         MVC   OUTTEXT(80),INTEXT
         PUT   OUTFILE,OUTAREA
```

最初にMVC命令で出力領域を空白文字で埋めます。埋めないと後ろにゴミが出力されます。
次にGETマクロで入力に指定したファイル(この場合はカードリーダ)からデータを読み込みます。
次に入力されたデータ(INTEXTに入っています)を出力領域にMVC命令でコピーします。

MVC命令の第1オペランド後ろのかっこ内の数字は「何バイトコピーするか」の指定です。
コピー元とコピー先が同じサイズであれば省略可能(アセンブラが決めてくれる)ですが、この場合は
異なるので明示的に指定します。

PUTマクロを呼び出して出力に指定したファイル(この場合はラインプリンタ)にデータを出力します。

# 実行

カードリーダに上記のカードデッキをかけます(実際にはHercules上でリーダにファイルを割り当てます)。

アセンブラが起動してソースをアセンブルし、リンケージエディタが実行モジュールを生成します。実行段階で次のJCLを読み取ります。'GO.INFILE'以下が入力データです。

```
//GO.OUTFILE DD SYSOUT=A
//GO.SYSUDUMP DD SYSOUT=A
//GO.INFILE DD *
HELLO, WORLD!!
/*
```

うまくいくとラインプリンタ(に割り付けたファイル)にジョブの実行結果が出力されます。

```
//HELLO  JOB CLASS=A,MSGCLASS=A,MSGLEVEL=(1,1)
// EXEC ASMFCLG,REGION.ASM=256K
XXASM    EXEC  PGM=IEUASM,PARM=LOAD,REGION=50K                          00020018
XXSYSLIB DD    DSNAME=SYS1.MACLIB,DISP=SHR                         IEUD 00040016
//ASM.SYSUT1 DD UNIT=SYSDA
X/SYSUT1 DD    DSNAME=&SYSUT1,UNIT=SYSSQ,SPACE=(1700,(400,50)),        X00050018
XX             SEP=(SYSLIB)                                             00060018
//ASM.SYSUT2 DD UNIT=SYSDA
X/SYSUT2 DD    DSNAME=&SYSUT2,UNIT=SYSSQ,SPACE=(1700,(400,50))          00070018
//ASM.SYSUT3 DD UNIT=SYSDA
X/SYSUT3 DD    DSNAME=&SYSUT3,SPACE=(1700,(400,50)),                   X00080018
XX             UNIT=(SYSSQ,SEP=(SYSUT2,SYSUT1,SYSLIB))                  00090018
XXSYSPRINT DD  SYSOUT=A                                                 00140000
XXSYSPUNCH DD  SYSOUT=B                                                 00150018
//ASM.SYSGO  DD UNIT=SYSDA
X/SYSGO     DD DSNAME=&LOADSET,UNIT=SYSSQ,SPACE=(80,(200,50)),         X00160000
XX             DISP=(MOD,PASS)                                          00180000
//ASM.SYSIN DD *
IEF236I ALLOC. FOR HELLO    ASM
IEF237I 350   ALLOCATED TO SYSLIB
IEF237I 151   ALLOCATED TO SYSUT1
IEF237I 352   ALLOCATED TO SYSUT2
IEF237I 150   ALLOCATED TO SYSUT3
IEF237I 352   ALLOCATED TO SYSPRINT
IEF237I 151   ALLOCATED TO SYSPUNCH
IEF237I 352   ALLOCATED TO SYSGO
IEF237I 150   ALLOCATED TO SYSIN

                                              EXTERNAL SYMBOL DICTIONARY                                       PAGE    1
SYMBOL   TYPE ID  ADDR  LENGTH LD ID                                                                      03.31 12/08/91


PRINTOUT  SD  01 000000 00023D
                                                                                                                                             PAGE    1


  LOC  OBJECT CODE    ADDR1 ADDR2  STMT   SOURCE STATEMENT                                            F04MAR74  12/08/91

                                      1          PRINT NOGEN
000000                                2 PRINTOUT START
000000 90EC D00C            0000C     3          STM   14,12,12(13)
000004 05C0                           4          BALR  12,0
000006                                5          USING *,12
000006 50D0 C05E            00064     6          ST    13,SAVEAREA+4
00000A 41D0 C05A            00060     7          LA    13,SAVEAREA
                                      8 *
                                      9          OPEN  (INFILE,INPUT,OUTFILE,OUTPUT)
00001E D283 C1B3 C1B2 001B9 001B8    17          MVC   OUTAREA(132),SPACES
                                     18          GET   INFILE,RECORD
000032 D24F C1B3 C162 001B9 00168    23          MVC   OUTTEXT(80),INTEXT
                                     24          PUT   OUTFILE,OUTAREA
                                     29 EOF      CLOSE (INFILE,,OUTFILE)
                                     37 *
000056 58D0 C05E            00064    38          L     13,SAVEAREA+4
00005A 98EC D00C            0000C    39          LM    14,12,12(13)
00005E 07FE                          40          BR    14
                                     41 *
000060                               42 SAVEAREA DS    18F
                                     43 INFILE   DCB   DDNAME=INFILE,MACRF=GM,BLKSIZE=80,LRECL=80,             *
                                                       DSORG=PS,EODAD=EOF
                                     97 OUTFILE  DCB   DDNAME=OUTFILE,MACRF=PM,BLKSIZE=132,LRECL=132,          *
                                                       DSORG=PS
000168                              151 RECORD   DS    0CL80
000168                              152 INTEXT   DS    CL80
0001B8 40                           153 SPACES   DC    CL1' '
0001B9                              154 OUTAREA  DS    0CL132
0001B9                              155 OUTTEXT  DS    CL132
                                    156          END
                                                                                                     RELOCATION DICTIONARY                                          PAGE   1


 POS.ID   REL.ID   FLAGS   ADDRESS                                                                              12/08/91

   01       01      08     000015
   01       01      08     000019
   01       01      08     00004D
   01       01      08     000051
   01       01      08     0000C9
                                                                              CROSS-REFERENCE                                                   PAGE    1


SYMBOL    LEN  VALUE  DEFN     REFERENCES                                                                       12/08/91

EOF      00004 000048 00031   0065
INFILE   00004 0000A8 00047   0013  0019  0033
INTEXT   00080 000168 00152   0023
OUTAREA  00132 0001B9 00154   0017  0026
OUTFILE  00004 000108 00101   0015  0025  0035
OUTTEXT  00132 0001B9 00155   0023
PRINTOUT 00001 000000 00002
RECORD   00080 000168 00151   0020
SAVEAREA 00004 000060 00042   0006  0007  0038
SPACES   00001 0001B8 00153   0017



NO STATEMENTS FLAGGED IN THIS ASSEMBLY
*STATISTICS*     SOURCE RECORDS (SYSIN) =    30      SOURCE RECORDS (SYSLIB) =  2921
*OPTIONS IN EFFECT*   LIST, DECK, LOAD, NORENT, XREF, NOTEST, ALGN, OS, NOTERM, LINECNT =  55
   59 PRINTED LINES

IEF142I - STEP WAS EXECUTED - COND CODE 0000
IEF285I   SYS1.MACLIB                                  KEPT
IEF285I   VOL SER NOS= MVTRES.
IEF285I   SYS91342.T020452.RV000.HELLO.SYSUT1          DELETED
IEF285I   VOL SER NOS= WORK01.
IEF285I   SYS91342.T020452.RV000.HELLO.SYSUT2          DELETED
IEF285I   VOL SER NOS= WORK02.
IEF285I   SYS91342.T020452.RV000.HELLO.SYSUT3          DELETED
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.SV000.HELLO.R0000067        SYSOUT
IEF285I   VOL SER NOS= WORK02.
IEF285I   SYS91342.T020452.SV000.HELLO.R0000068        SYSOUT
IEF285I   VOL SER NOS= WORK01.
IEF285I   SYS91342.T020452.RV000.HELLO.LOADSET         PASSED
IEF285I   VOL SER NOS= WORK02.
IEF285I   SYS91342.T020452.RV000.HELLO.S0000069        SYSIN
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.RV000.HELLO.S0000069        DELETED
IEF285I   VOL SER NOS= SYSRES.
IEF373I STEP /ASM     / START 91342.0331
IEF374I STEP /ASM     / STOP  91342.0331 CPU   0MIN 01.36SEC MAIN 256K LCS   0K
XXLKED   EXEC  PGM=IEWL,PARM=(XREF,LET,LIST,NCAL),REGION=96K,          X00210018
XX             COND=(8,LT,ASM)                                          00220018
XXSYSLIN DD    DSNAME=&LOADSET,DISP=(OLD,DELETE)                        00240000
XX       DD    DDNAME=SYSIN                                             00260000
XXSYSLMOD DD   DSNAME=&GOSET(GO),UNIT=SYSDA,SPACE=(1024,(50,20,1)),    X00280000
XX             DISP=(MOD,PASS)                                          00300000
XXSYSUT1 DD    DSNAME=&SYSUT1,UNIT=(SYSDA,SEP=(SYSLIN,SYSLMOD)),       X00320018
XX             SPACE=(1024,(50,20))                                     00340000
XXSYSPRINT DD  SYSOUT=A                                                 00360000
IEF236I ALLOC. FOR HELLO    LKED
IEF237I 352   ALLOCATED TO SYSLIN
IEF237I 150   ALLOCATED TO SYSLMOD
IEF237I 151   ALLOCATED TO SYSUT1
IEF237I 352   ALLOCATED TO SYSPRINT

F128-LEVEL LINKAGE EDITOR OPTIONS SPECIFIED XREF,LET,LIST,NCAL
          DEFAULT OPTION(S) USED -  SIZE=(131072,18432)


                                                CROSS REFERENCE TABLE


  CONTROL SECTION                       ENTRY

    NAME    ORIGIN  LENGTH                NAME   LOCATION     NAME   LOCATION     NAME   LOCATION     NAME   LOCATION

  PRINTOUT      00     23D



  LOCATION  REFERS TO SYMBOL  IN CONTROL SECTION             LOCATION  REFERS TO SYMBOL  IN CONTROL SECTION


 ENTRY ADDRESS       00
 TOTAL LENGTH       240

****GO        DOES NOT EXIST BUT HAS BEEN ADDED TO DATA SET


IEF142I - STEP WAS EXECUTED - COND CODE 0000
IEF285I   SYS91342.T020452.RV000.HELLO.LOADSET         DELETED
IEF285I   VOL SER NOS= WORK02.
IEF285I   SYS91342.T020452.RV000.HELLO.GOSET           PASSED
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.RV000.HELLO.SYSUT1          DELETED
IEF285I   VOL SER NOS= WORK01.
IEF285I   SYS91342.T020452.SV000.HELLO.R0000070        SYSOUT
IEF285I   VOL SER NOS= WORK02.
IEF373I STEP /LKED    / START 91342.0331
IEF374I STEP /LKED    / STOP  91342.0331 CPU   0MIN 00.09SEC MAIN 128K LCS   0K
XXGO     EXEC  PGM=*.LKED.SYSLMOD,COND=((8,LT,ASM),(4,LT,LKED))         40360018
//GO.OUTFILE DD SYSOUT=A
//GO.SYSUDUMP DD SYSOUT=A
//GO.INFILE DD *
//
IEF236I ALLOC. FOR HELLO    GO
IEF237I 150   ALLOCATED TO PGM=*.DD
IEF237I 352   ALLOCATED TO OUTFILE
IEF237I 150   ALLOCATED TO SYSUDUMP
IEF237I 150   ALLOCATED TO INFILE

HELLO, WORLD!!

IEF142I - STEP WAS EXECUTED - COND CODE 3520
IEF285I   SYS91342.T020452.RV000.HELLO.GOSET           PASSED
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.SV000.HELLO.R0000071        SYSOUT
IEF285I   VOL SER NOS= WORK02.
IEF285I   SYS91342.T020452.SV000.HELLO.R0000072        DELETED
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.RV000.HELLO.S0000073        SYSIN
IEF285I   VOL SER NOS= SYSRES.
IEF285I   SYS91342.T020452.RV000.HELLO.S0000073        DELETED
IEF285I   VOL SER NOS= SYSRES.
IEF373I STEP /GO      / START 91342.0331
IEF374I STEP /GO      / STOP  91342.0331 CPU   0MIN 00.03SEC MAIN   8K LCS   0K
IEF285I   SYS91342.T020452.RV000.HELLO.GOSET           DELETED
IEF285I   VOL SER NOS= SYSRES.
IEF375I  JOB /HELLO   / START 91342.0331
IEF376I  JOB /HELLO   / STOP  91342.0331 CPU   0MIN 01.48SEC
```