Let's start with something simpler, an IEFBR14 program. This
program does almost nothing but it's a good place to start
learning S/370 assembler. Here is the S/370 Assembler source for IEFBR14:
IEFBR14 CSECT , SLR 15,15 BR 14 END , That's it. If you're using the Turnkey system, you can type this into a MVS file (I recommend RPF) and submit it to MVS using the job shown below. This job assembles, link edits, and executes our S/370 Assembler program in batch under MVS. Throughout the tutorial, I will show the actual JCL I use; you will have to modify it as appropriate for your environment. //IEFBR14 JOB CLASS=A,MSGCLASS=A,RESTART=ASMF //*-------------------------------------------------------------------- //IEHPROGM EXEC PGM=IEHPROGM //SYSPRINT DD SYSOUT=* //MVS3380 DD UNIT=3380,VOL=SER=MVS809,DISP=SHR //SYSIN DD * SCRATCH DSNAME=JMM.S370ASM.LOAD,VOL=3380=MVS809 UNCATLG DSNAME=JMM.S370ASM.LOAD //*-------------------------------------------------------------------- //ALLOC EXEC PGM=IEFBR14 //LOAD DD DSN=JMM.S370ASM.LOAD, // UNIT=3380,VOL=SER=MVS809, // SPACE=(CYL,(20,0,15)), // DCB=(RECFM=U,BLKSIZE=32760), // DISP=(,CATLG) //*-------------------------------------------------------------------- //ASMF EXEC PGM=IFOX00,REGION=2048K //SYSLIB DD DSN=SYS1.AMODGEN,DISP=SHR // DD DSN=SYS1.AMACLIB,DISP=SHR //SYSUT1 DD DISP=(NEW,DELETE),SPACE=(1700,(900,100)),UNIT=SYSDA //SYSUT2 DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA //SYSUT3 DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA //SYSPRINT DD SYSOUT=* //SYSPUNCH DD DSN=&&OBJ,UNIT=SYSDA,SPACE=(CYL,1),DISP=(,PASS) //SYSIN DD * IEFBR14 CSECT , SLR 15,15 BR 14 END , //*------------------------------------------------------------------- //LKED EXEC PGM=IEWL, // COND=(5,LT,ASMF), // PARM='LIST,MAP,XREF,LET,NCAL,RENT' //SYSPRINT DD SYSOUT=* //SYSLMOD DD DSN=JMM.S370ASM.LOAD,DISP=SHR //* SLIB DD DSN=SYS1.LINKLIB,DISP=SHR //SYSUT1 DD UNIT=SYSDA,SPACE=(TRK,(5,5)) //SYSLIN DD DSN=&&OBJ,DISP=(OLD,DELETE) // DD * NAME IEFBR14(R) //*------------------------------------------------------------------- //IEFBR14 EXEC PGM=IEFBR14 //STEPLIB DD DSN=JMM.S370ASM.LOAD,DISP=SHR // The output produced by executing this job appears at the bottom of this page. Let's take each step in order, and see what each one does. The first step, IEHPROGM, deletes and uncatalogs a library if it exists. This step will produce a non-zero return code, which you can safely ignore, if the library does not already exist. The next step, ALLOC, creates the library anew. The assembly step, ASMF, reads the S/370 assembler source code and produces an object deck. The Link Edit step, LKED, reads the object deck and produces an executable load module. The final step, IEFBR14, executes our S/370 Assembler program from the load module. Both IEHPROGM and IBM's IEFBR14 program are standard utilities, so we won't say anything else about them. If you're interested in them, check some of the links in the H390-MVS group's Links section. We begin examing this MVS job with the ASMF step, which executes the S/370 assembler whose program name is IFOX00.
The S/370 assembler Executing IFOX00 Let's briefly review the DDNAMEs for IFOX00.
When we run our JCL, our assembly gets a return code zero from IFOX00, so the source code was assembled cleanly. We can tell from the message in our job's output that says: IEF142I IEFBR14 ASMF - STEP WAS EXECUTED - COND CODE 0000
The MVS38j IFOX00 assembler, the VM "assemble" command, and about any other S/370 assembler you'll run across have some fairly standard requirements on how your source program must be formatted. The S/370 assembler standard is that source records are 80 bytes in length. MVS source code datasets can be blocked or unblocked; you'll probably want to block them using DCB attributes such as RECFM=FB,LRECL=80,BLKSIZE=3200. For the most part, S/370 assembler source is in uppercase, although comments can usually be mixed case. If you're using a more modern assembler, such as HLASM, most of the source code can be mixed case. Source statements come in several varieties: comments, assembler statements, and instructions. Comments contain an asterisk (*) in column one. Columns are usually numbered beginning with one. Pretty much anything goes for comment lines, they're freeform. Instructions are easy to identify: they're documented in POPs and the REFSUM. Everything else is an assembler statement, which provides instructions to the assembler. Each S/370 assembler instruction is divided into several (somewhat freeform) fields: label, opcode, operand(s), comments, continuation column, and sequence numbers.
Labels are optional, and if present must begin in column one. They are used to defined symbolic locations, such as someplace you might like to branch. In S/370 assembler, labels can be from one to eight bytes in length. For now, you can think of IEFBR14 as a label although we'll describe it more specifically later. If you're using the Turnkey system, I believe IFOX00 has Greg Price's usermod applied which allows entirely blank source lines to also appear in the source file. Without Greg's usermod or something similar, IFOX00 would complain when it saw an entirely blank line.
When we execute IFOX00, it produces the output shown below. MVS printer output is normally wider than most user's web browsers display, so you'll have to scroll right and left to see the entire output. The assembler numbers its output pages on the far right. |
EXTERNAL SYMBOL DICTIONARY PAGE 1 SYMBOL TYPE ID ADDR LENGTH LDID ASM 0201 02.32 04/26/76 IEFBR14 SD 0001 000000 000004 PAGE 2 LOC OBJECT CODE ADDR1 ADDR2 STMT SOURCE STATEMENT ASM 0201 02.32 04/26/76 000000 1 IEFBR14 CSECT , 000000 1FFF 2 SLR 15,15 000002 07FE 3 BR 14 4 END , ASSEMBLER DIAGNOSTICS AND STATISTICS PAGE 3 ASM 0201 02.32 04/26/76 NO STATEMENTS FLAGGED IN THIS ASSEMBLY HIGHEST SEVERITY WAS 0 OPTIONS FOR THIS ASSEMBLY ALIGN, ALOGIC, BUFSIZE(STD), DECK, ESD, FLAG(0), LINECOUNT(55), LIST, NOMCALL, YFLAG, WORKSIZE(2097152) NOMLOGIC, NONUMBER, NOOBJECT, NORENT, RLD, NOSTMT, NOLIBMAC, NOTERMINAL, NOTEST, XREF(SHORT) SYSPARM() WORK FILE BUFFER SIZE/NUMBER =19066/ 1 TOTAL RECORDS READ FROM SYSTEM INPUT 4 TOTAL RECORDS READ FROM SYSTEM LIBRARY 0 TOTAL RECORDS PUNCHED 3 TOTAL RECORDS PRINTED 22
Most of this section on deciphering the assemble's output is also covered in the S/370 Language Guide. However, since we have yet to locate a copy of this manual that's available for download, I'll go into some of the details here. Page 1, the External Symbol Dictionary Page 2, the program listing
Page 3, ASSEMBLER DIAGNOSTICS AND STATISTICS
Next, we examine the LKED step, which executes the S/370 linkage editor whose program name is IEWL. The linkage editor is also sometimes referred to as LKED, an abbreviation for LinKage EDitor.
The S/370 Linkage Editor Executing IEWL
Let's briefly review the DDNAMEs for IEWL.
SYSPRINT is the listing of the linkage edit.
SYSLMOD is the resulting load module, if one was produced.
SYSUT1 is a work file.
SYSLIN is the primary input. Input object decks and
control statements can be present on SYSLIN.
|
F64-LEVEL LINKAGE EDITOR OPTIONS SPECIFIED LIST,MAP,XREF,LET,NCAL,RENT DEFAULT OPTION(S) USED - SIZE=(165888,55296) IEW0000 NAME IEFBR14(R) CROSS REFERENCE TABLE CONTROL SECTION ENTRY NAME ORIGIN LENGTH NAME LOCATION NAME LOCATION NAME LOCATION NAME LOCATION IEFBR14 00 4 ENTRY ADDRESS 00 TOTAL LENGTH 8 ****IEFBR14 NOW REPLACED IN DATA SET AUTHORIZATION CODE IS 0. **MODULE HAS BEEN MARKED REENTERABLE, AND REUSABLE.
Let's briefly examine the Linkage Editor's output. We can't begin to do justice to explaining the MVS Linkage Editor as it's worthy of a tutorial of its own. You might notice that the assembler level F matches the Linkage Editor level F. That's frequently how things go; they tend to stay in sync with each other, since they're so dependent on each other. If you'll refer back to the MVS JCL we used to execute the IEWL program, you'll notice we passed some PARM values; these are where the linkage editor retrieves it's options. LKED OPTIONS were LIST (show the input statements from SYSLIN), MAP (produce a load module map), XREF (produce a cross-reference), LET (mark the module executable even if it contains errors), NCAL (do Not use auto-CALl facility to resolve unresolved symbols), and RENT (mark the module reentrant). I'll only mention a few of these options. If you omit NCAL, the SYSLIB DDNAME in the LKED step will be opened and searched for external symbols that can be used to satisfy LKED SYSLIN input requirements. First, SYSLIN is where we put the assembler's output object deck; LKED read it in as part of it's primary input. We concatenated an instream dataset (DD *) after the object deck, and provided a NAME statement with the replace (R) option. This NAME statement specifies the load module's name that gets stored in the load library's directory. The replace option says it's OK to replace the module if it already exists. Notice LKED control statements cannot begin in column 1 (for a somewhat obscure and probably not necessary reason), so we put the NAME in column 2. The Linkage Editor has its own manual, and it would be good to have one of those, as well as the LKED messages manual. There are now two main columns: CONTROL SECTION and ENTRY. We already know what those are: a CSECT or something like it, and an entry point. Beneath each of these two main columns are some subcolumns (for lack of a better term). Control section NAME is our old friend the IEFBR14 CSECT. Next is the ORIGIN column, which is another offset; this time it's the offset from the beginning of the load module. LENGTH means the same thing as the assembler External Symbol Dictionary length. Should a CSECT length not be divisible by 8, LKED will round the next CSECT up to the next doubleword boundary. There's a reason LKED does this, having to do with some of the S/370 instructions that require some of their data to be aligned on a doubleword boundary (meaning a storage address evenly divisible by 8). If LKED did not do this CSECT alignment, then when the assembler produced it's object deck with the objective of placing some storage definition on a doubleword boundary, the data area might not actually end up on a doubleword boundary in the program once it was loaded in storage. So every now and again you'll see some "dead space" in your load modules to satisfy this requirement. As a further aside, doubleword alignment is why the MVS GETMAIN (allocate storage) service provides storage on a doubleword boundary. I've never seen this documented anywhere, but it seems a rational explanation (or so I speculate). Having read all the input, LKED now assigns the ENTRY ADDRESS (again a load module relative offset) to the load module. Our END statement didn't specify an entry point address, and we didn't provide LKED with an ENTRY statement, so LKED takes it's default entry point which is the first CSECT it encounters in the primary input. In this case, it's the IEFBR14 CSECT. TOTAL LENGTH of the load module is 8, just like we know as is required by CSECT alignment (even though there is only one CSECT). ****IEFBR14 NOW REPLACED IN DATASET means LKED respected our (R) option on the NAME statement. LKED places the output load module on the SYSLMOD DDNAME. AUTHORIZATION CODE is a somewhat more advanced topic. I'll limit myself to saying that MVS provides an authorization facility called APF (Authorized Program Facility) used to allow a program to act as an extension of the MVS operating system. Such programs are called Authorized Programs, and they are marked as candidates for this grant of special privileges by linking them with a non-zero authorization code. MVS performs some additional checks before granting this privilege, namely checking that the load module came from an APF library which we won't talk about right now. MODULE HAS BEEN MARKED ... some stuff. Remember our RENT option? Well, reentrant implies reusable and LKED is just being clear about that. What is a reentrant program? It's a program which can be executed by more than one task without requiring another physical copy. MVS makes kind of a big deal out of this, as reentrant programming techniques allow MVS (and user programs) to provide their services with less overhead. The simplest definition (although not quite precise) is that reentrant programs don't modify their own storage. We'll leave the definition of "task" for another day.
Well, that's the Linkage Editor output. So where's the IEFBR14 output? There isn't any. Our IEFBR14 program didn't open any datasets, didn't write any output ... nothing. If you'll glance up at the job's output below, you will see IEF142I IEFBR14 IEFBR14 - STEP WAS EXECUTED - COND CODE 0000 which means our IEFBR14 program produced a zero return code which conventionally means "everything went well, no errors". How did IEFBR14 provide this return code to MVS? For the answer to that question, we'll have to learn a little bit more about how the program executed. Stay tuned.
The following shows the entire MVS printer output our assembly, linkedit, and execution job produced. |
J E S 2 J O B L O G 05.11.01 JOB 12 $HASP373 IEFBR14 STARTED - INIT 1 - CLASS A - SYS BSP1 05.11.01 JOB 12 IEF403I IEFBR14 - STARTED - TIME=05.11.01 05.11.01 JOB 12 IEFBR14 ASMF IFOX00 RC= 0000 05.11.01 JOB 12 IEFBR14 LKED IEWL RC= 0000 05.11.02 JOB 12 IEFBR14 IEFBR14 IEFBR14 RC= 0000 05.11.02 JOB 12 IEF404I IEFBR14 - ENDED - TIME=05.11.02 05.11.02 JOB 12 $HASP395 IEFBR14 ENDED ------ JES2 JOB STATISTICS ------ 26 APR 76 JOB EXECUTION DATE 44 CARDS READ 181 SYSOUT PRINT RECORDS 0 SYSOUT PUNCH RECORDS 0.01 MINUTES EXECUTION TIME 1 //IEFBR14 JOB CLASS=A,MSGCLASS=A,RESTART=ASMF JOB 12 ***-------------------------------------------------------------------- 2 //IEHPROGM EXEC PGM=IEHPROGM 3 //SYSPRINT DD SYSOUT=* 4 //MVS3380 DD UNIT=3380,VOL=SER=MVS809,DISP=SHR 5 //SYSIN DD * ***-------------------------------------------------------------------- 6 //ALLOC EXEC PGM=IEFBR14 7 //LOAD DD DSN=JMM.S370ASM.LOAD, // UNIT=3380,VOL=SER=MVS809, // SPACE=(CYL,(20,0,15)), // DCB=(RECFM=U,BLKSIZE=32760), // DISP=(,CATLG) ***-------------------------------------------------------------------- 8 //ASMF EXEC PGM=IFOX00,REGION=2048K 9 //SYSLIB DD DSN=SYS1.AMODGEN,DISP=SHR 10 // DD DSN=SYS1.AMACLIB,DISP=SHR 11 //SYSUT1 DD DISP=(NEW,DELETE),SPACE=(1700,(900,100)),UNIT=SYSDA 12 //SYSUT2 DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA 13 //SYSUT3 DD DISP=(NEW,DELETE),SPACE=(1700,(600,100)),UNIT=SYSDA 14 //SYSPRINT DD SYSOUT=* 15 //SYSPUNCH DD DSN=&&OBJ,UNIT=SYSDA,SPACE=(CYL,1),DISP=(,PASS) 16 //SYSIN DD * ***------------------------------------------------------------------- 17 //LKED EXEC PGM=IEWL, // COND=(5,LT,ASMF), // PARM='LIST,MAP,XREF,LET,NCAL,RENT' 18 //SYSPRINT DD SYSOUT=* 19 //SYSLMOD DD DSN=JMM.S370ASM.LOAD,DISP=SHR *** SLIB DD DSN=SYS1.LINKLIB,DISP=SHR 20 //SYSUT1 DD UNIT=SYSDA,SPACE=(TRK,(5,5)) 21 //SYSLIN DD DSN=&&OBJ,DISP=(OLD,DELETE) 22 // DD * ***------------------------------------------------------------------- 23 //IEFBR14 EXEC PGM=IEFBR14 24 //STEPLIB DD DSN=JMM.S370ASM.LOAD,DISP=SHR // IEF236I ALLOC. FOR IEFBR14 ASMF IEF237I 248 ALLOCATED TO SYSLIB IEF237I 248 ALLOCATED TO IEF237I 149 ALLOCATED TO SYSUT1 IEF237I 14A ALLOCATED TO SYSUT2 IEF237I 190 ALLOCATED TO SYSUT3 IEF237I JES2 ALLOCATED TO SYSPRINT IEF237I 14B ALLOCATED TO SYSPUNCH IEF237I JES2 ALLOCATED TO SYSIN IEF142I IEFBR14 ASMF - STEP WAS EXECUTED - COND CODE 0000 IEF285I SYS1.AMODGEN KEPT *--------0 IEF285I VOL SER NOS= MVSDLB. IEF285I SYS1.AMACLIB KEPT *--------0 IEF285I VOL SER NOS= MVSDLB. IEF285I SYS76117.T051101.RA000.IEFBR14.R0000002 DELETED *--------8 IEF285I VOL SER NOS= SMP001. IEF285I SYS76117.T051101.RA000.IEFBR14.R0000003 DELETED *--------7 IEF285I VOL SER NOS= SMP002. IEF285I SYS76117.T051101.RA000.IEFBR14.R0000004 DELETED *--------7 IEF285I VOL SER NOS= WORK03. IEF285I JES2.JOB00012.SO0105 SYSOUT IEF285I SYS76117.T051101.RA000.IEFBR14.OBJ PASSED *--------3 IEF285I VOL SER NOS= SMP003. IEF285I JES2.JOB00012.SI0102 SYSIN IEF373I STEP /ASMF / START 76117.0511 IEF374I STEP /ASMF / STOP 76117.0511 CPU 0MIN 00.31SEC SRB 0MIN 00.01SEC VIRT 2048K SYS 208K ************************************************************************************************************************************ * 3. Jobstep of job: IEFBR14 Stepname: ASMF Program name: IFOX00 Executed on 26.04.76 from 05.11.01 to 05.11.01 * * elapsed time 00:00:00,50 CPU-Identifier: BSP1 Page-in: 0 * * CPU time 00:00:00,32 Virtual Storage used: 2048K Page-out: 0 * * corr. CPU: 00:00:00,32 CPU time has been corrected by 1 / 1,0 multiplier * * * * I/O Operation * * Number of records read via DD * or DD DATA: 4 * * 248.......0 248.......0 149.......8 14A.......7 190.......7 DMY.......0 14B.......3 DMY.......0 * * * * Charge for step (w/o SYSOUT): 0,53 * ************************************************************************************************************************************ IEF236I ALLOC. FOR IEFBR14 LKED IEF237I JES2 ALLOCATED TO SYSPRINT IEF237I 181 ALLOCATED TO SYSLMOD IEF237I 240 ALLOCATED TO SYS00031 IEF237I 149 ALLOCATED TO SYSUT1 IEF237I 14B ALLOCATED TO SYSLIN IEF237I JES2 ALLOCATED TO IEF142I IEFBR14 LKED - STEP WAS EXECUTED - COND CODE 0000 IEF285I JES2.JOB00012.SO0106 SYSOUT IEF285I JMM.S370ASM.LOAD KEPT *--------9 IEF285I VOL SER NOS= MVS809. IEF285I SYS1.UCAT.TSO KEPT *--------0 IEF285I VOL SER NOS= PUB000. IEF285I SYS76117.T051101.RA000.IEFBR14.R0000005 DELETED *--------0 IEF285I VOL SER NOS= SMP001. IEF285I SYS76117.T051101.RA000.IEFBR14.OBJ DELETED *--------4 IEF285I VOL SER NOS= SMP003. IEF285I JES2.JOB00012.SI0103 SYSIN IEF373I STEP /LKED / START 76117.0511 IEF374I STEP /LKED / STOP 76117.0511 CPU 0MIN 00.07SEC SRB 0MIN 00.01SEC VIRT 196K SYS 212K ************************************************************************************************************************************ * 4. Jobstep of job: IEFBR14 Stepname: LKED Program name: IEWL Executed on 26.04.76 from 05.11.01 to 05.11.01 * * elapsed time 00:00:00,18 CPU-Identifier: BSP1 Page-in: 0 * * CPU time 00:00:00,08 Virtual Storage used: 196K Page-out: 0 * * corr. CPU: 00:00:00,08 CPU time has been corrected by 1 / 1,0 multiplier * * * * I/O Operation * * Number of records read via DD * or DD DATA: 1 * * DMY.......0 181.......9 240.......0 149.......0 14B.......4 DMY.......0 * * * * Charge for step (w/o SYSOUT): 0,13 * ************************************************************************************************************************************ IEF236I ALLOC. FOR IEFBR14 IEFBR14 IEF237I 181 ALLOCATED TO STEPLIB IEF237I 240 ALLOCATED TO SYS00033 IEF142I IEFBR14 IEFBR14 - STEP WAS EXECUTED - COND CODE 0000 IEF285I JMM.S370ASM.LOAD KEPT *--------0 IEF285I VOL SER NOS= MVS809. IEF285I SYS1.UCAT.TSO KEPT *--------0 IEF285I VOL SER NOS= PUB000. IEF373I STEP /IEFBR14 / START 76117.0511 IEF374I STEP /IEFBR14 / STOP 76117.0511 CPU 0MIN 00.01SEC SRB 0MIN 00.00SEC VIRT 8K SYS 192K ************************************************************************************************************************************ * 5. Jobstep of job: IEFBR14 Stepname: IEFBR14 Program name: IEFBR14 Executed on 26.04.76 from 05.11.02 to 05.11.02 * * elapsed time 00:00:00,09 CPU-Identifier: BSP1 Page-in: 0 * * CPU time 00:00:00,01 Virtual Storage used: 8K Page-out: 0 * * corr. CPU: 00:00:00,01 CPU time has been corrected by 1 / 1,0 multiplier * * * * I/O Operation * * Number of records read via DD * or DD DATA: 0 * * 181.......0 240.......0 * * * * Charge for step (w/o SYSOUT): 0,01 * ************************************************************************************************************************************ IEF375I JOB /IEFBR14 / START 76117.0511 IEF376I JOB /IEFBR14 / STOP 76117.0511 CPU 0MIN 00.39SEC SRB 0MIN 00.02SEC EXTERNAL SYMBOL DICTIONARY PAGE 1 SYMBOL TYPE ID ADDR LENGTH LDID ASM 0201 05.11 04/26/76 IEFBR14 SD 0001 000000 000004 PAGE 2 LOC OBJECT CODE ADDR1 ADDR2 STMT SOURCE STATEMENT ASM 0201 05.11 04/26/76 000000 1 IEFBR14 CSECT , 000000 1FFF 2 SLR 15,15 000002 07FE 3 BR 14 4 END , ASSEMBLER DIAGNOSTICS AND STATISTICS PAGE 3 ASM 0201 05.11 04/26/76 NO STATEMENTS FLAGGED IN THIS ASSEMBLY HIGHEST SEVERITY WAS 0 OPTIONS FOR THIS ASSEMBLY ALIGN, ALOGIC, BUFSIZE(STD), DECK, ESD, FLAG(0), LINECOUNT(55), LIST, NOMCALL, YFLAG, WORKSIZE(2097152) NOMLOGIC, NONUMBER, NOOBJECT, NORENT, RLD, NOSTMT, NOLIBMAC, NOTERMINAL, NOTEST, XREF(SHORT) SYSPARM() WORK FILE BUFFER SIZE/NUMBER =19066/ 1 TOTAL RECORDS READ FROM SYSTEM INPUT 4 TOTAL RECORDS READ FROM SYSTEM LIBRARY 0 TOTAL RECORDS PUNCHED 3 TOTAL RECORDS PRINTED 22 F64-LEVEL LINKAGE EDITOR OPTIONS SPECIFIED LIST,MAP,XREF,LET,NCAL,RENT DEFAULT OPTION(S) USED - SIZE=(165888,55296) IEW0000 NAME IEFBR14(R) CROSS REFERENCE TABLE CONTROL SECTION ENTRY NAME ORIGIN LENGTH NAME LOCATION NAME LOCATION NAME LOCATION NAME LOCATION IEFBR14 00 4 ENTRY ADDRESS 00 TOTAL LENGTH 8 ****IEFBR14 NOW REPLACED IN DATA SET AUTHORIZATION CODE IS 0. **MODULE HAS BEEN MARKED REENTERABLE, AND REUSABLE.